需求:需要一个 WebView 作为运营活动的 Web 页面的容器,其中需要实现拦截 url 的功能,对符合某些规则的 url 进行替换
方式: 通过拦截器实现对流程的解耦
介绍:什么是拦截器 借鉴okhttp的Interceptors Interceptor 可以获取到一个当前的 request 和 response,实现「监测」;在此基础上,每个 Interceptor 可以修改传给下一个 Interceptor 的 request 和返回给上一个 Interceptor 的 response,实现对数据的「重写」。
这时okhttp的示例图:
多个 Interceptor 构成一个调用栈,每个 Interceptor 可以在执行 chain.proceed 之前修改 request,在 return response 之前修改 response。整体结构有些像递归调用,只是每个Interceptor调用的不是自身的 intercept 方法,而是下一个 Interceptor 的 intercept 方法。
拦截器简单构成:
1.IWebInterceptor
interface IWebInterceptor {
suspend fun intercept(chain: Chain): Response
interface Chain {
fun request(): Request
suspend fun proceed(request: Request): Response
}
}
2.RealInterceptorChain主要作用就是操作拦截器的集合类,通过链式递归调用了,直到最后一个response返回,才会依次返回到第一个interceptor。
class RealInterceptorChain(
interceptor: List<IWebInterceptor>?,
index: Int,
request: Request) : IWebInterceptor.Chain {
private val interceptors: List<IWebInterceptor>? = interceptor

private val index = index
private val request: Request = request
override fun request(): Request {
return request
}
override suspend fun proceed(request: Request): Response {
if (index >= (interceptors?.size ?: 0)) return Response(request.originalData)
//调用下一个在chain中的拦截器
val next = RealInterceptorChain(
interceptors, index + 1, request
)
val interceptor: IWebInterceptor = interceptors!![index]
return interceptor.intercept(next)
}
}
运用:
val interceptors: MutableList<IWebInterceptor> = ArrayList()
//业务逻辑 start
interceptors.add(WillActInterceptor())
interceptors.add(WebSpecificInterceptor())
//业务逻辑 end
interceptors.add(WebNormalInterceptor())
val request = Request(data)
val chain = RealInterceptorChain(
interceptors,
0,
Request(data))
val response = chain.proceed(request)
具体拦截器实现
/**
* 拦截活动链接
*/
class WillActInterceptor : IWebInterceptor {
override suspend fun intercept(chain: IWebInterceptor.Chain): Response {
val request = chain.request()
val data = request.originalData
val url = data.getString("url")
return if (true == url?.contains("activity/cultural")) {
data.putString("url",getH5Url())
Response(data)
} else {
chain.proceed(request)
}
}
class WebSpecificInterceptor : IWebInterceptor {
override suspend fun intercept(chain: IWebInterceptor.Chain): Response {
val request = chain.request()
val data = request.originalData
val url = data.getString("url")
val urlType = data.getString("url_type")
if (true == url?.startsWith("youth_app://")) {
return Response(data, false, url)
}
return when (urlType) {
"agreement" -> {
data.putString("url", HTTP_AGREEMENT)
Response(data)
}
"privacy" -> {
data.putString("url", HTTP_PRIVACY)
Response(data)
}
else -> {
chain.proceed(request)
}
}
}