使用uniapp制作安卓app容器

1. 背景

项目需要做一个安卓app,而且不需要上架应用市场,部门也没有安卓开发,想着就套个webview就行了吧。没有选择react native之类的是因为这些工具需要安装很多环境工具,我只是开发一个壳子没必要这么复杂。

webview也方便快速修复页面问题。

所以最后选择了uniapp,但是uniapp本身就是套在一个大的webview下的, 所以再套一个webview难免会有一些意想不到的问题,下面就是一些踩过的坑记录。

2. 项目初始化

新建项目就默认模板就行,我只需要壳子。

启动了之后可以看到有两个调试工具

第一个就是网页上常用的vue调试工具,可以看到vue组件属性啥的,第二个就是类似chrome的控制台,但是无法查看元素,还有就是必须让设备和电脑在同一个网段下才行,不然连接不上。

hbuilder的控制台本身也有一些输出,比如页面的console

但是这里输出对象的时候不是很方便查看,如果你需要的话就打开上面说的第二个调试工具。

3. webview使用

整个项目很简单,大概就这样一个页面

html 复制代码
<template>
	<web-view :src='PROJECT_PATH' @message="onMessage"></web-view>
</template>
<script>
    // ...
</script>

3.1 网页与app通信

这是最重要的一个功能,可以参考官方文档

网页和app交互总结起来就是这两点:

  • 网页 -> APPwindow.uni.postMessage();
  • APP -> 网页webview.evalJS()

3.1.1. 网页 -> APP

首先要在项目中引入uni.webview.js,这个就相当于jsbridge,可以让网页操作uniapp

初始化完成后会在window上挂载一个uni对象,通过uni.postMessage就能往app发送消息,app中监听onMessage就行。

这里有几个小坑:

  1. 发送的格式window.uni.postMessage({ data: 数据 }),必须要有个字段data,这样app才能收到数据。源码

2. 发送的数据不需要序列化成字符串,uniapp会转换json。 3. appmessage事件中接收到事件参数应该这样解构

ts 复制代码
function onMessage(e) {
    const {
            type,
            data
    } = e.detail.data[0]
}

3.1.2. APP -> 网页

app向网页传输消息就直接调用网页的js就行了。这里我统一封装了一个函数:

ts 复制代码
// app向网页发送消息
const deliverMessage = (msg) => {
    // 调用webview中的deliverMessage函数
    // 这个函数是我在网页挂载的一个全局函数,调用deliverMessage后会触发页面中的一些事件
    currentWebview.evalJS(`deliverMessage(${JSON.stringify(msg)})`)
}

上面的代码例子中出现的currentWebview需要我们自己去获取。

ts 复制代码
// vue2中
const rootWebview = this.$scope.$getAppWebview()
this.currentWebview = rootWebview.children()[0]

// vue3中
import {
    getCurrentInstance,
    ref,
} from "vue";
const currentWebview = ref(null)
const vueInstance = getCurrentInstance()
const rootWebview = vueInstance.proxy.$scope.$getAppWebview()
currentWebview.value = rootWebview.children()[0]

这里也有一个坑,rootWebview.children()如果你一渲染就获取是无法获取到webview实例的,具体原因没有深入研究,估计是异步的原因

这里提供两个思路:

  1. 加一个定时器,延迟获取webview,这个方法虽然听起来不保险,但是实际测试还是挺稳当的。关键是简单。
ts 复制代码
setTimeout(() => {
    currentWebview.value = rootWebview.children()[0]
}, 1000)
  1. 你要是觉得定时器不保险,那就使用plusapi手动创建webview。但是消息处理这块比较麻烦。官网参考
html 复制代码
<template>
    <!-- 这里面就不需要webview组件了 -->
</template>
ts 复制代码
// 我这里vue3为例
onMounted(() => {
    plus.globalEvent.addEventListener('plusMessage', ({data: {type, args}}) => {
        // 是网页调用uni的api
        if(type === 'WEB_INVOKE_APPSERVICE') {
            const {data: {name, arg}} = args
            // 是发送消息事件
            if(name === 'postMessage') {
                // arg就是传过来的数据
            }
        }
    })
    const wv = plus.webview.create("", "webview", {
        'uni-app': 'none',
    })
    wv.loadURL(网页地址)
    rootWebview.append(wv);
})

plus.globalEvent.addEventListener这个是翻源码找到的,主要是我不想改uni.webview.js的源码,所以只有找到正确的监听事件。

WEB_INVOKE_APPSERVICEuniapp内部定义的一个名字,反正就是用来交互操作的命名空间。

这样基础的互操作就有了。

3.1.3. 整个流程

  1. 网页调用window.uni.postMessage({ data }) => app监听(用组件的onMessage或者自定义的globalEvent
  2. app调用网页定义的函数deliverMessage并传递参数,网页中的deliverMessage内部处理监听
ts 复制代码
// 网页中的deliverMessage
window.deliverMessage = (msg) => {
  // 触发网页注册的监听器
  eventListeners.forEach((listener) => {
    
  });
};

3.2. 返回拦截

默认情况下,手机按下返回键,app会响应提示是否退出,但是实际我需要网页进入二级路由的时候,按下手机返回键是返回上一级路由而不是退出。当路由是一级路由时才提示是否退出app

ts 复制代码
import {
    onBackPress,
    onShow,
} from '@dcloudio/uni-app'
// 页面当前的路由信息
const pageRoute = shallowRef()
onBackPress(() => {
    // tab页正常app返回逻辑
    if (pageRoute.value?.isTab) {
        return false
    } else {
        // 二级路由拦截app返回
        return true
    }
})

pageRoute是页面当前路由信息,页面通过监听路由变化触发routeChange事件,将路由信息传给app。当按下返回键的时候,判断当前路由配置是不是tab页,如果是就正常退出,不是就拦截返回。

4. 总结

有了通信功能,很多操作就可以实现了,比如获取设备safeArea,获取设备联网状态等等。

相关推荐
jessezappy13 分钟前
jQuery-Word-Export 使用记录及完整修正文件下载 jquery.wordexport.js
前端·word·jquery·filesaver·word-export
上优18 分钟前
uniapp 选择 省市区 省市 以及 回显
大数据·elasticsearch·uni-app
旧林84340 分钟前
第八章 利用CSS制作导航菜单
前端·css
yngsqq1 小时前
c#使用高版本8.0步骤
java·前端·c#
Myli_ing1 小时前
考研倒计时-配色+1
前端·javascript·考研
余道各努力,千里自同风1 小时前
前端 vue 如何区分开发环境
前端·javascript·vue.js
软件小伟2 小时前
Vue3+element-plus 实现中英文切换(Vue-i18n组件的使用)
前端·javascript·vue.js
醉の虾2 小时前
Vue3 使用v-for 渲染列表数据后更新
前端·javascript·vue.js
张小小大智慧2 小时前
TypeScript 的发展与基本语法
前端·javascript·typescript
hummhumm2 小时前
第 22 章 - Go语言 测试与基准测试
java·大数据·开发语言·前端·python·golang·log4j