深挖一:移动端混合开发之hybrid

2018-12-28  本文已影响0人  轩辕无枫

一、序言

滚滚长江东逝水,奔流到海不复回。
不要问我为为啥要废这么一句话,其实还是感叹前端发展的迅猛,很多技术和工具都是一闪而逝。如长江之水一样,转瞬即逝。
移动端开发的方式就是如此:
从2010年后的安卓和ios活了之后,移动端app开发的程序员可谓是如过江之鲫,源源不绝。
每年从培训班出来的程序员多达几万。笔者当时还想去参加ios培训呢。
然而过了几年后,考虑到开发成本、维护成本等各方面因素。分端开发已经越来越被当做一个开发效率的瓶颈。
现在让我看看解决这类问题的历程吧。

二、混合框架的两种模式

  1. hybrid :运行时联系沙盒。
  2. native : 编译时原生ui。
    今天主要是讲解hybrid的发展历程。而native会在下期跟大家见面。

三、hybrid

首先大家要明白deepLink的概念,不懂的推荐去看一篇文章链接:
点我去看deepLink
deepLink主要有url schema 和Universal Links 两种。本文准备深层次去讲解下 url schema的工作原理。
给出一个url schema的样例。

  1. dinglei://
  2. dinglei://getUserInfo

是不是看起来很眼熟,对了url schema本身就是一种协议,而且其工作原理和http的ajax还有些类似,上个别人的图。

ajax工作原理。
我们可以看到ajax的url一改变,就会被浏览器所监测到,然后发送给服务器。这一过程会开启一个线程。当服务器完成相应和返回数据后,线程会开始把回调压入到宏任务中,等待执行。

Attention Please!!!

如果说url schema 本身也是一个 同种类型的处理方式,你会不会偷着乐。

原谅我再次盗图:


url shcema 配合沙盒的工作原理图

请读者先记住以下几点:

  1. url schema 是app自身注册到手机系统里面的。其配置方式是工程项目下的info.plist里面配置的。在安装完成后,就已经保存在手机系统的协议列表中了。
  2. 当浏览器挂起这个url schema的请求时,第一接收方式系统本身,不是盒子!!!!
  3. 默认的链接如 weixin:// 盒子的操作都是发送给手机系统,然后手机系统回去列表上查,查到了会去通知对应的盒子做处理,一般是直接打开盒子。如果需要做其他操作,需要传参。
  4. 回调,依然是盒子获取盒子本身webview的全局对象,进行执行。

好吧!让我先上第一部分的干货吧。如何通过url schema去跟native实现一些业务场景吧。

window.testUrlSchemaGlobal = window.testUrlSchemaGlobal || {};


// 建立链接  ios 和安卓不同
function doConnection (url) {
  console.log(url);
    if (window.$plt.isMatch('ios')) {
        window.location = url;
    } else {
      setUrl(url);
    }
};

// 建立 安卓的 链接
function setUrl(url) {
  const iframe = document.createElement('iframe');
  iframe.style.display = 'none';
  iframe.setAttribute('src', url);
  const d = () => {
    setTimeout(() => {
      document.body.removeChild(iframe);
    }, 1000);
  };
  document.body.appendChild(iframe);
}

// 构造url
function getUrlByParams (params) {
  debugger
    var paramStr = '', url = 'scheme://';
    url += params.funcName + '?t=' + new Date().getTime(); //时间戳,防止url不起效
    if (params.callback) {
        url += '&callback=' + params.callback;
        delete params.callback;
    }
    if (params.param) {
        paramStr = typeof params.param == 'object' ? JSON.stringify(params.param) : params.param;
        url += '&param=' + encodeURIComponent(paramStr);
    }
    return url;
};

/**
 * 
 * @param {*} params 
 * funName 
 * callback   传递名称 存放到  全局对象 testUrlSchemaGlobal  共bridge 去调用
 */
function requestHybrid (params) {
    //生成唯一执行函数,执行后销毁
    var tt = (new Date().getTime());
    var t = 'hybrid_' + tt;
    var tmpFn;

    //处理有回调的情况
    if (params.callback) {
        tmpFn = params.callback;
        params.callback = t;
        window.testUrlSchemaGlobal[t] = function (data) {
            tmpFn(data);
            delete window.testUrlSchemaGlobal[t];
        }
    }
    // 直接连接
    doConnection(getUrlByParams(params));
};


//获取版本信息,约定APP的navigator.userAgent版本包含版本信息:scheme/xx.xx.xx
function  getHybridInfo() {
    var platform_version = {};
    var na = navigator.userAgent;
    var info = na.match(/scheme\/\d\.\d\.\d/);

    if (info && info[0]) {
        info = info[0].split('/');
        if (info && info.length == 2) {
            platform_version.platform = info[0];
            platform_version.version = info[1];
        }
    }
    return platform_version;
};
举个例子:
requestHybrid({funcName:"dinglei",param:{isWeb:false},callback(){ console.log('callback') }});

其流程是
1.生成链接 scheme://dinglei?t=1545898661620&param=%7B%22isWeb%22%3Afalse%7D
2.然后注册全局的callback时间撮到去全局对象 testUrlSchemaGlobal中。
3.iframe去建立链接,传递信息。
4.系统处理这个链接,并向盒子发送。
5.盒子去处理相关任务,完成后调用全局的callback。

但是肯定会有同学,疑惑每次都经过手机系统的调度中心,做个中间转换。不是很浪费资源吗。
回答是yes啦。

看到这里是不是有种豁然开朗的感觉,喜欢的同学给个赞,因为作为新人,您的点赞会是我持续写作的动力。
但是你以为已经结束了吗?


chaoxiao

这只是最原始的交互方式,换而言之,在hybrid的方式中,这种事最low的。也是最直接的。

先给大家介绍ios关于交互方式的发展流程。让大家有个直接的印象。

首先我们回忆下我们上面的链接方式,是每次都会建立一次链接,给手机系统的调度中心,手机调度中心传给app盒子,盒子来决定做什么事情。这样是耗性能的。这是上面大致的情况。
让我思考下,什么时候是一定需要传给手机调度中心的?

很简单在盒子外的h5中打开链接的时候,是希望进行跳转到某个页面,这个时候因为不在沙盒内,是必须要传递给手机调度中心的。而页面本身在盒子里面的时候,那直接传递给沙盒不是更好点?

jsbridge就是干这件事情的,它除了第一次建立链接是传递给手机的调度中心,后面都是功过bridge直接监听url schema的。
直接上代码来讲解:

function setupWebViewJavascriptBridge(callback) {
    //  WebViewJavascriptBridge   传递信息
    if (window.WebViewJavascriptBridge) { return callback(WebViewJavascriptBridge); }
     // 建立回调 等同于 全局回调。
    if (window.WVJBCallbacks) { return window.WVJBCallbacks.push(callback); }
    window.WVJBCallbacks = [callback];
  // 建立链接
    var WVJBIframe = document.createElement('iframe');
    WVJBIframe.style.display = 'none';
    WVJBIframe.src = 'scheme://__BRIDGE_LOADED__';
    document.documentElement.appendChild(WVJBIframe);
    setTimeout(function() { document.documentElement.removeChild(WVJBIframe) }, 0)
}
WebViewJavascriptBridge.registerHandler(handlerName,
      function(data, callback) {
                //alert('handlerName callback' + data);
                responseCallback(data),
                callback && callback({
                  errorCode: "0",
                   errorMessage: "成功"
                })
})
WebViewJavascriptBridge.callHandler(path, params);

因为水平有限,暂时如此。后面等研究够了,会继续更新。

参考

上一篇下一篇

猜你喜欢

热点阅读