H5与App交互实践

最近遇到App 与H5交互的需求,具体场景是安卓IOS开发遇到一个静态的页面,由于开发周期和项目维护成本的问题就把这个页面交给前端来做。整个页面只有一个接口交互。前端获取经纬度数据,拿到数据之后去请求接口。项目中遇到了很多的问题,大部分都是交互速度与用户体验优化问题。具体见下:

方案一:前端项目开发部署上线安卓IOS通过webView访问前端页面。在路由中传递经纬度参数。在这里需要考虑到App传过来的参数可能为空的情况。若为空则由前端去调用高德地图Api获取经纬度(若路由传参为空,获取经纬度很慢,不推荐)
<template>
  <div class="main-container">
   	<div>经纬度</div>
   	<div>
   	  <!--打印一下列表的数据-->
	  <div v-for="item in list" :key="item.id">
	    {{item.name}}
	  </div>
	<div>
  </div>
</template>

<script>
import { getLocation } from '@/utils/getLocation' //引入封装好的方法
import * as Api from '@/api/quest.js' // 请求数据接口
export default {
  data() {
    return {
      params: {}, // 接口请求参数
      list: [], // 存放请求到的数据
    }
  },
  mounted() {
    this.fetchList()
  },
  methods: {
    async getPosition() {
    // 如果路由参数携带了经纬度信息则直接使用,否则调用H5方法获取经纬度
      const { lng, lat } = this.$route.query
      if (lng && lat) {
        this.params = { lng, lat }
      } else {
        const { lng, lat } = await getLocation()
        this.params = { lng, lat }
      }
    },
    async fetchList() {
        await this.getPosition()
        const { list = [] } = await Api.list(this.params)
        this.list = list
    }
  }
}
</script>

<style lang="less" scoped>
// 样式
</style>

附上utils中获取经纬度getLocation方法代码,不详细介绍,可自行查阅之前的博客
function loadSDK() {
  if (window.AMap) return
  return new Promise((resolve, reject) => {
    const script = document.createElement('script')
    script.src =
      '//webapi.amap.com/maps?v=1.4.6&key=93a6530af2063c6456115cabc328ec37'
    document.head.appendChild(script)
    script.onload = resolve
    script.onerror = reject
  })
}

export default async () => {
  await loadSDK()
  return new Promise((resolve) => {
    // eslint-disable-next-line no-undef
    AMap.plugin('AMap.Geolocation', () => {
      // eslint-disable-next-line no-undef
      const geolocation = new AMap.Geolocation({ enableHighAccuracy: false })
      geolocation.getCurrentPosition((status, result) => {
        const res =
          status === 'complete'
            ? result.position
            : { lat: 39.909187, lng: 116.397451 } //默认北京 116.397451、39.909187
        console.log('定位结果', res)
        resolve(res)
      })
    })
  })
}

方案二:由于方案一App 端请求可能由于很多原因造成的页面加载速度慢导致用户体验不佳的情况。所以修改方案为前端打包由App放到本地沙盒中,这样可以大大缩短加载速度。为了更进一步优化采用了H5与App端交互获取经纬度(推荐,速度比较快)
<template>
  <div class="main-container">
   	<div>经纬度</div>
   	<div>
   	  <!--打印一下列表的数据-->
	  <div v-for="item in list" :key="item.id">
	    {{item.name}}
	  </div>
	<div>
  </div>
</template>

<script>
import { getLocation } from '@/api/bridge' // 交互方法
import * as Api from '@/api/quest.js' // 请求数据接口
export default {
  data() {
    return {
      params: {}, // 接口请求参数
      list: [], // 存放请求到的数据
    }
  },
  mounted() {
    this.fetchList()
  },
  methods: {
    async getPosition() {
    // 如果路由参数携带了经纬度信息则直接使用,否则调用H5方法获取经纬度
      const { lng, lat } = this.$route.query
      if (lng && lat) {
        this.params = { lng, lat }
      } else {
        const { lng, lat } = await getLocation()
        this.params = { lng, lat }
      }
    },
    async fetchList() {
        await this.getPosition()
        const { list = [] } = await Api.list(this.params)
        this.list = list
    }
  }
}
</script>

<style lang="less" scoped>
// 样式
</style>
接口方法(api/bridge):
import bridge from '@/utils/bridge'

//获取地理位置
export async function getLocation() {
  const res = await bridge.callHandler({
    action: 'halo_fun_page', // 与后端确定好的action
    data: { get_latlng: 1 } // 与后端确定好的请求参数
  })
  if (!res) return
  // 根据返回的数据结构处理返回前端需要的数据格式
  const { get_latlng } = JSON.parse(res) 
  const { lat, lng } = JSON.parse(get_latlng)
  return { lat, lng }
}
交互方法封装(utils/bridge)
import { isMyApp } from '@/utils/validate'

// 注册方法获取WebViewJavascriptBridge对象
function setupWebViewJavascriptBridge(callback) {
  if (window.WebViewJavascriptBridge) {
    return callback(window.WebViewJavascriptBridge)
  }
  if (window.WVJBCallbacks) {
    return window.WVJBCallbacks.push(callback)
  }
  // 兼容安卓
  document.addEventListener(
    'WebViewJavascriptBridgeReady',
    () => callback(window.WebViewJavascriptBridge),
    false
  )
  // 兼容ios
  window.WVJBCallbacks = [callback]
  var WVJBIframe = document.createElement('iframe')
  WVJBIframe.style.display = 'none'
  WVJBIframe.src = 'https://__bridge_loaded__'
  document.documentElement.appendChild(WVJBIframe)
  setTimeout(function() {
    document.documentElement.removeChild(WVJBIframe)
  }, 0)
}
//  获取WebViewJavascriptBridge对象
function getBirdge() {
  return new Promise((resolve) => {
    if (window.WebViewJavascriptBridge) {
      return resolve(window.WebViewJavascriptBridge)
    }
    setupWebViewJavascriptBridge((bridge) => {
      resolve(bridge)
    })
  })
}
// 重写之后的birdge
const bridge = {
  ctx: null, // WebViewJavascriptBridge
  async callHandler(data) {
    if (!isMyApp) {
      console.log('app is error')
      return Promise.reject('bridge error')
    }
    if (!this.ctx) {
      this.ctx = await getBirdge()
    }
    data.data = JSON.stringify(data.data)
    // 根据业务场景重写数据
    return new Promise((resolve) => {
      this.ctx.callHandler('commonActionV2', data, (res) => resolve(res))
    })
  },
  registerHandler(jsHandlerName, fn) {
    window[jsHandlerName] = fn
    // 重写事件注册方法
    // this.ctx.registerHandler(jsHandlerName, (data, callback) => {
    //   if (callback) {
    //     callback(
    //       `返回一个字符串,告诉ObjC:我已收到数据${JSON.stringify(data)}`
    //     )
    //   }
    // })
  }
}
export default bridge

交互大致就是这些东西,还有很多小的点值得注意,慢慢补充

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值