最近遇到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
交互大致就是这些东西,还有很多小的点值得注意,慢慢补充