美文网首页Android技术知识Android开发经验谈Android开发
[Android]你不知道的Android进程化(7)--Web

[Android]你不知道的Android进程化(7)--Web

作者: CangWang | 来源:发表于2019-02-01 16:53 被阅读171次

    大家好,我系苍王。
    以下是我这个系列的相关文章,有兴趣可以参考一下,可以给个喜欢或者关注我的文章。

    [Android]如何做一个崩溃率少于千分之三噶应用app--章节列表

    Android组件化架构热卖中

    更多深入的开发技巧可以关注我的小专栏《Android进程化开发》,专栏里会提供本篇加强的版本

    大家应该都有或多或少都会接触到Webview的封装和开发,一般都是在默认进程中开启一个Web的Activity来做操作。但是近来越来越多人会偏向于将Webview单独一个进程来做处理。

    WebView进程的好处:

    1.不占用主进程内存,减少主进程内存压力,减少系统强制回收的可能性。
    2.Webview如果存在内存泄露,内存会更加宽裕,只要关闭就了事了,不会对主进程有过多影响。
    3.进程隔离,如果出现崩溃不会相互影响,并且可以做一些拉活操作。

    Android开启单独进程的方式,在以前的进程化已经介绍过了,WebView通过依赖于Activity来做单独进程,开启Activity单独进程,只要在AndroidMainfest中声明Activity的时候添加android:process=":xxx"属性

    哈哈,这些简单的介绍,估计大家都懂,接下来就是展示真正技术的时候了。

    JSBridge原理

    JsBridge,如果大家有做过Webview和客户端的js调用,相信大家都会接触这个框架,这个框架兼容android和ios端,提供了js对android和ios端的互相调用方案。
    因为WebView是单独进程的,其实大家都不喜欢WebView和其他业务过分耦合,那么就需要让WebView和jsbridge做一些封装。
    下面是jsbridge原理,jsbridge通过注入js调用代码到html里面,html中通过调用相应函数,然后jsbridge通过shouldOverrideUrlloading来拦截对应拼接的字符串,然后回调到注册触发的webview注册的registerHandler函数完成方法实现。

    jsbridge调用原理.png

    说一下两点jsbridge使用需要注意的地方。
    1.Webview必须注册BridgeWebViewClient。
    2.onPageFinished和shouldOverrideUrlLoading覆写时,一定要调用supper的方法,不然注入和回调将无法触发。

    JsBridge基本回调框架建立

    我们现在要做的controller到webview的封装,这里只是共同进程里面的封装。

    1. 先建立一个业务类注册的jsbridge管理类
    data class JsBean(val functionName: String, val url: String?, val result: (context: Context?, data: String, data2: String, callBack: IJavaScriptCallBack?) -> String?)
    object JavaScriptInterface {
        val set: MutableSet<JsBean> = HashSet()
        //jsbridge接收的scheme名
        val SCHEME_NAME = "eating"
        var context: Context? = null
    
        fun register(bean: JsBean) {
            set.add(bean)
        }
    
        fun unregister(bean: JsBean) {
            set.remove(bean)
        }
    }
    

    2.业务初始化时调用JsBridge的注册

     JavaScriptInterface.register(JavaScriptInterface.JsBean(
                    "groupgame",
                    ""
            ) { context, data, data2, callback ->
                ……自身逻辑……
                data     //返回值
            })
    

    3.编写jsbridge注册回调

        //非跨进程使用,fragment或webview使用
        fun inject(context: Context, url: String, webView: NestedScrollWebView) {
            //html调用得方法名为sendAction
            webView.registerHandler("sendAction") { data, function ->
                //解析为uri
                val uri = Uri.parse(data)
                //比对scheme名
                if (uri.scheme == SCHEME_NAME) {
                    //比对想要触发的方法名
                    set.filter { uri.authority == it.functionName }
                            //调用jsbean触发的方法
                            .mapNotNull { it.result(context, uri.pathSegments[0], "", null) }
                            //回调给html 
                            .forEach { function.onCallBack(it) }
                }
            }
        }
    

    4.在webViewActivity初始化的时候注册

    JavaScriptInterface.inject(context, url, web)
    

    Jsbridge独立进程封装

    这里当然是要调用aidl的,之后优化的话封装Binder。


    跨进程jsbridge.png

    jsbridge到web的部分是共通的,流程图中就不展示了。
    1.编写aidl接口

    //关闭web页的接口,回调给webActivity的实现
    interface IJavaScriptCallBack {
        void callbackFinish();
    }
    
    //javaScript的分发到业务controller的实现
    interface IJavaScriptlInterface {
    //    void handler(String data);
        void handler(String data,IJavaScriptCallBack callback);
    }
    

    2.创建一个JavaScriptService

    class JavaScriptService : Service() {
        companion object {
            val TAG = JavaScriptService::class.java.simpleName
        }
    
        val mBinder = object : IJavaScriptlInterface.Stub() {
            override fun handler(data: String?, callBack: IJavaScriptCallBack?) {
                if (data != null)
                    //jsbridge分发给不同业务
                    JavaScriptInterface.filterData(data, callBack)
            }
        }
    
        override fun onBind(intent: Intent?): IBinder {
            return mBinder
        }
    
    }
    

    3.WebActivity绑定启动

        private val serviceConn = object : ServiceConnection {
            override fun onServiceDisconnected(name: ComponentName?) {
                isServiceConnect = false
            }
    
            override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
                //获取aidl
                jsbController = IJavaScriptlInterface.Stub.asInterface(service)
                val url = intent.getStringExtra(ARouterConstants.PARAM.WEB_URL) ?: return
                //添加js框架
                JavaScriptInterface.inject(this@WebActivity, url, web, jsbController, callback) 
                isServiceConnect = true
            }
        }
    
        private fun bindService() {
            val intent = Intent(this, JavaScriptService::class.java)
            bindService(intent, serviceConn, Context.BIND_AUTO_CREATE)
        }
    

    4.Jsbridge绑定函数

        //WebActivity跨进程专用回调
        fun inject(activity: AppCompatActivity, url: String, webView: NestedScrollWebView, jsbController: IJavaScriptlInterface?, callBack: IJavaScriptCallBack?) {
            //web进程内调用
            webView.registerHandler("sendAction") { data, function ->
                val uri = Uri.parse(data)
                if (uri.scheme == SCHEME_NAME && set.size > 0) {
                    set.filter { uri.authority == it.functionName }
                            .mapNotNull { it.result(activity, uri.pathSegments[0], "", callBack) }
                            .forEach { function.onCallBack(it) }
                }
                //aidl分发到不同业务
                jsbController?.handler(data, callBack)
            }
        }
    

    5.分发的调用触发

        //WebActivity跨进程回调触发
        fun filterData(data: String, callBack: IJavaScriptCallBack?) {
            val uri = Uri.parse(data)
            if (uri.scheme == SCHEME_NAME && set.size > 0) {
                set.filter { uri.authority == it.functionName }
                        //这里获取到最顶层的activity,因为aidl无法传递context对象
                        .mapNotNull { it.result(AmeTopActivity.current(), uri.pathSegments[0], "", callBack) }
            }
        }
    

    基本的进程回调就到这里了。

    Android组件化群1 Android组件化群2

    相关文章

      网友评论

        本文标题:[Android]你不知道的Android进程化(7)--Web

        本文链接:https://www.haomeiwen.com/subject/qohdsqtx.html