zoukankan      html  css  js  c++  java
  • hybrid

    hybrid是什么,为何用hybrid?
    hybrid即‘混合’,即前端和客户端的混合开发。
    比如大部分app打开详情页,上面返回和三个点,底部的评论等是客户端做的。中间的页面就可以用hybrid。
    为何使用hybrid,第一个可以快速迭代更新,无需app审核。如果要审核,一天一上线那是不可能的事情。为什么他不需要审核呢?之所以app需要审核,是因为app,比如开发安卓的java代码,这些代码都有权利访问到手机安全,比较隐私的一些东西,比如深层次的api,可以地理位置,比如开启相机这些。用这些功能开发出来的app肯定需要审核。hybrid就是js,html5,css,调用不到深层次的api,没有那么高的权限,所以不需要审核。
    第二个体验更流畅。不需要重新加载页面。跟native的体验是基本一致的。第三个减少开发和沟通成本,双端公用一套代码。


    webview是什么?
    是app中的一个组件(app可以有webbiew,也可以咩有)
    用于加载h5页面,即一个小型的浏览器内核


    file协议
    其实在一开始接触html开发,就已经使用了file协议。比如写一个html页面,双击打开的时候,就是file:///Users/xxx/xxx/index.html。请求本地的资源用的就是file协议。线上的用http(s)协议。只不过当时没有‘协议’,‘标准’等这些概念。所以file协议,本地文件,快。http协议,网络加载,慢。


    hybrid具体怎么实现
    1、前端做好静态页面(html,js,css),将文件交给客户端
    2、客户端拿到前端静态页面,以文件形式存储在app中
    3、客户端在一个webview中
    4、使用file协议加载静态页面



    介绍一下hybrid更新和上线的流程?
    打包上传,对应一个版本号,客户端去拉到代码,拉的时候先去对比版本,版本一致说明没更新,客户端没必要重新下载。不一样就重新下载。然后app里面自己解压zip包。



    hybrid和h5的区别
    hybrid的优点:体验更好,跟na体验基本一致。可快速迭代,无需app审核(关键)
    hybrid的缺点:开发成本高,联调、测试、查bug都比较麻烦。运维成本高,上线麻烦。
    适用的场景:hybrid适合产品的稳定功能,体验要求高,迭代频繁。h5适合单次的运营活动或不常用功能,对体验要求不高,但对速度有要求,单次没必要话费很高的成本。

    前端js和客户端如何通讯?
    https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115
    比如微信端这些js-sdk的一些客户端能力,这些是已经封装好的。这个就是前端js如何和客户端进行通讯。通过一个js方法直接就实现了,不需要具体是怎么实现的。

    新闻详情页适合用hybrid,前端如何获取新闻内容?
    不能用ajax获取。第一跨域,第二速度慢。而且一般ajax是用http协议获取线上的,而hybrid一般是用file协议,本地的。客户端获取新闻内容,然后js通讯拿到内容,再渲染。


    js和客户端通讯的基本形式
    wx.checkJsApi({
      jsApiList: ['chooseImage'], // 需要检测的JS接口列表,所有JS接口列表见附录2,
      success: function(res) {
        // 以键值对的形式返回,可用的api值true,不可用为false
        // 如:{"checkResult":{"chooseImage":true},"errMsg":"checkJsApi:ok"}
      }
    });

    比如微信的这种。之前也用过其他的,也是封装好这样。js通过触发某个东西,然后传递参数+callback。客户端通过回调函数返回内容。

    schema协议简介和使用
    schema协议和我们之前了解的http协议,还有file协议。或者socket协议类似的格式
    schema协议 —— 是前端和客户端通讯的约定。

    比如微信的部分schema协议
    weixin://dl/scan
    weixin://dl/feedback
    weixin://dl/moments
    weixin://dl/chat
    weixin://dl/help
    weixin://dl/features
    weixin://dl/games
    weixin://dl/profile
    ...

    前面这个名字是可以自己定的,取完后就是协议的一部分了。微信有严格的权限验证,外部页面不能随意使用 schema。如果是我们自己与客户端交互,代码如何实现
    <body>
      <button id="btn">扫一扫</button>
      <script type="text/javascript">
        function invokeScan(){
          window['_invoke_scan_callback_'] = function(result){
          alert(result);
        }
    
        var iframe = document.createElement('iframe');
        iframe.style.display = 'none';
        // iframe.src = 'weixin://dl/scan'; // 重要!
        iframe.src = 'weixin://dl/scan?k1=v1&k2=v2&k3=v3&callback=_invoke_scan_callback_';
        var body = document.body;
        body.appendChild(iframe);
        setTimeout(() => {
          body.removeChild(iframe);
          iframe = null;
        }, 1000);
      }
    
      document.getElementById('btn').addEventListener('click'),function(){
      invokeScan()
    }
    </script>
    </body>

    主要建立个空的iframe,然后发起协议,然后客户端拿到协议并得到参数,然后通过回调返回结果。




    schema使用的封装
    封装,就是让调用者可以傻瓜式调用,而且不用再定义全局函数

    调用者
    window.invoke.share({title:'xxx',content:'xxx'}, function(result){
      if (result.errno = 0) {
        alert('分享成功')
      } else {
        alert(result.message)
      }
    })


    封装者
    // 分享者
    function invokeShoare(data, callback){
      _invoke('share', data, callback)
    }
    // 登录
    function invokeLogin(data, callback){
      _invoke('login', data, callback)
    }
    // 扫一扫
    function invokeScan(data, callback){
      _invoke('scan', data, callback)
    }
    // 暴露给全局
    window.invoke = {
      share: invokeShare,
      login: invokeLogin,
      scan: invokeScan
    }

    再往深一层次看
    function invoke(action, data, callback) {
      // 拼接 schema协议
      var schema = 'myapp: //utils';
      schema += '/' + action;
      schema += '?a=a';
    
      var key;
      for (key in data) {
        if(data.hasOwnProperty(key)){
          schema += '&' + key + '=' + data[key]
        }
      }
    
      // 处理callback
      var callbackName = '';
      if (typeof callback === 'string') {
        callbackName = callback;
      } else {
        callbackName = cation + Date.now();
        window[callbackName] = callback;
      }
      schema = '&callback' + callbackName;
    
      // ifarme中掉用scheme —— 省略n行(上方已经有写)
    }

    我们综合一下,就可以整理为下面的流程
    schema.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <meta http-equiv="X-UA-Compatible" content="ie=edge">
      <title>Document</title>
    </head>
    <body>
      <button id="btn1">扫一扫</button>
      <button id="btn2">分享</button>
    
      <script src="invoke.js"></script>
      <script type="text/javascript">
        document.getElementById('btn1').addEventListener('click'),function(){
          window.invoke.scan({}, function(){
            console.log('扫码成功')
          })
        }
        document.getElementById('btn2').addEventListener('click'),function(){
          window.invoke.share({title:'xxx',content:'yyy'}, function(){
            if(result.errno === 0){
              console.log('分享成功')
            }else {
              console.log(result.message);
            }
          })
        }
      </script>
    </body>
    </html>
    invoke.js
    (function(){
      // 调用 schema 的封装
      function _invoke(action, data, callback){
        // 拼接 schema协议
        var schema = 'myapp: //utils/' + action;
        schema += '?a=a';
      
        var key;
        for (key in data) {
          if(data.hasOwnProperty(key)){
            schema += '&' + key + '=' + data[key]
          }
        }
    
        // 处理callback
        var callbackName = '';
        if (typeof callback === 'string') {
          callbackName = callback;
        } else {
          callbackName = action + Date.now();
          window[callbackName] = callback;
        }
        schema = '&callback' + callbackName;
    
        // 触发
        var iframe = document.createElement('iframe');
        iframe.style.display = 'none';
        iframe.src = schema;
        var body = document.body;
        body.appendChild(iframe);
        setTimeout(() => {
          body.removeChild(iframe);
          iframe = null;
        });
      }
     
      // 暴露到全局变量
      window.invoke = {
        share: function(data, callback){
          _invoke('share', data, callback);
        },
        scan: function(data, callback){
          _invoke('scan', data, callback)
        },
        login: function(data, callback) {
          _invoke('login', data, callback);
        }
      }
    })(window);

    将以上封装的代码打包,叫做invoke.js,内置到客户端。客户端每次启动webview,都默认执行invoke.js。本地加载,免去网络加载的时间,更快。本地加载,没有网络请求,黑客看不到schema协议,更安全。

  • 相关阅读:
    ArcEngine 里面的日期
    ArcEngine连接Oracle数据库
    ArcGIS连接Oracle数据库
    ms sql 带自增列 带外键约束 数据导入导出
    获取指定 MethodInfo 的 MSIL 或者 C# 源码
    架构知识集锦
    ClickOnce手动更新
    委托简单例子
    C# 多线程编程之锁的使用【互斥锁(lock)和读写锁(ReadWriteLock)】
    可扩展类库强制取消异步调用
  • 原文地址:https://www.cnblogs.com/wzndkj/p/11115937.html
Copyright © 2011-2022 走看看