宿主自定义浏览内核兼容百度内核特性实现说明
1 简介
小程序框架默认采用”百度T7浏览内核”渲染页面内容,也支持退化到”系统WebView”方案,宿主如有特殊需求,必须使用自定义的浏览内核,可以采用此方案使小程序支持自定义浏览内核渲染。
- 接口类:
IBdWebViewCompat
- 依赖模块:
deps.business.swan.core
- 默认实现:
IBdWebViewCompat.Default.get()
- 是否必须实现: 否
- 可选择性依赖的实现: 无
注:用于宿主反射替换系统 WebView 浏览内核的 WebViewFactoryProvider 方式接入宿主自有浏览内核时,实现宿主浏览内核兼容百度内核特性。
2 实现步骤
退化到系统WebView模式,注释掉编译文件中所有T7浏览内核的依赖引用:例如
// implementation deps.business.swan.webview.so
在小程序进程中,将系统
WebViewFactory
类中的静态对象sProviderInstance
反射替换为宿主自定义浏览内核的自定义实现1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21/** 标记自定义内核安装状态 */
var hasInstalled = false
/** 反射替换系统 WebView 实现,安装宿主自定义内核 */
fun installCustomWebView() {
try {
takeIf { !hasInstalled }?.let {
Class.forName("android.webkit.WebViewFactory")?.getDeclaredField("sProviderInstance")
}?.takeIf { field ->
field.isAccessible = true
!CustomWebViewFactorProvider::class.isInstance(field.get(null))
}?.set("sProviderInstance", CustomWebViewFactoryProvider()).apply {
hasInstalled = true
Log.d(TAG, "Hook done!")
}
} catch (e: Exception) {
Log.w(TAG, "catch: ${e.message}")
} finally {
Log.d(TAG, "hasInstalled: $hasInstalled")
}
}实现内核特性接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48package com.host.baidu.swan.webview.compat.impl
import android.util.Log
import com.baidu.pyramid.annotation.Service
import com.baidu.pyramid.annotation.Singleton
import com.baidu.swan.apps.ioc.interfaces.IBdWebViewCompat
import com.baidu.webkit.sdk.WebView
import com.baidu.webkit.sdk.system.WebViewImpl
import java.lang.Exception
/**
* 宿主浏览内核兼容百度内核的示例实现
*
* 参考文档:02-小程序宿主能力接口实现指南
*/
// 必要 pyramid IoC 注解,不加该注解时,依赖注入框架不会识别到该实现类
// 可选 pyramid IoC 注解,加该注解表示要求依赖注入框架单例维护该实现类的对象,不加该注解则表示每次调用该接口时都会构造新的实现类对象
class BdWebViewCompatByHost : IBdWebViewCompat {
/**
* WebView 实现是否已消费了当前触摸事件
*
* @param bdWebView
* @return 如果当前触摸事件被 WebView 实例优先消费,则返回 true,认为 webview 的外层容器不应处理触摸事件,否则返回 false
*/
override fun hasTouchEventConsumedByWebView(bdWebView: WebView?): Boolean {
bdWebView?.webView?.takeIf { it is WebViewImpl }?.let { sysWebViewImpl ->
try {
android.webkit.WebView::class.java.getDeclaredMethod("getWebViewProvider")
.invoke(sysWebViewImpl).let { webViewProviderObj ->
Log.i(TAG, "GetWebViewProvider invoke ret = $webViewProviderObj")
if (webViewProviderObj is HostWebViewProvider) {
return webViewProviderObj.hasTouchEventConsumedByWebView()
}
}
} catch (e: Exception) {
Log.w(TAG, "couldHandleTouchEventByContainer: bdWebView = $bdWebView", e)
}
}
return false
}
companion object {
const val TAG = "BdWebViewCompatByHost"
}
}