最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • H5 必知必会之与 App 交互

    正文概述 掘金(为之漫笔)   2020-12-17   585

    本文将深入探讨 H5 与 App 交互的几种常见模式。

    首先声明,本文涉及的 H5 与 App 交互协议和模式没有什么特别独到之处,相反,它们恰恰是在业界既有经验基础上结合项目实际归纳提炼出来的。因此,文中涉及的技术和代码可以看作是行业经验落地的产物,不涉秘,也不是权威做法,仅供业界同仁参考。

    本文内容如下:

    • 概述
    • 基础接口
    • 单向调用
    • 双向调用
    • 实现模式
    • 哪方主导
    1. 概述

    H5,在中国被专门用来指代开发内嵌于手机应用中的网页的技术,外国好像并没有这个说法。从技术上讲,H5 是 HTML5 即 Hyper Text Markup Language(超文本标记语言)第 5 版的简称。而 HTML 只是开发网页要用到的多种技术之一。除了 HTML,还要用 CSS 设计界面,用 JavaScript 实现交互,甚至要用 Node.js 实现服务端逻辑。为什么 H5 会被用来笼统地指代这些技术呢?我猜一是因为它简单,二是移动端网页开发技术又恰好需要这么一个概念。

    移动端网页运行在手机应用内嵌的浏览器引擎中,这个没有 UI 的内核容器统称 WebView,即 iPhone 的 UIWebView(iOS 2.0–12.0)、WKWebView(iOS 8.0+,macOS 10.10+)和 Android 的 WebView。总之,WebView 就是在手机应用中运行和展示网页的界面和接口(神奇的是,英文 Interface,既可以翻译成 “界面” 也可以翻译成“接口”)。

    H5 与原生应用的交互都是通过原生应用中的 WebView 实现的。通过这个环境,H5 可以调用原生应用注入其中的原生对象的方法,原生应用也可以调用 H5 暴露在这个环境中的 JavaScript 对象的方法,从而实现指令与数据的传输。

    比如,在 Android 应用中,WebView类有一个公有方法addJavascriptInterface,签名为:

    public void addJavascriptInterface (Object object, String name)
    

    调用这个方法可以向 WebView 中以指定的名称name注入指定的 Java 对象object。这样,WebView 中的 JavaScript 就可以通过name调用object的方法。比如:

    class JsObject {
        @JavascriptInterface
        public String toString() { return "injectedObject"; }
     }
     webview.getSettings().setJavaScriptEnabled(true);
     webView.addJavascriptInterface(new JsObject(), "injectedObject");
     webView.loadData("", "text/html", null);
     webView.loadUrl("javascript:alert(injectedObject.toString())");
    

    在 iOS 或 macOS 中,需要通过创建WKWebView类的实例在应用中嵌入网页,交互过程类似。

    1. 基础接口

    所谓基础接口,就是首先要规定原生应用和 JS 分别在 WebView 里注入 / 暴露一个什么对象:

    • NativeBridge:原生应用注入到 WebView 中的对象
    • JSBridge:JS 暴露在 WebView 中的对象

    并约定在这两个对象上分别可以调用什么方法:

    • NativeBridge.callNative(action, params, whoCare)
    • JSBridge.callJS(action, params, whoAmI)

    顾名思义,NativeBridge.callNative是由 JS 调用向 Native 传递指令或数据的方法,而JSBridge.callJS则是由 Native 调用向 JS 传递指令或数据的方法。方法签名中的参数含义如下:

    •  action:字符串,希望 Native/JS 执行的操作
    •  params:JSON 对象,要传给 Native/JS 的数据
    •  whoCare:数值,表示 JS 希望哪个端响应
    • whoAmI:数值,表示哪个端调用的 JS

    基础接口只有两个对象和两个方法,JS 与 App 间的互操作则通过actionparams来扩展和定义。

    1. 实现模式

    对于 JS 而言,虽然这里只定义了一个对象一个方法,但实践中,可以把action对应方法的实现附加到JSBridge上,只要把callJS实现为一个分发方法即可,比如:

    window.JSBridge = {}
    window.JSBridge.callJS = function({action, params, whoAmI}) {
      return window.JSBridge[action](params, whoAmI)
    }
    

    这样,所有对callJS的调用,都会转化成对JSBridge上相应action方法的调用,优点是只需一行代码。

    另一种实现方式是通过switch...case语句实现调用分发,比如:

    function callJS (action, params, whoAmI) {
      params = JSON.parse(JSON.stringify(params))
      switch (action) {
        case 'showSkill':
          const category = params.category
          JSBridge.showSkill(category)
          break
        case 'showSkillDetail':
          const id = params.id
          JSBridge.showSkillDetail(id)
          break
        case 'otherAction':
          // some code
          break
        default:
      }
    }
    // JS暴露给应用的通用接口
    const SpkJSBridge = {}
    // 全部接口
    JSBridge.callJS = callJS
    

    这样实现的优点是所有方法一目了然,当然同样也是把所有相关接口都附加到同一个JSBridge对象上。

    以上两种实现模式各有利弊。

    1. 单向调用

    由 JS 发起的单向调用 App 的操作,主要涉及加载 URL 和切换到原生界面,可对应如下action

    • loadUrl:加载另一个 URL
    • loadContent:跳转到原生界面

    loadUrl调用的参考协议如下:

    NativeBridge.callNative({
        action: 'loadUrl',
        params: { url },
        whoCare: 0
    })
    

    这里NativeBridge是 App 的原生对象,其callNative方法被调用时,会收到一个对象(字典 / 映射)参数。根据这个参数的action属性的值,App 可知需要执行的操作是加载 URL。于是再取得params属性中的url,发送请求即可。

    loadContent调用的参考协议如下:

    NativeBridge.callNative({
      action: "loadContent",
      params: {
        type: "album",
        content: {
          album_id: "1"
        }
      },
      whoCare: 0
    })
    

    同上,这里通过params向 App 传递了必要参数,App 负责切换到相应的原生界面。

    由 App 发起的单向调用 JS 的操作,主要涉及用户点击后退按钮(<),可对应如下action

    • can_back:询问 JS 是否返回前是否需要用户确认

    can_back调用的参考协议如下:

    JSBridge.callJS({
      action: "can_back",
      params: {},
      whoAmI: 1/2
    })
    

    此调用返回的值示例如下:

    {
      can: true,
      target: "prev"
    }
    

    顾名思义,can_back用于 App 询问 JS:在返回上一级界面前,是否弹窗提示用户?

    返回值中的can如果是true,则直接返回,不提示;如果是false,则弹出一个确认框,请用户确认。另一个值target是与 App 约定的返回目标,比如prev表示返回上一级,top表示返回顶级,等等。

    1. 双向调用

    双向调用是 JS 先调用 App,然后 App 在完成操作后再调用 JS,双向通常都需要传递数据。双向调用主要涉及 JS 调用 App 原生组件和用户点击右上角按钮,可对应如下action

    • loadComponent:调用原生组件
    • displayNextButton:显示 “下一步”“保存” 或“完成”按钮

    loadComponent的参考协议如下:

    NativeBridge.callNative({
      action: 'loadComponent',
      params: {
        type: 'location',
        value,
        callbackName: 'set_location'
      },
      whoCare: 0
    })
    

    在这个例子中,涉及 JS 调用 App 显示其实现的城市选择组件:type: 'location',用户选择完城市之后,App 再调用set_location,将用户选择的城市名称传给 JS:

    JSBridge.callJS({
      action: 'set_location',
      params: {
        value: '北京市朝阳区',
      },
      whoAmI: 1/2
    })
    

    JS 根据拿到的值更新界面,完成一次双向调用。另一个例子是 JS 调用原生的日期选择组件,与此类似。

    为什么叫displayNextButton?因为根据具体业务场景,可能存在如下三种情况:

    1. 当前 WebView 不需要显示右上角按钮,比如详情页;
    2. 当前 WebView 需要显示 “下一步” 或“保存”按钮,但需要禁用变灰;
    3. 当前 WebView 需要显示 “下一步” 或“保存”按钮,允许用户点击。

    displayNextButton协议的参考实现如下:

    NativeBridge.callNative({
      action: "displayNextButton",
      params: {
        name: "下一步",
        enable: false,
        callbackName: "save_form"
      },
      whoCare: 0
    })
    

    以上代码示例表明,JS 调用 App,告诉 App 显示 “下一步” 按钮,但是要禁用变灰,因为enable: false。如果传递的是enable: true,那么用户就可以点击 “下一步” 按钮了。点击之后,App 再调用 JS 的save_form。最后,如果不想显示按钮,可以传递name: ''

    下面重点说一下用户点击 “下一步” 按钮,App 调用save_form的场景。此时也分两种情况:

    1. JS 直接保存数据
    2. JS 通过 App 保存数据

    如果是 JS 通过 App 保存数据——可能因为 App 端实现了数据写入必需的加密机制——那么,JS 可以在 App 调用save_form时将约定好的数据返回给 App,由 App 去保存数据。

    如果是 JS 直接保存数据,比如通过 Ajax,那么在保存完数据之后,则还需要调用前面所说的 App 暴露的loadUrlloadComponent方法,以告知 App 切换界面。当然这种情况下会出现第三次调用,但仍然属于双向调用。

    1. 哪方主导

    本文介绍了 JS 与 App 交互的几种模式,而且只讨论了 JS 端的实现。在开发实践中,团队各端总会面临哪一端主导的问题。本文展示的参考实现就是 H5 端主导的一种实现形式。H5 主导的特点是把主要业务逻辑都封装到 WebView 中,App 主要协同配合,而优点是业务逻辑的变更不会蔓延到 App。毕竟相对于 H5,App 的安装部署模式会造成多版本共存问题,需要尽可能控制新版本。假如由 App 端主导,将逻辑封装在 App 端,势必造成版本不受控,给整个项目或产品埋下隐患。

    当然,事无绝对。具体情况还要具体分析。而且,哪方主导有时候也取决多方面因素。实践中还是要因人、因时、因势制宜。


    起源地下载网 » H5 必知必会之与 App 交互

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元