关于重构Android端webView模块的一些实践及总结

勿忘初心2018-10-24 10:27

此文已由作者徐铭阳授权网易云社区发布。

欢迎访问网易云社区,了解更多网易技术产品运营经验。


前言

做业务过程中接到js插件的需求,原有代码中webView比较分散,各个页面可能是不同同学开发,很多页面都是单独自己实现webView,没有统一收口,导致代码中webView的实现非常多,如果有新的需求可能就需要check所有的webView,而这种方式不小心就会忽略某些页面的处理,正好有js插件的需求,所以就借此机会准备重构下浏览器模块,将浏览器单独独立一个模块,接入中M管理模块的方式,剥离jsbridge、插件机制,模块内部维护页面通用插件,个性化插件如支付、分享等插件交个业务去实现插件。


需求

  • 剥离jsbridge和插件机制,业务无关,完全解耦
  • 支持js-native-js,native-js-native
  • 优化jsbridge注入时机
  • 业务组件懒加载,不需要在app启动时初始化
  • lib-ucmooc-browser模块注册


解决方案

  • 新增中M浏览器模块管理使用中M模块管理方式,通过组件懒加载机制

  • 重构后调用关键类的调用方式如下:                                               

    • 实现功能如下:                                                                              

      • 优化注入时机:增加onReceiveTitle时注入时机,jsbridge自身机制保证不会重复注入


      JSAPI

      lib-ucmooc-browser模块声明H5Plugin接口,外部可通过实现该接口的方式注入jsapi,通用型插件会在第一次打开webView时注入,其他非通用型接口业务控制,可在打开H5页面之前注入js插件

      关于调用方式如下

      • H5页面监听jsbridge事件注入成功,只有在jsbridge注入成功之后js插件才会生效

        document.addEventListener('YixinJSBridgeReady', function (event) {
              alert(event.detail);
        
          }, false);
        
      • 打开全新的页面
        window.YixinJSBridge.call("open_page_plugin", {
                              "mReturnUrl": "http://www.baidu.com"
                          })
        
      • 嵌入native页面内部的webView

        LinearLayout layout = (LinearLayout) findViewById(R.id.h5_page_test);
              H5ServiceImpl h5Service = ModuleContext.getInstance().getServiceByInterface(IH5Service.class.getName());
              Bundle bundle = new Bundle();
              if(h5Service != null) {
                  H5Page page = h5Service.createPage(bundle);
                  if (page != null) {
                      layout.removeAllViews();
                      layout.addView(page.getContentView());
                  }
              }
        
      • 普通js插件调用

        window.YixinJSBridge.call("closeWebView")
        
      • 插件Demo

        public class H5ExitPagePlugin implements H5Plugin{
          private static final String JS_API_EXIT_PAGE = "exit_page_plugin";
          @Override
          public void filterJsApi(List<String> plugins) {
              plugins.add(JS_API_EXIT_PAGE);
          }
        
          @Override
          public boolean handlerJsApi(JsApiReq req, JsApiRep rep, H5Bridge bridge) {
              if(req == null || req.getJsMessage() == null) {
                  return false;
              }
              if(TextUtils.equals(req.getJsMessage().methodName, JS_API_EXIT_PAGE)) {
                  JSONObject jsonObject = new JSONObject();
                  try {
                      jsonObject.put("data", "你好 web");
                  } catch (JSONException e) {
                      e.printStackTrace();
                  }
                  if(bridge != null) {
                      bridge.sendToWeb(JS_API_EXIT_PAGE, jsonObject);
                  }
                  return true;
              }
              return false;
          }
        
          @Override
          public void onDestroy() {
        
          }
        }
        
      • native主动发消息给H5 和前端约定好对应字段,插件中会获取H5bridge对象,通过该对象传递给H5
      bridge.sendToWeb(JS_API_EXIT_PAGE, jsonObject);
      


      其他

      通用型JSAPI还有很多,这里就不一一列举了,后面JSAPI会慢慢完善

      如有问题欢迎指正交流


      网易云免费体验馆,0成本体验20+款云产品! 

      更多网易技术、产品、运营经验分享请点击