开发

宿主自定义浏览内核兼容百度内核特性实现说明

1 简介

小程序框架默认采用”百度T7浏览内核”渲染页面内容,也支持退化到”系统WebView”方案,宿主如有特殊需求,必须使用自定义的浏览内核,可以采用此方案使小程序支持自定义浏览内核渲染。

  • 接口类: IBdWebViewCompat
  • 依赖模块: deps.business.swan.core
  • 默认实现: IBdWebViewCompat.Default.get()
  • 是否必须实现:
  • 可选择性依赖的实现:

注:用于宿主反射替换系统 WebView 浏览内核的 WebViewFactoryProvider 方式接入宿主自有浏览内核时,实现宿主浏览内核兼容百度内核特性。

2 实现步骤

  1. 退化到系统WebView模式,注释掉编译文件中所有T7浏览内核的依赖引用:例如// implementation deps.business.swan.webview.so

  2. 在小程序进程中,将系统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")
    }
    }
  3. 实现内核特性接口

    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
    48
    package 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-小程序宿主能力接口实现指南
    */
    @Service // 必要 pyramid IoC 注解,不加该注解时,依赖注入框架不会识别到该实现类
    @Singleton // 可选 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"
    }
    }