查看: 300|回复: 3

uni-app鸿蒙UTS插件开发实战:调用原生API全流程

[复制链接]
发表于 昨天 14:00 | 显示全部楼层 |阅读模式
在uni-app跨平台开发中,当需要调用鸿蒙系统特有的原生能力(如读取设备信息、打开应用市场详情页)时,UTS插件是关键桥梁。UTS(uni-app TypeScript)允许你在uni-app项目中用TypeScript直接调用鸿蒙ArkTS API,省去了JS桥接开销,性能更优。本文以跳转华为应用市场详情页为例,完整演示从创建到调用的技术细节,并总结踩坑经验。

一、新建uni_modules插件
在项目根目录的 'uni_modules' 文件夹(如不存在则新建)内,右键选择“新建uni_modules插件”。插件命名建议用英文,例如 'openAppProduct';注意避免以 'uni-' 开头(官方插件保留前缀),个人插件推荐用开发者标识开头,如 'wq-openAppProduct'。

二、配置package.json声明ArkTS支持
编辑插件根目录的 package.json,在 'uni_modules' 节点下新增 'uni-ext-api' 配置,声明该插件支持鸿蒙ArkTS平台(arkts: true),其他平台对应设为false:
  1. {
  2.   "uni_modules": {
  3.     "uni-ext-api": {
  4.       "uni": {
  5.         "openAppProduct": {
  6.           "name": "openAppProduct",
  7.           "app": {
  8.             "js": false,
  9.             "kotlin": false,
  10.             "swift": false,
  11.             "arkts": true
  12.           }
  13.         }
  14.       }
  15.     }
  16.   }
  17. }
复制代码

三、定义接口类型(interface.uts)
编写 'utssdk/interface.uts' 文件,定义对外暴露的参数类型和回调风格。uni-app规范使用 success/fail/complete 回调:
  1. export interface Uni {
  2.   openAppProduct(options: OpenAppProductOptions): void;
  3. }
  4. export type OpenAppProduct = (options: OpenAppProductOptions) => void;
  5. export type OpenAppProductSuccess = { errMsg: string };
  6. export type OpenAppProductSuccessCallback = (result: OpenAppProductSuccess) => void;
  7. export type OpenAppProductFail = { errMsg: string };
  8. export type OpenAppProductFailCallback = (result: OpenAppProductFail) => void;
  9. export type OpenAppProductComplete = { errMsg: string };
  10. export type OpenAppProductCompleteCallback = (result: OpenAppProductComplete) => void;
  11. export type OpenAppProductOptions = {
  12.   success?: OpenAppProductSuccessCallback | null,
  13.   fail?: OpenAppProductFailCallback | null,
  14.   complete?: OpenAppProductCompleteCallback | null
  15. };
复制代码

四、实现鸿蒙原生代码(app-harmony/index.uts)
编写 'utssdk/app-harmony/index.uts' 文件,调用两个关键鸿蒙API:bundleManager.getBundleInfoForSelfSync 获取当前应用包名,productViewManager.loadProduct 打开应用市场详情页。注意:productViewManager.loadProduct 本身没有成功回调,只有 error 回调,因此代码通过 isSuccess 标志做“反向判断”。
  1. import { OpenAppProduct, OpenAppProductOptions, OpenAppProductSuccess, OpenAppProductFail, OpenAppProductComplete } from '../interface.uts';
  2. import bundleManager from '@ohos.bundle.bundleManager';
  3. export { OpenAppProduct, OpenAppProductOptions, OpenAppProductSuccess, OpenAppProductFail, OpenAppProductComplete };
  4. import { productViewManager } from '@kit.StoreKit';
  5. import { hilog } from '@kit.PerformanceAnalysisKit';
  6. import type { common, Want } from '@kit.AbilityKit';
  7. import { BusinessError } from '@kit.BasicServicesKit';
  8. export function openAppProduct(options: OpenAppProductOptions) {
  9.   let isSuccess = true;
  10.   try {
  11.     const request: Want = {
  12.       parameters: {
  13.         bundleName: bundleManager.getBundleInfoForSelfSync(
  14.           bundleManager.BundleFlag.GET_BUNDLE_INFO_DEFAULT
  15.         ).name
  16.       }
  17.     };
  18.     productViewManager.loadProduct(
  19.       getContext() as common.UIAbilityContext,
  20.       request,
  21.       {
  22.         onError: (err: BusinessError) => {
  23.           isSuccess = false;
  24.           hilog.info(0, 'TAG', `loadProduct onError. code is ${err.code}, message is ${err.message}`);
  25.           let result: OpenAppProductFail = { errMsg: err.message ?? "" };
  26.           const completeResult: OpenAppProductComplete = { errMsg: err.message ?? "" };
  27.           options?.fail?.(result);
  28.           options?.complete?.(completeResult);
  29.         }
  30.       } as productViewManager.ProductViewCallback
  31.     );
  32.   } catch (err) {
  33.     isSuccess = false;
  34.     hilog.error(0, 'TAG', `loadProduct failed. code is ${err.code}, message is ${err.message}`);
  35.     let result: OpenAppProductFail = { errMsg: err.message ?? "" };
  36.     const completeResult: OpenAppProductComplete = { errMsg: err.message ?? "" };
  37.     options?.fail?.(result);
  38.     options?.complete?.(completeResult);
  39.   }
  40.   if (isSuccess) {
  41.     let result: OpenAppProductSuccess = { errMsg: "ok" };
  42.     const completeResult: OpenAppProductComplete = { errMsg: "ok" };
  43.     options?.success?.(result);
  44.     options?.complete?.(completeResult);
  45.   }
  46. }
复制代码

五、在页面中使用插件
方式一:挂载到 uni 全局对象。在任意页面引入一次(避免被Tree Shaking摇掉),然后直接调用 uni.openAppProduct()。
  1. <template>
  2.   <view class="content">
  3.     <button class="button" @click="openAppProductBtn">打开应用市场</button>
  4.   </view>
  5. </template>
  6. <script lang="uts">
  7. // 注意:需要在任意页面引入 1 次,否则可能被摇掉
  8. // import "@/uni_modules/xxx-openAppProduct"
  9. export default {
  10.   methods: {
  11.     openAppProductBtn() {
  12.       uni.openAppProduct({
  13.         success: (res) => { console.log('success: ', JSON.stringify(res)); },
  14.         fail: (err) => { console.error('fail: ', JSON.stringify(err)); },
  15.         complete: (res) => { console.log('complete: ', JSON.stringify(res)); }
  16.       });
  17.     }
  18.   }
  19. }
  20. </script>
复制代码
方式二:直接 import 函数调用,这种方式对Tree Shaking更友好。
  1. <template>
  2.   <view class="content">
  3.     <button class="button" @click="openAppProductBtn">打开应用市场</button>
  4.   </view>
  5. </template>
  6. <script lang="uts">
  7. import { openAppProduct } from "@/uni_modules/xxx-openAppProduct"
  8. export default {
  9.   methods: {
  10.     openAppProductBtn() {
  11.       openAppProduct({
  12.         success: (res: any) => { console.log('success: ', JSON.stringify(res)); },
  13.         fail: (err: any) => { console.error('fail: ', JSON.stringify(err)); },
  14.         complete: (res: any) => { console.log('complete: ', JSON.stringify(res)); }
  15.       });
  16.     }
  17.   }
  18. }
  19. </script>
复制代码

六、运行到鸿蒙设备
在HBuilderX顶部菜单选择“运行 → 运行到手机或模拟器 → 运行到鸿蒙”。新安装的HBuilderX需先点击“下载真机运行插件”安装运行环境。运行后DevEco Studio自动启动并编译部署。

七、调用鸿蒙第三方ohpm库
在UTS插件中也可以调用鸿蒙的ohpm三方库(如支付宝SDK、推送SDK)。安装ohpm包后,在 'utssdk/app-harmony/*.uts' 文件中import使用。注意:ohpm库不能直接在页面的 'pages/*.vue' 中import,必须通过UTS插件封装。示例:
页面中调用:
  1. import { requestPayment } from "@/uni_modules/test-alipay";
  2. requestPayment({ orderInfo: "xxxx" });
复制代码
插件实现 'utssdk/app-harmony/index.uts':
  1. import { Pay } from '@cashier_alipay/cashiersdk';
  2. export interface RequestPaymentOptions { orderInfo: string }
  3. export function requestPayment(options: RequestPaymentOptions) {
  4.   return new Pay().pay(options.orderInfo, true);
  5. }
复制代码

八、UTS插件架构概览
项目目录结构:
  1. 项目根目录/
  2. ├── pages/index/index.vue          # 调用方
  3. ├── uni_modules/xxx-openAppProduct/ # UTS插件
  4. │   ├── package.json                # 配置 arkts: true
  5. │   └── utssdk/
  6. │       ├── interface.uts           # 类型定义(跨平台通用)
  7. │       └── app-harmony/index.uts   # 鸿蒙原生实现
  8. │       # 还可添加 app-android/、app-ios/ 等平台目录
复制代码

九、踩坑记录与注意事项
1. 插件名不要以 uni- 开头,避免与官方插件冲突。
2. interface.uts 中定义的类型,在 app-harmony/index.uts 中必须用相对路径 '../interface.uts' 引入。
3. 挂载到 uni 全局对象的插件,需在任意页面 import 一次,否则可能被Tree Shaking摇掉;使用import函数方式则无需此操作。
4. productViewManager.loadProduct 没有成功回调,只能通过 isSuccess 标志“反向判断”——未进入 error 回调即视为成功。这是鸿蒙 API 的设计局限。
5. 第三方ohpm库只能在UTS插件文件中调用,不能在页面 script 中直接import。
6. 真机运行需先安装“真机运行插件”(HBuilderX提示后点击下载),运行会联动 DevEco Studio。

通过以上步骤,你可以在uni-app鸿蒙项目中高效封装UTS插件,调用原生API或第三方库,实现跨平台原生能力复用。
回复

使用道具 举报

发表于 昨天 14:05 | 显示全部楼层

Re: uni-app鸿蒙UTS插件开发实战:调用原生API全流程

感谢楼主分享这么详细的实战教程!正在研究 uni-app 对接鸿蒙原生能力,这篇从创建插件到配置 package.json 再到回调处理的完整流程太实用了。想请教一下,在 `productViewManager.loadProduct` 里用反向判断 `isSuccess` 处理无成功回调的情况,如果遇到加载失败但没触发 error 回调的情况,会不会有遗漏?有什么兜底处理建议吗?
回复 支持 反对

使用道具 举报

发表于 昨天 14:05 | 显示全部楼层

Re: uni-app鸿蒙UTS插件开发实战:调用原生API全流程

感谢楼主分享这么详细的UTS插件实战教程!正好最近在搞鸿蒙原生能力调用,这篇从创建到配置再到代码实现的全流程非常清晰,尤其是反向判断成功回调的思路,很实用。 我自己也踩过package.json配置的坑,之前没注意“uni-ext-api”节点,导致一直没法调用原生API,看了你的配置才反应过来。另外有个小疑问:如果插件需要同时兼容安卓和iOS,是不是得在package.json里把kotlin和swift也设成true,然后分别写对应的原生代码文件?还有,interface.uts里定义的OpenAppProductOptions没有传入任何参数,实际调用时是靠内部获取包名,那用户在使用时直接传回调就行了对吧? 期待楼主后续能再讲讲多平台兼容的配置,或者结合其他鸿蒙API的例子就更好了。再次感谢!
回复 支持 反对

使用道具 举报

发表于 昨天 14:05 | 显示全部楼层

Re: uni-app鸿蒙UTS插件开发实战:调用原生API全流程

感谢楼主分享这么详细的实战流程!正好最近在踩鸿蒙UTS插件的坑,这篇从创建uni_modules到配置package.json、定义接口再到实现原生调用的全流程,逻辑非常清晰,尤其是对`productViewManager.loadProduct`成功率反向判断的处理,很实用。之前一直没搞懂`isSuccess`标志为什么放try里,看了你的解释就明白了。请问在真机调试时,`bundleManager.getBundleInfoForSelfSync`这一步有没有遇到过权限或签名不一致的问题?期待楼主后续再讲讲其他API的封装经验。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

关注微信公众号

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2026-7-21 08:15 , Processed in 0.027841 second(s), 17 queries , Gzip On, Redis On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部