![uni-app官网](https://qiniu-web-assets.dcloud.net.cn/unidoc/zh/logo.png)
![uni-app官网](https://qiniu-web-assets.dcloud.net.cn/unidoc/zh/uni-app.png)
简体中文
Windows系统如使用模拟器则需要开启以下功能
打开控制面板 - 程序与功能 - 开启以下功能
注意: 需要win10专业版或win11专业版才能开启以上功能,家庭版需先升级成专业版或企业版
下载 uni-app 鸿蒙离线SDK template-1.3.7.tgz 下载地址
解压刚下载的压缩包,将解压后的模板工程在 DevEco-Studio 中打开
如果没有登录华为账号,此时需要先登录,登录成功后看到如下页面
选择模拟器型号,选第一个即可
安装完模拟器后,点击启动按钮启动模拟器
启动模拟器成功后,如果提示需要先签名,则进行配置签名
注意:真机需要鸿蒙系统版本 API 12 以上
打开鸿蒙手机开发者模式,开启USB调试,通过USB线连接电脑,在此处选择你的手机名称,再启动项目即可,如果提示需要先签名,则进行配置签名
注意:配置签名需要先启动模拟器或连接真机后才能配置
点击 DevEco-Studio 上方菜单 File - Project Structure...
在弹出的窗体中选择 Project - Signing Configs 并打钩 Automatically generate signature,即可自动生成签名
最后依次点击 Apply
和 OK
使签名生效
打开HBuilderX,点击上方菜单 - 工具 - 设置,在出现的弹窗右侧窗体新增如下配置
注意:值填你自己的 DevEco-Studio 启动路径
"harmony.devTools.path" : "D:/Huawei/DevEco Studio"
HBuilderX 新建一个空白的 uniapp 项目,选vue3
在 manifest.json 文件中配置鸿蒙离线SDK路径
编辑 manifest.json 文件,新增如下配置:
"app-harmony": {
"projectPath": "上一步下载的template-1.3.7.tgz的解压地址/package"
}
点击 HBuilderX 上方【运行】菜单,运行到鸿蒙 DevEco Studio
如果没有出现此菜单,请确认你的 HBuilderX 版本是否是 4.22 及以上
先等待 HBuilderX 编译完成,然后打开 DevEco-Studio,点击运行
uni-app在Android和iOS平台,支持uts插件和App原生语言插件。目前App原生语言插件已经停止维护。uts插件是主推的扩展方式。
鸿蒙系统有很多原生API,可以通过uts插件方式接入,被uni-app调用。
详细的教程见:
这里以打开华为应用市场详情页为例
定义API名称为:openAppProduct
新建uni_modules插件
uni-openAppProduct
(注意,开发者自己创建时,不可以使用 uni-
开头,应以自己名字或昵称的缩写命令,如:wq-openAppProduct
package.json
中的 uni_modules
节点,新增如下配置,arkts 为 true 代表支持鸿蒙注意:下方的属性名中包含的 uni
请勿更改成自己的名字或昵称缩写,只能用 uni
{
...其他属性
"uni_modules": {
"uni-ext-api": {
"uni": {
"openAppProduct": {
"name": "openAppProduct",
"app": {
"js": false,
"kotlin": false,
"swift": false,
"arkts": true
}
}
}
},
...其他属性
}
}
/utssdk/interface.uts
文件,内容如下export interface Uni {
/**
* openAppProduct()
* @description
* 跳转应用市场详情页
* @param {OpenAppProductOptions} options
* @return {void}
* @example
```typescript
uni.openAppProduct({});
```
*/
openAppProduct(options : OpenAppProductOptions) : void;
}
export type OpenAppProduct = (options : OpenAppProductOptions) => void;
export type OpenAppProductSuccess = {
/**
* 错误信息
*/
errMsg : string
};
export type OpenAppProductSuccessCallback = (result : OpenAppProductSuccess) => void;
export type OpenAppProductFail = {
/**
* 错误信息
*/
errMsg : string
};
export type OpenAppProductFailCallback = (result : OpenAppProductFail) => void;
export type OpenAppProductComplete = {
/**
* 错误信息
*/
errMsg : string
};
export type OpenAppProductCompleteCallback = (result : OpenAppProductComplete) => void;
export type OpenAppProductOptions = {
/**
* 接口调用成功的回调函数
* @defaultValue null
*/
success ?: OpenAppProductSuccessCallback | null,
/**
* 接口调用失败的回调函数
* @defaultValue null
*/
fail ?: OpenAppProductFailCallback | null,
/**
* 接口调用结束的回调函数(调用成功、失败都会执行)
* @defaultValue null
*/
complete ?: OpenAppProductCompleteCallback | null
};
/utssdk/app-harmony/index.uts
文件(没有则新建),内容如下import {
OpenAppProduct,
OpenAppProductOptions,
OpenAppProductSuccess,
OpenAppProductFail,
OpenAppProductComplete
} from '../interface.uts'
import bundleManager from '@ohos.bundle.bundleManager';
export {
OpenAppProduct,
OpenAppProductOptions,
OpenAppProductSuccess,
OpenAppProductFail,
OpenAppProductComplete
}
import { productViewManager } from '@kit.StoreKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import type { common, Want } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';
export function openAppProduct(options : OpenAppProductOptions) {
let isSuccess = true;
try {
const request : Want = {
parameters: {
// 此处填入要加载的应用包名,例如: bundleName: "com.huawei.hmsapp.appgallery"
bundleName: bundleManager.getBundleInfoForSelfSync(bundleManager.BundleFlag.GET_BUNDLE_INFO_DEFAULT).name // 加载当前包名
}
};
productViewManager.loadProduct(getContext() as common.UIAbilityContext, request, {
onError: (err : BusinessError) => {
isSuccess = false;
hilog.info(0, 'TAG', `loadProduct onError. code is ${err.code}, message is ${err.message}`);
let result : OpenAppProductFail = {
errMsg: err.message ?? ""
};
const completeResult : OpenAppProductComplete = {
errMsg: err.message ?? ""
}
options?.fail?.(result);
options?.complete?.(completeResult);
}
} as productViewManager.ProductViewCallback);
} catch (err) {
isSuccess = false;
hilog.error(0, 'TAG', `loadProduct failed. code is ${err.code}, message is ${err.message}`);
let result : OpenAppProductFail = {
errMsg: err.message ?? ""
};
const completeResult : OpenAppProductComplete = {
errMsg: err.message ?? ""
}
options?.fail?.(result);
options?.complete?.(completeResult);
}
// productViewManager.loadProduct 没有成功回调,故以此方式判断是否成功执行
if (isSuccess) {
let result : OpenAppProductSuccess = {
errMsg: "ok"
};
const completeResult : OpenAppProductComplete = {
errMsg: "ok"
}
options?.success?.(result);
options?.complete?.(completeResult);
}
}
/pages/index/index.vue
内容如下方式一(挂载到uni全局对象)
<template>
<view class="content">
<button class="button" @click="openAppProductBtn">打开应用市场</button>
</view>
</template>
<script lang="uts">
export default {
data() {
return {
}
},
onLoad() {
},
methods: {
openAppProductBtn() {
uni.openAppProduct({
success: (res) => {
console.log('success: ', JSON.stringify(res));
},
fail: (err) => {
console.error('fail: ', JSON.stringify(err));
},
complete: (res) => {
console.log('complete: ', JSON.stringify(res));
}
});
}
}
}
</script>
<style>
.content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.button{
width: 100%;
margin: 10px;
}
</style>
方式二(使用import引入)
<template>
<view class="content">
<button class="button" @click="openAppProductBtn">打开应用市场</button>
</view>
</template>
<script lang="uts">
import { openAppProduct } from "@/uni_modules/xxx-openAppProduct"
export default {
data() {
return {
}
},
onLoad() {
},
methods: {
openAppProductBtn() {
openAppProduct({
success: (res : any) => {
console.log('success: ', JSON.stringify(res));
},
fail: (err : any) => {
console.error('fail: ', JSON.stringify(err));
},
complete: (res : any) => {
console.log('complete: ', JSON.stringify(res));
}
});
}
}
}
</script>
<style>
.content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.button{
width: 100%;
margin: 10px;
}
</style>
新增于HBuilderX 4.25
鸿蒙的包用法和npm包差不多,在鸿蒙项目里面用ohpm安装三方库后,在 /uni_modules/uts插件名/utssdk/app-harmony/index.uts
内即可直接 import
注意:只能在满足uts插件 /uni_modules/*/utssdk/app-harmony/*.uts
的文件下使用,无法直接在项目的pages中使用
具体使用流程:在项目的pages引入uts插件,uts插件内再引入鸿蒙第三方库调用
以调用 @cashier_alipay/cashiersdk
为例,代码如下
page
内代码
// 导入要使用的插件
import { requestPayment } from "@/uni_modules/test-alipay";
requestPayment({
orderInfo: "xxxx"
});
/uni_modules/*/utssdk/app-harmony/*.uts
内的代码
import { Pay } from '@cashier_alipay/cashiersdk'
export interface RequestPaymentOptions {
orderInfo: string
}
export function requestPayment(options : RequestPaymentOptions) {
return new Pay().pay(options.orderInfo, true)
}
鸿蒙官方文档提供了如何发布鸿蒙应用,详见文档
仅 APP-HARMONY 和 APP 可以条件编译命中鸿蒙平台,APP-PLUS 不能命中中鸿蒙平台
// #ifdef APP-HARMONY
console.log("仅鸿蒙会编译")
// #endif
// #ifndef APP-HARMONY
console.log("仅非鸿蒙会编译")
// #endif
// #ifdef APP
console.log("安卓、苹果、鸿蒙会编译,小程序和Web不会编译")
// #endif
// #ifndef APP
console.log("安卓、苹果、鸿蒙不会编译,小程序和Web会编译")
// #endif
// #ifdef APP-PLUS
console.log("安卓、苹果会编译,鸿蒙不会编译,小程序和Web也不会编译")
// #endif
// #ifndef APP-PLUS
console.log("安卓、苹果不会编译,鸿蒙会编译,小程序和Web也会编译")
// #endif
新增于HBuilderX 4.26
map组件、getLocation、openLocation、chooseLocation依赖于地图厂商。目前仅支持腾讯地图,且此界面上显示的地图是通过webview加载的。由于目前页面使用的并非http协议,因此在申请腾讯地图key时需要将域名白名单留空以便地图能正确加载出来。后续在harmonyOS上页面会调整成以http方式加载,到时可以在腾讯地图控制台配置域名白名单。
在uni-app项目内配置腾讯地图key:
{
// ...
"app-plus" : {
// ...
"distribute" : {
// ...
"sdkConfigs" : {
// ...
"maps" : {
"qqmap" : {
"key" : "XXX-XXXX-XXXX"
}
}
}
}
},
// ...
}
在编译到鸿蒙时,plus对象不可用。如果要向webview发送消息,可以使用WebviewContext的evalJs,注意此方案来源于uni-app-x,非uni-app-x仅鸿蒙支持。
示例如下:
// uni-app页面
<template>
<view class="content">
<web-view id="web" @message="onMessage" src="/static/index.html"></web-view>
</view>
</template>
<script>
let context
const native = {
add: (a, b, callback) => {
callback(undefined, a + b)
}
}
function callback(id, err, data) {
context.evalJs(
`window.__bridge.callback(${id}, ${err ? JSON.stringify(err) : undefined}, ${data ? JSON.stringify(data) : undefined})`
)
}
export default {
data() {
return {
title: 'Hello'
}
},
onLoad() {},
onReady() {
context = uni.createWebviewContext('web', this)
},
methods: {
onMessage(event) {
const dataList = event.detail.data
dataList.forEach(({
data
} = {}) => {
if (data && typeof data === 'object' && data.action === '__invoke') {
const {
method,
args,
id
} = data
if (!(method in native)) {
return callback(id, {
message: `method:${method} not found`
})
}
try {
native[method](...args, (err, data) => {
callback(id, err, data)
})
} catch (e) {
callback(id, e)
}
}
})
}
}
}
</script>
<style>
</style>
<!-- webview内的html -->
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>JSBridge Demo</title>
</head>
<body>
<button id="call-native-method">callNativeMethod</button>
<script type="text/javascript" src="./uni.webview.1.5.6.js"></script>
<script>
let callbackId = 0
const callbacks = {}
window.__bridge = {
invoke(method, args, callback) {
const id = callbackId++
callbacks[id] = callback
uni.postMessage({
data: {
action: '__invoke',
method,
args,
id
}
});
},
callback(callbackId, err, data) {
const callback = callbacks[callbackId]
if (!callback) {
return
}
delete callbacks[callbackId]
callback(err, data)
}
}
document.querySelector('#call-native-method').addEventListener('click', () => {
console.log(uni)
window.__bridge.invoke('add', [1, 2], (err, data) => {
console.log('invoke add callback:', err, data)
})
})
</script>
</body>
</html>
AppScope\app.json5
修改 bundleName
删除 build-profile.json5
内旧的签名信息
重启鸿蒙 DevEco Studio,启动模拟器或连接真机后,重新配置签名
AppScope\resources\base\element\string.json
修改数组元素 name 值为 app_name 对应的 value 的值entry\src\main\resources\base\element\string.json
修改数组元素 name 值为 EntryAbility_label 对应的 value 的值entry\src\main\resources\en_US\element\string.json
修改数组元素 name 值为 EntryAbility_label 对应的 value 的值entry\src\main\resources\zh_CN\element\string.json
修改数组元素 name 值为 EntryAbility_label 对应的 value 的值替换以下文件,注意文件不要改名
虽然鸿蒙官方文档提供了如何开启热重载,详见文档,但目前只能针对ets文件的修改进行热更,还无法针对uniapp打包的js文件进行热更。
目前编译到鸿蒙时,在uniapp页面通过console.log打印日志无法在 HBuilderX 直接查看,需要在鸿蒙DevEco Studio内查看,具体查看方法如下图所示
注意:在uniapp页面打印对象或数组时,需要 JSON.stringify
,如 console.log("obj", JSON.stringify(obj))
首先尝试重新编译uniapp项目,并重启模拟器或真机,如果依然白屏或闪退,那可能是你项目中有用到了鸿蒙不支持的组件或者api,可以尝试pages.json进行代码二分法排查(删除一半页面如果正常了代表被删除的那一半页面中有造成白屏或闪退的页面)
确保签名没有问题的情况下,尝试重启电脑
Windows系统
Windows系统快速复制路径方法
注意:复制后的 \
要改成 /
原路径后面添加 /bin/devecostudio64.exe
,然后重启 HBuilderX
Mac系统
Mac系统快速复制路径方法
原路径后面添加 /Contents/MacOS/devecostudio
,然后重启 HBuilderX
当前导航栏未支持,可以尝试关闭原生导航栏,使用自己的自定义导航栏组件实现。
暂不支持
Cannot read property route of undefined
此问题由于arkTs的混淆Bug引发,即使进入到一个空的组合式api页面也会出现这个报错,已反馈给鸿蒙团队处理。
临时解决方案:在鸿蒙项目entry/obfuscation-rules.txt
文件中增加一行-disable-obfuscation
来禁用混淆。
Install Failed: error: failed to install bundle
此问题是由于支付宝sdk兼容性造成的,目前只能删除支付宝sdk依赖,如下图所示操作,删除后需要点右上角的 Sync Now,并等待 Sync 结束
删除后还需要点右上角的 Sync Now,并等待 Sync 结束