h5怎么调原生app提供的方法?

802 阅读6分钟

对于一些没有参与过混合开发的初级前端同学在刚接触时或者面试的时候被问到怎么支付?怎么扫一扫?登录态怎么获取?等等一些问题的时候可能是个懵逼的!所以我就来稍微普及一下这个看似麻烦,其实贼拉简单的方法! 首页工作中的移动端项目

1.常见的比如 微信!支付宝!这些是原生app,也就是开发需要最少一个安卓开发,一个ios开发,并没有前端啥事,说实话,原生app的体验要比h5(前端的移动端页面)强太多了,最直观的就是流畅!但是原生开发效率没有h5的高,而且一个项目得请2个开发老师,但是请一个前端就可以搞定,所以h5要便宜,开发速度快!体验差点就差点嘛!

2.混合开发app,字面意思,混合开发,大家都在一起玩,比如,原生开发老师已经把app做好了,已经有了登录模块,首页模块,但是其中有些小服务,比如说门禁进出审核啦,企业名录相关信息啊!这种不太重要的,业务逻辑比较独立的模块,可以分给h5来做,然后原生老师在这里写一个按钮 ‘点我看企业名录’ 然后url配置咱h5的全地址,然后一点击,你就发现一个进度条在屏幕上方挪动,进度条到顶后咱的页面也就展示出来了!这里就是一个混合开发很简单的案例!

3.纯h5, 所有的功能都是前端写的,原生就提供一个套,把你的项目装里面,咋一看好像是个app,点开才发现是个h5! 至于这个套要怎么套,你就跑去烦原生就行!

咱主要说的是第二种,专业点讲就是怎么实现 ‘h5与原生的交互’,其实就是你要拉起支付,调起摄像头扫一扫,包括你要改变这个app当前的头部标题,头部颜色等等你h5实现不了,或者实现起来麻烦的跟手机功能相关的东西你都可以去问原生咋么办,不想问你就去百度.上代码啦:


import api from "@/api/"
// (function() {


//   if (window.iParkJSBridge) {
//     // Android加上了这个if判断,如果当前window已经定义了iParkJSBridge对象,不再重新加载
//     // 避免重新初始化_callback_map等变量,导致之前的消息回调失败,返回cb404
//     //alert('window already has a iParkJSBridge object!!!');
//     return;
//   };
  /////////////////////////////////////////////////////////////////////////////////////////////////
  ///////////////////////////////////本地调用的实际逻辑////////////////////////////////////////////
  var _CUSTOM_PROTOCOL_SCHEME = 'iParkJSBridge',
    callbacksCount = 1,
    callbacks = {},
    appId = '17951';

  function _handleMessageFromPark(callbackId, message) {

    try {
      var callback = callbacks[callbackId];
      if (!callback) return;
      callback.apply(null, [message]);
    } catch (e) {
      alert(e)
    }
  }

    /**
     * 获取用户ua信息,判断OS,同时限制网页在浏览器中随意访问
     * @returns {string}
     */
    function getOS() {
      var android = 'PASC_iPark_Android';
      var ios = 'PASC_iPark_iPhone';
      var userAgent = navigator.userAgent;

      return userAgent.indexOf(ios) != -1 ? 'ios' : userAgent.indexOf(android) != -1 ? 'android' : '';
   }
   

  function _call(functionName, message, callback) {
     if(!getOS()){
       api.commonService.login().then(res=>{
         callback(JSON.stringify({data:{loginSession:res.body.loginsession}}))
       })
       return
     } else {
     var hasCallback = callback && typeof callback == "function";
     var callbackId = hasCallback ? callbacksCount++ : 0;
     if (hasCallback) {
         callbacks[callbackId] = callback;
     }
     if (typeof(message) == "null" || typeof(message) == "undefined") {
         message = {};
     }
     window.prompt(_CUSTOM_PROTOCOL_SCHEME + "¥" + functionName + "¥" + callbackId + "¥" + encodeURIComponent(JSON.stringify(message)));
    }
  }



  var iParkJSBridge = {
    invoke: _call,
    call: _call,
    handleMessageFromPark: _handleMessageFromPark
  };

  window.iParkJSBridge = iParkJSBridge;

// })();

export default iParkJSBridge;

这是一个jsBridge文件,字面意思就是js桥,看不懂没关系,你想在你h5的项目里调原生提供的方法必须要这个文件,没有就去问你们原生老师要,它是用来沟通原生的桥梁,没这玩意儿你说话再大声,原生也听不见,所以咋用呢?

import native from '@/utils/iParkJSBridge.js'

先在main.js引入啦!然后全局挂载,是不是贼拉简单

Vue.prototype.native = process.env.NODE_ENV === 'development' ? nativeDev : native

这个nativeDev是啥意思呢?这里涉及到兼容本地开发模式,比如你们项目是混合开发的,登录是原生做的,那么当打开你h5页面的时候token是不是应该是原生提供给你的?但是这个方法只能在手机上才生效的哇!当你本地开发用浏览器模拟的时候是没法触发的,那你项目跑起来拿不到登录态咋办呢?所有接口都不通,盲敲? 所以才有了 nativeDev,这其实就是一个后端给你写的获取登录态的接口(当然不能替代原生返回的登录态啦),有了它你就可以在浏览器模拟的时候也能正常请求,后端不给?那你就盲敲得了

    // ‘getLoginSession’这是个方法名,由原生定义,调这个方法可以获取到当前的登录态
    // 这个res就不说啦,就是告诉你拿到了,然后你存起来,到时候怎么用token就怎么用这个玩意儿
    native.call('getLoginSession', {}, (res) => {
      var info = JSON.parse(res)
      var data = info['data']
      store.commit('setLoginSession', data['loginSession'])
    })

是不是很简单的取到登录态,至于其他的常见方法比如 native.call('closePage')

function logout () {
  Toast({
    type: 'loading',
    message: '登录失效了,请重新登录',
    duration: 3000
  })
  setTimeout(() => {
    native.call('closePage')
  }, 3000)
}

看到没?只要直接写,这个页面就会被关闭,再细一点? 你还是转行得了,什么时候调还要我举例你玩个锤子前端啊! 就是当登录态失效直接关闭当前h5页面,所以这些东西都是原生提供的文档里有现成的,你去找,找不到就去问!

再给你举个支付的栗子: 比如充值吧!一个按钮,点一下准备充值10元钱:

recharge () {
        let params = {
          money: Math.abs(this.currentCount) * 100
        }
        this.api.mywalletService.recharge(params).then(res => {
          if (res.errorMessage) {
            this.$toast(res.errorMessage)
          } else {
            this.$toast.clear()
            // 后端返回的都是你即将调第三方支付的参数
            this.mchOrderNo = res.body.mchOrderNo
            this.memberNo = res.body.memberNo
            this.amount = res.body.amount
            this.rechargeID = res.body.id
            // 这个lowB的命名不是我写的
            this.yktzh()
          }
        })
   },
    yktzh () {
    // 这个 ‘payRecharge’ 方法就是去调别人的支付方式去了,不好想象没关系,去试试先,不能试就是你用微信付款时点付款按钮后,后面一系列步骤都可以看成 this.native.call('payRecharge')在干的事
      this.native.call('payRecharge',
        {
          'memberNo': this.memberNo,
          'mchOrderNo': this.mchOrderNo,
          'amount': this.amount
        }, (result) => {
          var info = JSON.parse(result)
          var data = info['data']
          if (data['errorCode'] === -4 || data['errorCode'] === 0 || data['errorCode'] === 1) {
            this.walletgetById()
          } else {
            this.$toast(data['errorMsg'])
          }
        })
    },
    walletgetById () {
      this.api.mywalletService.walletgetById({ id: this.rechargeID }).then(res => {
        if (res.errorMessage) {
          this.$toast(res.errorMessage)
        } else {
          if (res.body) {
            if (res.body.orderStatus === 'pay_success') {
              clearInterval(this.timeId)
              // 跳转成功页面
              this.$router.push({ name: 'resultpage',
                params: { res: {
                  resText: '付款成功',
                  resDis: `成功支付${this.currentCount}元`,
                  restoBackText: '返回我的钱包',
                  backHomePage: true,
                  logoRes: true
                } } })
            // tiaozhuan
            } else if (res.body.orderStatus === 'pay_fail') {
              clearInterval(this.timeId)
              // 跳转失败页面
              this.$router.push({ name: 'resultpage',
                params: { res: {
                  resText: '付款失败',
                  resDis: '',
                  restoBackText: '返回我的钱包',
                  backHomePage: true,
                  logoRes: false
                } } })
            // tiaozhuan
            } else if (res.body.orderStatus === 'pay_waiting') {
              clearInterval(this.timeId)
              this.checkNUm++
              if (this.checkNUm === 30) {
                clearInterval(this.timeId)
                // 跳转处理中页面
                this.$router.push({ name: 'resultpage',
                  params: { res: {
                    resText: '处理中',
                    resDis: '',
                    restoBackText: '返回查看明细',
                    backHomePage: true,
                    logoRes: false,
                    backDetail: true
                  } } })
              }
              // lunxun
              this.timeId = setTimeout(() => {
                this.walletgetById()
              }, 1000)
            } else {
              clearInterval(this.timeId)
            }
          }
        }
      })
    },

所以一共也就三个方法,你们随便看看就行,点按钮发请求,拿到参数调原生方法,或者是第三方的sdk,拿到状态吗以后发请求判断接下来要干嘛!其实大部分的活是后端在干,前端就是发发请求的事!所以这么一讲大家是不是稍微明白一点了?

好了,希望我的白话文对你们有点帮助!星空不问赶路人,是我一个好兄弟告诉我的! 为了更好的生活,加油吧兔子们! 对了,这里是h5怎么区原生的方法,但是有没有谁疑问原生要是想控制h5咋办呢?我作为一个h5要怎么配合才显得不low呢? 告诉你一个小秘密,原生可以很粗暴的看到你的代码,然后调你的方法,别问为什么,因为他们就是这么流痞!