h5逻辑_H5+app 混合开发

app分类

app主要指的是在手机上运行的第三方应用程序~主要分为一下三类

  • Native App (原生应用):指的是基于手机操作系统开发出来的第三方应用程序
    • 需要下载(每次更新都需下载)
    • ios/android 操作系统不同,代码不兼容(需要开发两套不同的代码) -> 开发慢,开发成本高
    • 用户体验度好
  • Web App(网页应用):指的是使用web技术来开发的app
    • 不需要下载
    • 跨平台的,一套代码可以在多个浏览器使用->开发快、快发成本低
    • 用户体验不太好,不同的浏览器展示效果可能存在差异,部分功能无法实现
  • HyBird App(混合应用)
    • 将原生应用与网页应用相结合,集原生应用 与 网页应用的优点于一身
    • 本质就是将网页内嵌在原生app中,然后产生一系列的交互~

h5与原生进行交互

[1] 判断h5页面打开的环境是ios/android

通过navigator.userAgent判断当前页面的运行环境

[2] JS调用ios/android的方法
js调用ios的方法
  • 在ios中:在ios中定义的方法若是想被嵌入的h5页面调用

    • [1] 声明一个方法 如getAppInfo
    • [2] 注册对这个方法的监听
        wkWebView.configuration.userContentController.add(self, name: getAppInfo)
      
  • 在js中

    在js中的调用使用固定语法window.webkit.messageHandlers.方法名.postMessage(数据)

    window.webkit.messageHandlers.getAppInfo.postMessage()
    
js调用android的方法
  • 在android中

    在android中,需要暴露出一个全局变量JSBridge,类似浏览器环境中的Window

      // 获取webview的设置对象
      WebSettings webSettings = mWebView.getSettings()
      //  设置Android允许js脚本
      webSettings.setJavaScriptEnabled(true)
      // 暴露出JSBridge的对象到webView的全局环境
      mWebView.addJavascriptInterface(getJSBridge(), 'JSBridge')
    

    通过以上代码,只要是此webView运行的h5页面中就可以访问到这个对象了!

    tips:全局环境的变量名并不是固定为JSBridge的
    mWebView.addJavascriptInterface(getJSBridge(), ‘WBridge’)
    通过上述代码配置的全局环境变量名为WBridge

    若是后续需要h5页面访问的属性或方法都可以添加在全局变量中。

  • 在js中

    在js中的调用是非常简单的,比如说在android中暴露全局变量为JSBridge,该变量上存在getAppInfo方法, 通过如下代码即可调用

      Window.JSBridge.getAppInfo()
    
区别

调用ios的方法时是异步的;而调用android的方法时是同步的!

总结-示例代码
function info() {
    
    
  if (navigator.userAgent.search(/(iphone|ipad|ipod)/i) >= 0) {
    
    
     return 'iOS' // 手机iOs
  } else if (navigator.userAgent.search(/android/i) >= 0) {
    
    
    return 'Android' // 手机安卓
  } else if (navigator.userAgent.search(/windows phone/i) >= 0) {
    
    
    return 'WinPhone'
  } else {
    
    
    return 'PC'
  }
}

const platform = info()
const params = {
    
    ...}
if (platform === 'iOS' && window.webkit) {
    
    
// showShareIcon 为ios抛出的方法
 window.webkit.messageHandlers.showShareIcon.postMessage(params)
} else if (platform === 'Android' && window.JSBridge) {
    
      
  // JSBridge为Android抛出的全局对象
   window.JSBridge.showShareIcon(JSON.stringify(params))
}else {
    
    
  return false
}
客户端调用js方法

若是客户端想调用web页面中的方法,需要我们先将方法暴露出去

tips: 有时客户端拿不到window, 因此需要做下兼容~

const pluginFun = (function(){
    
    
  // 兼容全局对象
  const _global = (function () {
    
    
    return window || this
  }())
  const plugin = {
    
    
    方法1(){
    
    },
    方法2(){
    
    },
    ...
  }
  // 将和客户端约定的方法暴露给全局对象
  for (const i in plugin) {
    
    
    !('jsFunc' in _global) && (_global[i] = plugin[i])
  }
}())
示例: 客户端与web交互之回调

需求场景:web页面上有提现功能,此功能的逻辑是

  • [1] 在客户端调用支付宝支付通道判断是否可以提现,判断结果返回到web页面
  • [2] web页面获取到是否可以提现之后:若是可以提现调取提现接口,若是不可以提现则提示不可提现原因;

在vue中可以使用$on进行事件监听,具体做法如下

  • [1]调用客户端方法->判断是否可以提现,监听客户端返回结果
    isDrawal(){
          
          
      if(isAndroid){
          
          
        if (window.xxxJSBridge) {
          
          
          window.xxxJSBridge.isDrawal(url) // url是支付宝url
        }
      }
    }
    vm.$on('drawal', data=>{
          
          
      // 获取到客户端返回的信息data, 若是可以提现则调取提现接口,若是不可以提现则提示不可提现原因;
    })
    
  • [2] 封装一个方法供客户端调用触发drawal事件
    const pluginFun = (function(){
          
          
      // 兼容全局对象
      const _global = (function () {
          
          
        return window || this
      }())
      function callbackme(data){
          
          
        vm.$emit('drawal', data)
      }
      _global.drawal = callbackme
    }())
    
[3]双方约定协议(schema)

当将web页面嵌入客户端时

若是我们使用$router.push等方法去进行页面跳转时,该页面会在当前webView(相当于是一个浏览器页面)中打开。

若是我们想要在新的webView中打开页面,则要使用h5与客户端预先约定协议

h5页面进行页面跳转时,客户端通过指定的方法拦截并解析url,如果检测到是预先约定好的协议,就调用相应方法~

以下面例子进行说明

  • h5与客户端约定的协议为 bd-pst

  • 若是url为web则在app内打开指定h5页面(该链接的url参数)

  • 若是url为非web则打来app内指定页面

  • 示例1

    jumpPage(url){
          
          
      location.href = 'bd-pst://web?url='+encodeURIComponent(url) // 通过一个新的浏览器打开页面
    }
    
    jumpPage(url){
          
          
     this.$router.push(url)  // 在当前浏览器打开
    }
    

    打开页面为h5页面 路径为 url

  • 示例2

      location.href='bd-pst://login'
    

    打开app内的login页面

  • 需要值得注意的是 若是使用新的webView去开开页面则tabBar中左侧返回按钮不能使用$router.back(相当于一个新的浏览器页面history中的历史记录是空的)。但是在客户端是存在跳转记录的,我们可以通过客户端的方法进行页面返回。

[4] 在web页面下载app

下载地址是客户端给我们的(android与ios下载地址不同),因此在下载之前需要先判断浏览器的所属环境

if(navigator.userAgent.search(/(iphone|ipad|ipod)/i) >= 0){
    
    
  // ios
  location.href = 'xxx'
}else if(navigator.userAgent.search(/android/i) >= 0){
    
    
  // Android
   location.href='xxx.apk'
}else{
    
    
  // 跳转到应用宝下载
}
[5] 是否全屏打开页面

在h5页面中经常需要设置navbar,那将h5页面嵌入到客户端时就涉及一个问题: nabBar是客户端配置的还是需要h5页面代码写上的呢?
如上页面是h5页面需要嵌入到客户端,此页面存在navBar,那这个navBar什么时候需要h5开发人员以代码添加什么时候不需要呢?

这就涉及到配置问题了。此时需要给客户端传递参数need_full_screen是否需要完整屏幕,若是值为false, 则h5页面不占据整个页面,如下图
在这里插入图片描述
h5页面的大小 = 整个屏幕 - 状态栏高度 - navbar高度

若是为true,则表示该页面占据全部屏幕,如下图
在这里插入图片描述
整个屏幕都是h5页面的位置,但是此时就出现了一个新的问题就是在h5页面需要设置一个padding-top,padding-top的值为 状态栏的高度

那么如何获取状态栏的高度?自然是在客户端获取~

举例说明:

  • [1] 通过bd协议打开页面---- ‘bd-xxx://web?url=xxx?need_full_screen=1’
  • [2] 客户端通过指定的方法拦截并解析url,发现url携带参数need_full_screen,则在打开该页面时在路径上拼接状态栏高度参数如xxx?need_full_screen=1&height=40
  • [3] h5页面通过url参数获取高度并添加样式

需要值得注意的是在客户端的tab页面中默认need_full_screen的值为true(即默认该页面没有navBar)

[6] 将h5页面作为客户端的tab页面

[1] tab页面膜人need_full_screen为true(具体可见**[5]是否全屏打开页面**)

[2] web页面作为客户端的tab页,切换tab的时候并不会销毁页面,也就是说再次打开页面的时候并不会走created生命周期函数,导致数据不刷新(不是最新状态)。此时可以走回调函数解决问题

  • [1] 封装一个监听函数供客户端调用
    const vm = new Vue()
    
    function(){
          
          
      const _global = (function () {
          
          
        return  window || this
      }())
      function callback(data){
          
          
        vm.$emit('refresh', data)
      }
    }()
    
  • [2] 在需要刷新的tab页面监听refresh方法
    vm.$on('refresh', (data)=>{
          
          
      if(data === 'refresh'){
          
          
        //  重新调去接口
      }
    })
    

猜你喜欢

转载自blog.csdn.net/qq_43260366/article/details/130199516