在正常的App开发中,咱们能够用这样的代码加载App的Assets中打包的Web页面。html
webview.loadUrl("file:///android_asset/index.html");
复制代码
Android系统实现这个功能时,并无像咱们想象的使用webview对象的Context去查找Assets资源。而是经过当前应用的ApplicationId,反查了当前安装的应用的apk路径。因此查到的天然是安装的宿主应用。在宿主的apk中天然是找不到插件的Assets的。关于这个设计的缘由,我猜想大概是由于WebView的渲染是在一个单独的进程中的,因此不方便拿到当前webview对象的context。android
做为插件框架,咱们的目标始终是尽量的让本来正常安装能运行的代码,在插件环境下也能运行。而这个API在业务开发中还比较经常使用,所以这个API的支持就比较重要了。web
虽然我没有作过特别普遍的调研,但我确实没见过其余插件框架支持这个能力。因此我直接讲一下Shadow是怎么在不使用非公开API的前提下支持这个功能的。bash
我受到了“Web离线包”方案的启发。在“Web离线包”方案中,客户端能够在本地拦截http请求,而后以本地资源直接返回。经过将一些Web资源直接打包在客户端中,经过这种技术能够提升Web的加载速度。所以,咱们就能够应用AOP思想,对WebView loadUrl中file:///android_asset/
协议进行修改。框架
因此方案很是简单,先经过Shadow Transform将App中用到的WebView都换成ShadowWebView。再Override ShadowWebView的loadUrl方法。将请求来的file:///android_asset/
协议都修改为http://android.asset/
协议。而后就能够采用“Web离线包”的方法,从插件的Assets中拿出须要的资源返回给这个请求了。之因此要将file
协议换成http
协议,是由于这种拦截本地请求的能力只支持http
协议。ide
关于这部分代码,请查看com.tencent.shadow.core.runtime.ShadowWebView
类的实现。spa
PS:我刚刚Google的时候发现还有一个咱们没用过的file:///android_res
协议,有兴趣的同窗能够帮忙实现一下,参与到Shadow的开源共建中来。插件