前言
随着华为纯血鸿蒙系统的到来,App对于鸿蒙的支持也需要提上日程,幸运的是,之前App是基于跨端框架uni-app开发的,uni-app最近也慢慢的实现了对于鸿蒙的支持,当然还有许多问题需要完善,需要陪其一起踩坑。不幸的是,我们之前使用的是vue2,uni-app的vue2版本没有支持鸿蒙,改造需要太多的工作量,所以前期先采用取巧的方式,先用vue3版本开发一个鸿蒙的App,然后之前项目编译为h5通过web-view的方式嵌入,这样子就需要考虑到cookie/token的共享,h5怎么调用App原生方法等问题,这就涉及到了h5和App之间通信。
这篇文章能学习到的:
- App和h5之间的通信,支持鸿蒙
- h5调用App原生方法封装
- 使用Promise封装通信库
- 开发过程中遇到的一些坑,及对应的解决方案
- 提供完整代码
原理
h5向App发送数据
h5向App发送数据,主要是使用postMessage方法,按照uni-app官网讲的,可以使用window.postMessage,但经过我的实践,这个方法并没办法发送数据,所以采用另外一种方式uni.postMessage,值得注意的是这个方法虽然是以uni开头,但在h5中并没有这个方法,需要额外引入一个js(uni.webview.1.5.6.js)才能支持,需要1.5.6版本才支持鸿蒙系统。另外一个点是这个文件提供的全局变量是uni,如果你的子应用也是uni-app开发的,那可能会导致变量冲突,因为这个文件是一个commonjs,可以直接修改全局变量,我将其改为了webUni,修改后的代码在下面有提供uni.webview.js。
uni.webview.js
已经是commonjs代码了,不需要在进行打包(如果进行重新编译后会报错),可以直接在index.html中引入,对于不需要打包文件,你可能想着将js文件放在public文件夹下,但这样子在uni-app中并不行,它不会帮你拷贝到构建结果dist中,推荐方式可以放在static文件夹下,所以在index.html添加代码:
<script type="text/javascript" src="/static/js/uni.webview.js"></script>
需要等待UniAppJSBridgeReady
事件触发后,才能调用对应API,这个事件是由uni.webview.js触发的。传递数据是格式要求的,必须写在 data 对象中。所以发送消息的具体代码如下:
document.addEventListener('UniAppJSBridgeReady', function() {
uni.postMessage({
data: {
action: 'message'
}
});
})
App端接收h5发送的数据
h5向APP发送消息后,可以在 <web-view>
的 message
事件回调 event.detail.data
中接收消息。event.detail.data是一个数组,正常只有一个数据,所以直接取数组的第一项就可以了。
接收消息的代码如下:
<template>
<web-view id="webview" @message="handleMessage" src="http://www.test.com"></web-view>
</template>
<script setup>
const handleMessage = (e) => {
const data = e.detail.data[0];
console.log(data);
};
</script>
App向h5发送数据
App向h5发送数据主要是在h5中将事件挂载到window全局对象上,然后App端获取当前页面的webview对象,通过webView.evalJS方法执行h5被挂载到window上的方法,将数据作为方法的参数,这个样子在h5中的方法被执行时,可以获取到来自App传递的参数。当然对于App获取webview对象,在Android和IOS系统
和鸿蒙系统
是存在差异的,以及evalJS方法也存在坑点。
Android和IOS系统
在以前vue2时是通过this.$scope.$getAppWebview()
来获取当前页面的webview对象。在vue3的组合式 API (Composition API)并没办法直接使用this,我采用getCurrentInstance获取当前实例,可惜的是当前实例中没有$scope
属性。所以采用另外一种方式,获取当前页面路由实例,在其中有包含$getAppWebview
方法。uni-app并没有提供直接获取当前页面路由的方法,可以通过getCurrentPages方法获取所有路由,然后取出最后一个,就是当前页面的路由。
$getAppWebview这个方法也不是直接获取到webview实例,需要在children中获取,根据官网描述,还需要有个setTimout的延迟。如果我们需要将App的token发送给H5,那么需要在H5的window上挂载一个方法,例如window.getToken,那么Android和IOS系统发送token给H5的代码就是这样子。
- App端
// 获取所有页面路由
const pages = getCurrentPages();
// 找到最后一个索引
const index = pages.length - 1;
// 获取到当前页面的webView实例
const currentWebview = pages[index].$getAppWebview();
setTimeout(() => {
// 取到真正的webview
const webView = currentWebview.children()[0];
// 通过evalJS执行H5中的getToken方法,并将token作为参数传递
const token = 'token_123456789';
webView.evalJS(`getToken('${token}')`);
});
- H5端
// 在window上挂载getToken方法,等待被执行,然后获取Token
window.getToken = function(token) {
// 被App执行后,就可以获取来自App的token
console.log(token)
}
鸿蒙系统
在鸿蒙系统中,获取webView对象的方式更简单一些,可以通过uni.createWebviewContext(webviewId, component?)方法来创建webview实例,这个方法需要两个参数,第一个参数为webviewId,第二个参数为组件实例,也就是this。官网说第二个参数为可选,我实践中发现如果不传第二个参数的话是会报错的。需要注意的点:
- 需要在web-view标签上添加id属性,我设置的id为webview;
- getCurrentInstance不要写到函数内部里面,比如handleMessage里面
- 注意鸿蒙这边webview.evalJs的最一个s是小写的,而Android和IOS系统最后一个s为大写
- 一般App向h5发送数据,需要H5的window上挂载了事件,这也意味着需要h5资源正常加载了,不然就找不到window事件了。那App怎么知道H5加载了呢,可以在H5端向App发送个数据,告知App我已经加载好了,你可以发送数据了,所以我这边把发送数据写在了handleMessage中。从另外一个角度来讲,不需要App主动去发送数据,而是H5主动来拿数据。
鸿蒙系统的代码如下:
<template>
<web-view id="webview" @message="handleMessage" src="http://www.test.com"></web-view>
</template>
<script setup>
import { getCurrentInstance } from 'vue';
const context = getCurrentInstance();
const handleMessage = (e) => {
const data = e.detail.data[0];
// 这边可以加类型判断
const webview = uni.createWebviewContext('webview', context);
const token = 'token_xxx';
webview.evalJs(`getToken('${token}')`);
};
</script>
Promise封装
我们现在已经实现了H5向App发送数据,以及App向H5发送数据,满足了基本需求,但是总感觉还差了点什么,有点割裂感,两者之间互不相关。或者说我从H5发送了个数据,想要等待App那边处理完在返回给我,但我并不知道在哪里等待,或者处理起来很麻烦。聪明的你一定想到了,裹一层Promise不就能满足我们的需求了嘛,那就一起看看怎么将通信Promise化。我们这边主要是对于H5向App通讯封装为Promise。
对于将一些功能Promise化,我们已经熟练到脚趾头都能实现,新增一个函数,返回一个Promise,成功的话,执行resolve,失败的话,执行reject。我们这个也是一样的,将uni.postMessage放在一个函数中,然后执行函数的时候返回一个Promise,主要问题是怎么才能让App执行resolve,reject呢。我们又想到了App执行的是H5挂载到window上的方法,那我们将resolve,reject挂载到window上,不就实现了。我们将token通信改为这样子:
- H5端代码
getToken() {
return new Promise((resolve, reject) => {
const data = { type: 'token' };
webUni.postMessage({
data,
});
window.tokenResolve = resolve;
window.tokenReject = reject;
});
}
// 使用方式
// 当tokenResolve方法被App执行,就能在then中获取token了
getToken().then((res) => {
console.log(res);
}).catch((err) => {
console.log(err);
});
- App端
const handleMessage = (e) => {
const data = e.detail.data[0];
const webview = uni.createWebviewContext('webview', context);
const token = 'token_xxx';
// 这边就可以执行H5中Promise的resolve方法了
webview.evalJs(`tokenResolve('${token}')`);
};
原生事件的支持
我们除了一些数据通信之外,H5没办法执行App原生事件也是我们的一大痛点,我们还需要将这个功能做一下封装。对于Android和IOS来说原生事件有uni和plus两部分,例如:扫码功能uni.scanCode、获取当前应用的APPID的plus.runtime.appid。而对于鸿蒙来说,由于不支持plus,所以只有uni相关事件。但我们还是需要支持uni和plus两种原生事件的调用。
uni-app提供的原生方法主要有两种,一种是函数类型的,执行一个函数,传递一个对象,对象中包含函数参数和success和fail回调,成功的话执行success回调,失败了执行fail回调,例如:uni.scanCode,一种是属性类型的,执行完之后就能直接获取到值,例如:plus.runtime.appid,下面提供两种类型的大致代码结构。
// 函数类型
uni.scanCode({
// 函数参数
scanType: ['barCode'],
success: function (res) {
console.log(res);
},
fail: function(err) {
console.log(err);
}
});
// 属性类型
plus.runtime.appid;// 输出 xxxxxxx
因为这两种调用方式的结构还是比较固定的,就可以有个设想,H5向App传递一个函数名称和参数(可选),例如:{fn: 'uni.scanCode', params?: {scanType: ['barCode']}},然后判断fn是否为函数,如果不是函数的话,可以直接执行,然后将直接结果传递给H5;如果fn是函数的话,将params作为函数参数进行执行,手动添加success和fail方法,在success中执行H5挂载在window的resolve,fail中执行H5挂载在window的reject方法,这样子就可以在H5中的then中获取到直接结果,才catch中获取到报错内容,这样子说的话可能有点抽象,可以直接看如下代码。
- 我们只对于uni和plus方法进行处理,当然可以根据自己的需要进行扩展
- H5传递过来的函数名称只是一个字符串
'uni.scanCode'
,并没办法执行,所以需要对其进行处理,然后从uni或者plus对象上获取到真正的函数或者属性才能进行执行。
// 解析函数名称
const parseNativeFn = (fnName) => {
const uniReg = /^uni.(.+)/;
const plusReg = /^plus.(.+)/;
let nativeFn = null;
let reg = null;
if (uniReg.test(fnName)) {
nativeFn = uni;
reg = uniReg;
} else if (plusReg.test(fnName)) {
nativeFn = plus;
reg = plusReg;
} else {
return;
}
fnName = fnName.match(reg)[1];
const fnNameArr = fnName.split('.');
for (const key of fnNameArr) {
nativeFn = nativeFn[key];
}
return nativeFn;
};
- 这边的data就是H5传递过来的参数
- evalJS是webview上的webview.evalJS
- invokeResolve和invokeReject是H5执行原生插件时Promise的resolve和reject
- 假设fn为扫码功能uni.scanCode,那么params就是其需要的参数{scanType: ['barCode']}
- App传给H5的参数需要为字符串,所以加了JSON.stringify。
// 执行原生插件
const invokeNativePlugin = (data, evalJS) => {
const { fn, params } = data;
if (!fn) {
evalJS(`invokeReject('请传入函数名称!')`);
return;
}
// 字符串转为真实的原生方法
const nativeFn = parseNativeFn(fn);
if (!nativeFn) {
evalJS(`invokeReject('${fn}该方法不存在!')`);
return;
}
if (typeof nativeFn === 'function') {
nativeFn({
...params,
success: function (res) {
evalJS(`invokeResolve(${JSON.stringify(res)})`);
},
fail: function (err) {
evalJS(`invokeReject(${JSON.stringify(err)})`);
},
});
} else {
// 不是函数,例如plus.runtime.appid,执行完就可以获取到值
evalJS(`invokeResolve('${nativeFn}')`);
}
};
- 在H5中就可以这么使用
/**
* 调用 uni.xxx 方法,例如 uni.getLocation
* @param {string} fn 函数名称 必填
* @param {object} params 函数参数 可选
* @returns 结果为Promise
*/
uni.nativeInstance
.invoke({
fn: 'uni.getLocation',
params: {
type: 'wgs84',
},
})
.then((res) => {
console.log(res);
})
.catch((err) => {
console.log(err);
});
完整代码
APP端代码
页面代码
<template>
<web-view
id="webview"
@message="handleMessage"
src="http://www.test.com"
></web-view>
</template>
<script setup>
import { getCurrentInstance } from 'vue';
import invokeNative from '@/utils/invokeNative.js';
const context = getCurrentInstance();
const handleMessage = (e) => {
const data = e.detail.data[0];
invokeNative(data, context);
};
</script>
src/utils/invokeNative.js
// 解析函数名称
const parseNativeFn = (fnName) => {
const uniReg = /^uni\.(.+)/;
const plusReg = /^plus\.(.+)/;
let nativeFn = null;
let reg = null;
if (uniReg.test(fnName)) {
nativeFn = uni;
reg = uniReg;
} else if (plusReg.test(fnName)) {
nativeFn = plus;
reg = plusReg;
} else {
return;
}
fnName = fnName.match(reg)[1];
const fnNameArr = fnName.split('.');
for (const key of fnNameArr) {
nativeFn = nativeFn[key];
}
return nativeFn;
};
// 执行原生插件
const invokeNativePlugin = (data, evalJS) => {
const { fn, params } = data;
if (!fn) {
evalJS(`invokeReject('请传入函数名称!')`);
return;
}
const nativeFn = parseNativeFn(fn);
if (!nativeFn) {
evalJS(`invokeReject('${fn}该方法不存在!')`);
return;
}
if (typeof nativeFn === 'function') {
nativeFn({
...params,
success: function (res) {
evalJS(`invokeResolve(${JSON.stringify(res)})`);
},
fail: function (err) {
evalJS(`invokeReject(${JSON.stringify(err)})`);
},
});
} else {
evalJS(`invokeResolve('${nativeFn}')`);
}
};
const getToken = async (evalJS) => {
// TODO: 根据实际方式获取
const token = 'token_123456';
evalJS(`tokenResolve('${token}')`);
};
const getEvalJs = async (context) => {
return new Promise((resolve) => {
// #ifdef APP-HARMONY
const webview = uni.createWebviewContext('webview', context);
resolve(webview.evalJS || webview.evalJs);
// #endif
// #ifndef APP-HARMONY
const pages = getCurrentPages();
const index = pages.length - 1;
const currentWebview = pages[index].$getAppWebview();
setTimeout(() => {
const webView = currentWebview.children()[0];
resolve((code) => webView.evalJS(code));
});
// #endif
});
};
const invokeNative = async (data, context) => {
const { type } = data;
const evalJS = await getEvalJs(context);
if (type === 'token') {
getToken(evalJS);
} else if (type === 'invoke') {
invokeNativePlugin(data, evalJS);
}
};
export default invokeNative;
h5端代码
index.html
<script>
document.addEventListener('UniAppJSBridgeReady', function () {
window.__UniAppJSBridgeReady__ = true;
});
</script>
<script type="text/javascript" src="/static/js/uni.webview.js"></script>
/static/js/uni.webview.js
!(function (e, n) {
'object' == typeof exports && 'undefined' != typeof module
? (module.exports = n())
: 'function' == typeof define && define.amd
? define(n)
: ((e = e || self).webUni = n());
})(this, function () {
'use strict';
try {
var e = {};
Object.defineProperty(e, 'passive', {
get: function () {
!0;
},
}),
window.addEventListener('test-passive', null, e);
} catch (e) {}
var n = Object.prototype.hasOwnProperty;
function i(e, i) {
return n.call(e, i);
}
var t = [];
function o() {
return window.__dcloud_weex_postMessage || window.__dcloud_weex_;
}
function a() {
return window.__uniapp_x_postMessage || window.__uniapp_x_;
}
var r = function (e, n) {
var i = { options: { timestamp: +new Date() }, name: e, arg: n };
if (a()) {
if ('postMessage' === e) {
var r = { data: n };
return window.__uniapp_x_postMessage
? window.__uniapp_x_postMessage(r)
: window.__uniapp_x_.postMessage(JSON.stringify(r));
}
var d = {
type: 'WEB_INVOKE_APPSERVICE',
args: { data: i, webviewIds: t },
};
window.__uniapp_x_postMessage
? window.__uniapp_x_postMessageToService(d)
: window.__uniapp_x_.postMessageToService(JSON.stringify(d));
} else if (o()) {
if ('postMessage' === e) {
var s = { data: [n] };
return window.__dcloud_weex_postMessage
? window.__dcloud_weex_postMessage(s)
: window.__dcloud_weex_.postMessage(JSON.stringify(s));
}
var w = {
type: 'WEB_INVOKE_APPSERVICE',
args: { data: i, webviewIds: t },
};
window.__dcloud_weex_postMessage
? window.__dcloud_weex_postMessageToService(w)
: window.__dcloud_weex_.postMessageToService(JSON.stringify(w));
} else {
if (!window.plus)
return window.parent.postMessage(
{ type: 'WEB_INVOKE_APPSERVICE', data: i, pageId: '' },
'*'
);
if (0 === t.length) {
var u = plus.webview.currentWebview();
if (!u) throw new Error('plus.webview.currentWebview() is undefined');
var g = u.parent(),
v = '';
(v = g ? g.id : u.id), t.push(v);
}
if (plus.webview.getWebviewById('__uniapp__service'))
plus.webview.postMessageToUniNView(
{ type: 'WEB_INVOKE_APPSERVICE', args: { data: i, webviewIds: t } },
'__uniapp__service'
);
else {
var c = JSON.stringify(i);
plus.webview
.getLaunchWebview()
.evalJS(
'UniPlusBridge.subscribeHandler("'
.concat('WEB_INVOKE_APPSERVICE', '",')
.concat(c, ',')
.concat(JSON.stringify(t), ');')
);
}
}
},
d = {
navigateTo: function () {
var e =
arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
n = e.url;
r('navigateTo', { url: encodeURI(n) });
},
navigateBack: function () {
var e =
arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
n = e.delta;
r('navigateBack', { delta: parseInt(n) || 1 });
},
switchTab: function () {
var e =
arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
n = e.url;
r('switchTab', { url: encodeURI(n) });
},
reLaunch: function () {
var e =
arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
n = e.url;
r('reLaunch', { url: encodeURI(n) });
},
redirectTo: function () {
var e =
arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
n = e.url;
r('redirectTo', { url: encodeURI(n) });
},
getEnv: function (e) {
a()
? e({ uvue: !0 })
: o()
? e({ nvue: !0 })
: window.plus
? e({ plus: !0 })
: e({ h5: !0 });
},
postMessage: function () {
var e =
arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {};
r('postMessage', e.data || {});
},
},
s = /uni-app/i.test(navigator.userAgent),
w = /Html5Plus/i.test(navigator.userAgent),
u = /complete|loaded|interactive/;
var g =
window.my &&
navigator.userAgent.indexOf(
['t', 'n', 'e', 'i', 'l', 'C', 'y', 'a', 'p', 'i', 'l', 'A']
.reverse()
.join('')
) > -1;
var v =
window.swan && window.swan.webView && /swan/i.test(navigator.userAgent);
var c =
window.qq &&
window.qq.miniProgram &&
/QQ/i.test(navigator.userAgent) &&
/miniProgram/i.test(navigator.userAgent);
var p =
window.tt &&
window.tt.miniProgram &&
/toutiaomicroapp/i.test(navigator.userAgent);
var _ =
window.wx &&
window.wx.miniProgram &&
/micromessenger/i.test(navigator.userAgent) &&
/miniProgram/i.test(navigator.userAgent);
var m = window.qa && /quickapp/i.test(navigator.userAgent);
var f =
window.ks &&
window.ks.miniProgram &&
/micromessenger/i.test(navigator.userAgent) &&
/miniProgram/i.test(navigator.userAgent);
var l =
window.tt &&
window.tt.miniProgram &&
/Lark|Feishu/i.test(navigator.userAgent);
var E =
window.jd && window.jd.miniProgram && /jdmp/i.test(navigator.userAgent);
var x =
window.xhs &&
window.xhs.miniProgram &&
/xhsminiapp/i.test(navigator.userAgent);
for (
var S,
h = function () {
(window.UniAppJSBridge = !0),
document.dispatchEvent(
new CustomEvent('UniAppJSBridgeReady', {
bubbles: !0,
cancelable: !0,
})
);
},
y = [
function (e) {
if (s || w)
return (
window.__uniapp_x_postMessage ||
window.__uniapp_x_ ||
window.__dcloud_weex_postMessage ||
window.__dcloud_weex_
? document.addEventListener('DOMContentLoaded', e)
: window.plus && u.test(document.readyState)
? setTimeout(e, 0)
: document.addEventListener('plusready', e),
d
);
},
function (e) {
if (_)
return (
window.WeixinJSBridge && window.WeixinJSBridge.invoke
? setTimeout(e, 0)
: document.addEventListener('WeixinJSBridgeReady', e),
window.wx.miniProgram
);
},
function (e) {
if (c)
return (
window.QQJSBridge && window.QQJSBridge.invoke
? setTimeout(e, 0)
: document.addEventListener('QQJSBridgeReady', e),
window.qq.miniProgram
);
},
function (e) {
if (g) {
document.addEventListener('DOMContentLoaded', e);
var n = window.my;
return {
navigateTo: n.navigateTo,
navigateBack: n.navigateBack,
switchTab: n.switchTab,
reLaunch: n.reLaunch,
redirectTo: n.redirectTo,
postMessage: n.postMessage,
getEnv: n.getEnv,
};
}
},
function (e) {
if (v)
return (
document.addEventListener('DOMContentLoaded', e),
window.swan.webView
);
},
function (e) {
if (p)
return (
document.addEventListener('DOMContentLoaded', e),
window.tt.miniProgram
);
},
function (e) {
if (m) {
window.QaJSBridge && window.QaJSBridge.invoke
? setTimeout(e, 0)
: document.addEventListener('QaJSBridgeReady', e);
var n = window.qa;
return {
navigateTo: n.navigateTo,
navigateBack: n.navigateBack,
switchTab: n.switchTab,
reLaunch: n.reLaunch,
redirectTo: n.redirectTo,
postMessage: n.postMessage,
getEnv: n.getEnv,
};
}
},
function (e) {
if (f)
return (
window.WeixinJSBridge && window.WeixinJSBridge.invoke
? setTimeout(e, 0)
: document.addEventListener('WeixinJSBridgeReady', e),
window.ks.miniProgram
);
},
function (e) {
if (l)
return (
document.addEventListener('DOMContentLoaded', e),
window.tt.miniProgram
);
},
function (e) {
if (E)
return (
window.JDJSBridgeReady && window.JDJSBridgeReady.invoke
? setTimeout(e, 0)
: document.addEventListener('JDJSBridgeReady', e),
window.jd.miniProgram
);
},
function (e) {
if (x) return window.xhs.miniProgram;
},
function (e) {
return document.addEventListener('DOMContentLoaded', e), d;
},
],
M = 0;
M < y.length && !(S = y[M](h));
M++
);
S || (S = {});
var P = 'undefined' != typeof webUni ? webUni : {};
if (!P.navigateTo) for (var b in S) i(S, b) && (P[b] = S[b]);
return (P.webView = S), P;
});
/src/utils/getNativeInstance.js
class NativeInstance {
constructor() {
this.readyPromise = new Promise((resolve) => {
if (window.__UniAppJSBridgeReady__) {
resolve();
}
document.addEventListener('UniAppJSBridgeReady', function () {
resolve();
});
});
}
async invoke(data) {
await this.readyPromise;
data = {
type: 'invoke',
...data,
};
webUni.postMessage({
data,
});
return new Promise((resolve, reject) => {
window.invokeResolve = resolve;
window.invokeReject = reject;
});
}
async getToken() {
await this.readyPromise;
const data = { type: 'token' };
webUni.postMessage({
data,
});
return new Promise((resolve) => {
window.tokenResolve = resolve;
});
}
async logout() {
await this.readyPromise;
const data = { type: 'logout' };
webUni.postMessage({
data,
});
}
async close() {
await this.readyPromise;
const data = { type: 'close' };
webUni.postMessage({
data,
});
}
async switchTitle(title) {
await this.readyPromise;
const data = { type: 'title', title };
webUni.postMessage({
data,
});
}
}
let instance = null;
export default () => {
// #ifdef H5
if (!instance) {
instance = new NativeInstance();
}
// #endif
return instance;
};
main.js
import getNativeInstance from '@/utils/getNativeInstance.js';
uni.nativeInstance = getNativeInstance();
使用方式
获取token
/**
* 获取Token
* @returns 结果为Promise
*/
uni.nativeInstance
.getToken()
.then((res) => {
console.log(res);
})
.catch((err) => {
console.log(err);
});
调用uni原生方法
/**
* 调用 uni.xxx 方法,例如 uni.getLocation
* @param {string} fn 函数名称 必填
* @param {object} params 函数参数 必填
* @returns 结果为Promise
*/
uni.nativeInstance
.invoke({
fn: 'uni.getLocation',
params: {
type: 'wgs84',
},
})
.then((res) => {
console.log(res);
alert(res);
})
.catch((err) => {
console.log(err);
});
调用plus原生方法
/**
* 调用 plus.xxx.xxx 方法,例如 plus.device.uuid
* @param {string} fn 函数名称 必填
* @param {object} params 函数参数 选填
* @returns 结果为Promise
*/
uni.nativeInstance
.invoke({
fn: 'plus.device.uuid',
})
.then((res) => {
console.log(res);
})
.catch((err) => {
console.log(err);
});
总结
这篇文章提供了uni-app的vue2版本或者普通vue项目支持鸿蒙App的一种方式,同时讲解Android和IOS
以及鸿蒙系统
中App和H5如何进行通信,并对其做了Promise封装,支持双向通信,在通信中衍生出了H5对于App原生方法的调用,最后提供了完整代码。
如果觉得这篇文章对您有帮助,欢迎点赞收藏,有问题也欢迎指出。