解决小程序分包引用分包下的json文件编译后生成到主包的问题
问题
目前,小程序端,分包引用分包下的json文件编译后会生成到主包中
解决方案
方案一
把 json 文件改成 js 文件,通过 export default 导出,manifest.json 中指定的小程序节点(比如mp-weixin)需要配置
"optimization": {
"subPackages": true
}
方案二
使用 @uni_toolkit/unplugin-json-optimization 插件
安装
# npm
npm install @uni_toolkit/unplugin-json-optimization -D
# yarn
yarn add @uni_toolkit/unplugin-json-optimization -D
# pnpm
pnpm add @uni_toolkit/unplugin-json-optimization -D
使用方法
// vite.config.js
import { defineConfig } from 'vite'
import uni from "@dcloudio/vite-plugin-uni"
import jsonOptimization from '@uni_toolkit/unplugin-json-optimization/vite'
export default defineConfig({
plugins: [
uni(),
jsonOptimization(),
],
}) 问题
目前,小程序端,分包引用分包下的json文件编译后会生成到主包中
解决方案
方案一
把 json 文件改成 js 文件,通过 export default 导出,manifest.json 中指定的小程序节点(比如mp-weixin)需要配置
"optimization": {
"subPackages": true
}
方案二
使用 @uni_toolkit/unplugin-json-optimization 插件
安装
# npm
npm install @uni_toolkit/unplugin-json-optimization -D
# yarn
yarn add @uni_toolkit/unplugin-json-optimization -D
# pnpm
pnpm add @uni_toolkit/unplugin-json-optimization -D
使用方法
// vite.config.js
import { defineConfig } from 'vite'
import uni from "@dcloudio/vite-plugin-uni"
import jsonOptimization from '@uni_toolkit/unplugin-json-optimization/vite'
export default defineConfig({
plugins: [
uni(),
jsonOptimization(),
],
}) 收起阅读 »
【紧急!!】谷歌报READ_MEDIA_IMAGES/READ_MEDIA_VIDEO 权限的相关要求,无法移除这两个权限
之前还好好的,最近发布的app都被拒绝了,提示这两个权限需要移除,由于使用次数和场景不太多,但是我在配置做了移除,谷歌还是扫描出来了,麻烦官方予以介入解决。这块已经直接导致无法上架最新版本的包了。是否有能解决办法,并且能兼容ios和安卓所有场景的使用。
之前还好好的,最近发布的app都被拒绝了,提示这两个权限需要移除,由于使用次数和场景不太多,但是我在配置做了移除,谷歌还是扫描出来了,麻烦官方予以介入解决。这块已经直接导致无法上架最新版本的包了。是否有能解决办法,并且能兼容ios和安卓所有场景的使用。
在 UniApp 中用 UTS 封装钉钉登录(HarmonyOS)
在 UniApp 中用 UTS 封装钉钉登录(HarmonyOS)
插件开发背景
业务需要在鸿蒙端提供一键授权登录的统一能力。钉钉开放平台已提供标准 ArkTS 能力,通过 ArkUI 组件与 UTS 的嵌入式原生组件机制,将授权登录流程抽象为一个可复用的页面 <embed> 组件。目标是:最少的页面接入代码、清晰的事件回调、可控的依赖与权限声明。仅考虑 ArkTS API。
这里用到了嵌入原生组件能力。
鸿蒙原生实现(ArkUI + OpenAuth)
核心在 ETS 侧完成交互和授权触发,依赖 @dingtalk/openauth:
// utssdk/app-harmony/button.ets(示意结构)
import { NativeEmbedBuilderOptions, defineNativeEmbed } from "@dcloudio/uni-app-runtime"
import { DDAuthApiFactory, AuthLoginParam } from '@dingtalk/openauth'
interface ButtonBuilderOptions extends NativeEmbedBuilderOptions {
label: string
// 其他自定义参数,如登录场景、回调地址等
}
@Component
struct ButtonComponent {
@Prop label: string
onButtonClick?: Function
build() {
Button(this.label)
.width('100%')
.height('100%')
.onClick(() => {
if (this.onButtonClick) {
const param: AuthLoginParam = {
// 根据业务填充必要参数,例如 appId、scope、state 等
}
DDAuthApiFactory.createDDAuthApi(param).authLogin(this)
this.onButtonClick({ detail: { status: 'pending' } })
}
})
}
}
@Builder
function ButtonBuilder(options: ButtonBuilderOptions) {
ButtonComponent({
label: options.label,
onButtonClick: options?.on?.get('buttonclick')
})
.width(options.width)
.height(options.height)
}
defineNativeEmbed('button', { builder: ButtonBuilder })
要点说明:
Button负责视觉与交互,授权调用走DDAuthApiFactory。- *通过
options.on映射到组件内部回调,事件名约定为全小写(如buttonclick)。 - UTS/ETS 不支持结构化类型等价,事件
detail与自定义参数类型要统一定义和复用。
UTS 封装实现(目录、依赖、导出)
目录结构:
uni_modules/harmony-dingding-login/
└─ utssdk/
├─ app-harmony/
│ ├─ index.uts
│ ├─ button.ets
│ ├─ config.json
│ └─ module.json5
└─ interface.uts
关键文件:
utssdk/app-harmony/config.json引入三方依赖(已内置):
{
"dependencies": {
"@dingtalk/openauth": "^1.1.0"
}
}
utssdk/app-harmony/index.uts负责激活原生组件:
// 内容即导入 ETS,触发注册
import './button.ets'
utssdk/interface.uts建议集中声明:事件细节、错误码、可选参数类型,确保 UTS/ETS 双侧一致。
用户使用说明(页面接入)
最少 3 步:
- 在页面引入插件:
import '@/uni_modules/harmony-dingding-login' - 在模板中使用
<embed>:指定tag="button"、绑定@buttonclick - 组织
options:包含按钮文案、宽高、以及钉钉授权所需参数
示例:
<template>
<view>
<embed class="dd-login" tag="button" :options="options" @buttonclick="onLogin" />
</view>
<!-- 建议宽高固定,避免布局跳动 -->
</template>
<script>
import '@/uni_modules/harmony-dingding-login'
export default {
data() {
return {
options: {
width: 200,
height: 44,
label: '钉钉登录',
on: new Map(), // 可按需传入,也可使用 @buttonclick 监听
// 可放置与授权相关的业务参数,以便在 ETS 读取
// appId、scope、state 等
}
}
},
methods: {
onLogin(e) {
// e.detail 建议包含授权阶段/结果数据
console.log('dingding auth:', e.detail)
// 与后端交换 code/token,完成会话建立
}
}
}
</script>
<style scoped>
.dd-login { display: block; width: 200px; height: 44px; }
</style>
注意事项
- 依赖已内置:
@dingtalk/openauth版本^1.1.0写入utssdk/app-harmony/config.json。
有疑问可留言说明
遇到授权参数、事件结构、标签命名、真机兼容等问题,直接留言描述运行环境与报错信息(含系统版本、设备型号、必要截图)。
在 UniApp 中用 UTS 封装钉钉登录(HarmonyOS)
插件开发背景
业务需要在鸿蒙端提供一键授权登录的统一能力。钉钉开放平台已提供标准 ArkTS 能力,通过 ArkUI 组件与 UTS 的嵌入式原生组件机制,将授权登录流程抽象为一个可复用的页面 <embed> 组件。目标是:最少的页面接入代码、清晰的事件回调、可控的依赖与权限声明。仅考虑 ArkTS API。
这里用到了嵌入原生组件能力。
鸿蒙原生实现(ArkUI + OpenAuth)
核心在 ETS 侧完成交互和授权触发,依赖 @dingtalk/openauth:
// utssdk/app-harmony/button.ets(示意结构)
import { NativeEmbedBuilderOptions, defineNativeEmbed } from "@dcloudio/uni-app-runtime"
import { DDAuthApiFactory, AuthLoginParam } from '@dingtalk/openauth'
interface ButtonBuilderOptions extends NativeEmbedBuilderOptions {
label: string
// 其他自定义参数,如登录场景、回调地址等
}
@Component
struct ButtonComponent {
@Prop label: string
onButtonClick?: Function
build() {
Button(this.label)
.width('100%')
.height('100%')
.onClick(() => {
if (this.onButtonClick) {
const param: AuthLoginParam = {
// 根据业务填充必要参数,例如 appId、scope、state 等
}
DDAuthApiFactory.createDDAuthApi(param).authLogin(this)
this.onButtonClick({ detail: { status: 'pending' } })
}
})
}
}
@Builder
function ButtonBuilder(options: ButtonBuilderOptions) {
ButtonComponent({
label: options.label,
onButtonClick: options?.on?.get('buttonclick')
})
.width(options.width)
.height(options.height)
}
defineNativeEmbed('button', { builder: ButtonBuilder })
要点说明:
Button负责视觉与交互,授权调用走DDAuthApiFactory。- *通过
options.on映射到组件内部回调,事件名约定为全小写(如buttonclick)。 - UTS/ETS 不支持结构化类型等价,事件
detail与自定义参数类型要统一定义和复用。
UTS 封装实现(目录、依赖、导出)
目录结构:
uni_modules/harmony-dingding-login/
└─ utssdk/
├─ app-harmony/
│ ├─ index.uts
│ ├─ button.ets
│ ├─ config.json
│ └─ module.json5
└─ interface.uts
关键文件:
utssdk/app-harmony/config.json引入三方依赖(已内置):
{
"dependencies": {
"@dingtalk/openauth": "^1.1.0"
}
}
utssdk/app-harmony/index.uts负责激活原生组件:
// 内容即导入 ETS,触发注册
import './button.ets'
utssdk/interface.uts建议集中声明:事件细节、错误码、可选参数类型,确保 UTS/ETS 双侧一致。
用户使用说明(页面接入)
最少 3 步:
- 在页面引入插件:
import '@/uni_modules/harmony-dingding-login' - 在模板中使用
<embed>:指定tag="button"、绑定@buttonclick - 组织
options:包含按钮文案、宽高、以及钉钉授权所需参数
示例:
<template>
<view>
<embed class="dd-login" tag="button" :options="options" @buttonclick="onLogin" />
</view>
<!-- 建议宽高固定,避免布局跳动 -->
</template>
<script>
import '@/uni_modules/harmony-dingding-login'
export default {
data() {
return {
options: {
width: 200,
height: 44,
label: '钉钉登录',
on: new Map(), // 可按需传入,也可使用 @buttonclick 监听
// 可放置与授权相关的业务参数,以便在 ETS 读取
// appId、scope、state 等
}
}
},
methods: {
onLogin(e) {
// e.detail 建议包含授权阶段/结果数据
console.log('dingding auth:', e.detail)
// 与后端交换 code/token,完成会话建立
}
}
}
</script>
<style scoped>
.dd-login { display: block; width: 200px; height: 44px; }
</style>
注意事项
- 依赖已内置:
@dingtalk/openauth版本^1.1.0写入utssdk/app-harmony/config.json。
有疑问可留言说明
遇到授权参数、事件结构、标签命名、真机兼容等问题,直接留言描述运行环境与报错信息(含系统版本、设备型号、必要截图)。
收起阅读 »【鸿蒙征文】uni-app 现有 UI 库兼容鸿蒙系统开发指南
uni-app 现有 UI 库兼容鸿蒙系统开发指南
核心结论:现有基于 Vue3 开发的 uni-app UI 库插件适配鸿蒙系统的门槛较低,无需大规模重构,重点攻克版本适配、API 兼容性等关键细节后即可正常编译运行。
一、前置核心要求
以下为 UI 库兼容鸿蒙的基础前提,未满足前会导致编译流程直接失败,需优先处理。
1.1 强制升级 Vue 版本至 Vue3
鸿蒙平台对 uni-app 的编译支持仅适配 Vue3 框架,Vue2 版本无法完成编译流程。若当前 UI 库仍基于 Vue2 开发,必须先完成版本升级,具体操作可参考官方权威文档:
官方升级指南:Vue2升级到Vue3指南
1.2 代码风格兼容说明
Vue3 支持选项式 API 和组合式 API(setup 语法糖)两种编码风格,鸿蒙编译环境对两者均完全兼容,无需强制将选项式风格重构为组合式。
提示:如果采用选项式 API 开发可实现「一套代码兼容 Vue2 和 Vue3 双环境」,降低多平台维护成本;
二、关键兼容性处理
完成前置要求后,需针对性处理鸿蒙不支持的核心 API 及对象,这是适配工作的核心环节。
2.1 彻底移除或替代 plus 对象
鸿蒙系统不支持 uni-app 中的 plus 对象(HTML5+ 扩展能力),若 UI 库中存在 plus 对象调用,需根据业务场景选择以下两种方案处理,确保编译通过。
方案 1:功能降级处理(快速适配首选)
这是应急方案,适用于非核心功能依赖 plus 对象的场景,通过条件编译在鸿蒙环境中屏蔽相关功能,保留其他平台的完整性。
核心原理: 利用 uni-app 的条件编译语法,针对鸿蒙平台(标识为 harmony)单独剔除 plus 相关代码块,避免编译报错。
示例代码:
// #ifndef APP-HARMONY
// 鸿蒙不支持的 plus 功能代码
plus.xxx();
// #endif
方案 2:UTS 重构实现(保留完整功能)
这是最完美的方案,通过 UTS 重构原 plus 功能,调用鸿蒙原生 API 实现等效能力。UTS 是 uni-app 跨平台的底层开发语言,可直接对接各平台原生能力。
参考资源:
-
UTS 语法基础:UTS 官方文档
-
鸿蒙原生 API 对接示例:UTS 调用鸿蒙 API 教程
2.2 处理不兼容的 uni.xxx API
目前 uni-app 已实现 90% 以上核心 API 对鸿蒙的支持,但仍有部分 API 存在兼容性限制,需按以下流程处理:
步骤 1:查询 API 兼容性
通过 uni-app 官方文档的「兼容性说明」模块,精准判断 API 是否支持鸿蒙:
- 打开 uni-app API 文档中心;
- 找到目标 API 页面,查看「平台兼容性」表格;
- 若「HarmonyOS」列标注具体版本号(如 3.0+),则支持;若显示「不支持」或空白,则需处理。
步骤 2:替换不支持的 API
与处理plus对象一样,使用【降级处理】或【UTS 重构】方式解决不支持的 API
三、常见问题解决方案
3.1 降级处理详细说明
定义:降级处理是指在鸿蒙平台中,用功能更基础但兼容性更广的实现替代不支持的 API/功能,或在不影响核心体验的前提下屏蔽非必要功能,确保整体流程通顺。
核心原则:「保核心、砍次要」,优先保障 UI 库的渲染、交互等核心能力,对个性化扩展功能可适当简化。
3.2 UTS 重构实操示例
- 鸿蒙原生 API 对接示例:UTS调用鸿蒙API教程
3.3 样式异常处理
目前鸿蒙基本上兼容所有css样式,但如果在鸿蒙上css样式显示异常,可以考虑使用条件编译专门为鸿蒙编写样式。
四、测试与发行流程
适配完成后,需通过官方工具完成编译测试和发行,确保 UI 库在鸿蒙设备上正常运行。
请查看鸿蒙运行和发行
uni-app 现有 UI 库兼容鸿蒙系统开发指南
核心结论:现有基于 Vue3 开发的 uni-app UI 库插件适配鸿蒙系统的门槛较低,无需大规模重构,重点攻克版本适配、API 兼容性等关键细节后即可正常编译运行。
一、前置核心要求
以下为 UI 库兼容鸿蒙的基础前提,未满足前会导致编译流程直接失败,需优先处理。
1.1 强制升级 Vue 版本至 Vue3
鸿蒙平台对 uni-app 的编译支持仅适配 Vue3 框架,Vue2 版本无法完成编译流程。若当前 UI 库仍基于 Vue2 开发,必须先完成版本升级,具体操作可参考官方权威文档:
官方升级指南:Vue2升级到Vue3指南
1.2 代码风格兼容说明
Vue3 支持选项式 API 和组合式 API(setup 语法糖)两种编码风格,鸿蒙编译环境对两者均完全兼容,无需强制将选项式风格重构为组合式。
提示:如果采用选项式 API 开发可实现「一套代码兼容 Vue2 和 Vue3 双环境」,降低多平台维护成本;
二、关键兼容性处理
完成前置要求后,需针对性处理鸿蒙不支持的核心 API 及对象,这是适配工作的核心环节。
2.1 彻底移除或替代 plus 对象
鸿蒙系统不支持 uni-app 中的 plus 对象(HTML5+ 扩展能力),若 UI 库中存在 plus 对象调用,需根据业务场景选择以下两种方案处理,确保编译通过。
方案 1:功能降级处理(快速适配首选)
这是应急方案,适用于非核心功能依赖 plus 对象的场景,通过条件编译在鸿蒙环境中屏蔽相关功能,保留其他平台的完整性。
核心原理: 利用 uni-app 的条件编译语法,针对鸿蒙平台(标识为 harmony)单独剔除 plus 相关代码块,避免编译报错。
示例代码:
// #ifndef APP-HARMONY
// 鸿蒙不支持的 plus 功能代码
plus.xxx();
// #endif
方案 2:UTS 重构实现(保留完整功能)
这是最完美的方案,通过 UTS 重构原 plus 功能,调用鸿蒙原生 API 实现等效能力。UTS 是 uni-app 跨平台的底层开发语言,可直接对接各平台原生能力。
参考资源:
-
UTS 语法基础:UTS 官方文档
-
鸿蒙原生 API 对接示例:UTS 调用鸿蒙 API 教程
2.2 处理不兼容的 uni.xxx API
目前 uni-app 已实现 90% 以上核心 API 对鸿蒙的支持,但仍有部分 API 存在兼容性限制,需按以下流程处理:
步骤 1:查询 API 兼容性
通过 uni-app 官方文档的「兼容性说明」模块,精准判断 API 是否支持鸿蒙:
- 打开 uni-app API 文档中心;
- 找到目标 API 页面,查看「平台兼容性」表格;
- 若「HarmonyOS」列标注具体版本号(如 3.0+),则支持;若显示「不支持」或空白,则需处理。
步骤 2:替换不支持的 API
与处理plus对象一样,使用【降级处理】或【UTS 重构】方式解决不支持的 API
三、常见问题解决方案
3.1 降级处理详细说明
定义:降级处理是指在鸿蒙平台中,用功能更基础但兼容性更广的实现替代不支持的 API/功能,或在不影响核心体验的前提下屏蔽非必要功能,确保整体流程通顺。
核心原则:「保核心、砍次要」,优先保障 UI 库的渲染、交互等核心能力,对个性化扩展功能可适当简化。
3.2 UTS 重构实操示例
- 鸿蒙原生 API 对接示例:UTS调用鸿蒙API教程
3.3 样式异常处理
目前鸿蒙基本上兼容所有css样式,但如果在鸿蒙上css样式显示异常,可以考虑使用条件编译专门为鸿蒙编写样式。
四、测试与发行流程
适配完成后,需通过官方工具完成编译测试和发行,确保 UI 库在鸿蒙设备上正常运行。
请查看鸿蒙运行和发行
收起阅读 »鸿蒙 UTS 插件开发实战:屏幕方向控制插件的完整实现
一、插件开发背景
在移动应用开发中,屏幕方向控制是一个常见且重要的功能需求
本文将详细介绍如何开发一个完整的鸿蒙屏幕方向控制 UTS 插件,包括原生 API 的使用、UTS 封装的实现细节以及最佳实践。
二、鸿蒙原生实现分析
2.1 鸿蒙屏幕方向 API 概述
鸿蒙系统提供了完善的窗口管理能力,屏幕方向控制主要通过 @ohos.window 模块实现。核心 API 包括:
- window.Orientation 枚举:定义了所有可用的屏幕方向
- setPreferredOrientation() 方法:设置窗口的首选显示方向
- getPreferredOrientation() 方法:获取当前窗口的显示方向
2.2 window.Orientation 枚举值详解
enum Orientation {
UNSPECIFIED = 0, // 未指定方向
PORTRAIT = 1, // 竖屏
LANDSCAPE = 2, // 横屏
PORTRAIT_INVERTED = 3, // 反向竖屏
LANDSCAPE_INVERTED = 4, // 反向横屏
AUTO_ROTATION = 5, // 自动旋转(跟随传感器)
AUTO_ROTATION_PORTRAIT = 6, // 自动旋转(仅竖屏)
AUTO_ROTATION_LANDSCAPE = 7, // 自动旋转(仅横屏)
AUTO_ROTATION_RESTRICTED = 8, // 受限自动旋转
AUTO_ROTATION_PORTRAIT_RESTRICTED = 9, // 受限自动旋转(仅竖屏)
AUTO_ROTATION_LANDSCAPE_RESTRICTED = 10 // 受限自动旋转(仅横屏)
}
2.3 原生 ArkTS 实现示例
在纯鸿蒙应用中,屏幕方向控制的典型实现如下:
import window from '@ohos.window';
import { BusinessError } from '@kit.BasicServicesKit';
// 获取窗口实例
let windowClass: window.Window = window.getLastWindow(context);
// 设置为横屏模式
let orientation = window.Orientation.LANDSCAPE;
try {
windowClass.setPreferredOrientation(orientation, (err: BusinessError) => {
if (err.code) {
console.error('Failed to set window orientation. Cause: ' + JSON.stringify(err));
return;
}
console.info('Succeeded in setting window orientation.');
});
} catch (exception) {
console.error('Failed to set window orientation. Cause: ' + JSON.stringify(exception));
}
2.4 原生实现的关键点
- 窗口实例获取:必须先获取有效的 window 实例才能进行方向设置
- 异步回调处理:setPreferredOrientation 采用异步回调模式,需要正确处理成功和失败情况
- 异常捕获:需要使用 try-catch 捕获可能的运行时异常
- 错误码处理:回调函数中的 err.code 需要被正确检查
三、UTS 封装实现详解
3.1 插件目录结构设计
一个规范的 UTS 插件应该具有清晰的目录结构,便于代码复用和跨平台扩展:
uni_modules/harmony-screen-orientation/
├── utssdk/
│ ├── interface.uts # 跨平台类型定义
│ ├── unierror.uts # 统一错误码定义
│ └── app-harmony/ # 鸿蒙平台实现
│ └── index.uts # 主要逻辑实现
├── package.json # 插件元数据
└── readme.md # 使用文档
3.2 类型系统设计(interface.uts)
良好的类型定义是 UTS 插件开发的基础。我们需要定义用户友好的接口类型:
import { ScreenOrientationErrorCode } from './unierror.uts'
/**
* 屏幕方向类型
* 使用简单的字符串字面量类型,降低用户使用门槛
*/
export type ScreenOrientationType = 'portrait' | 'landscape' | 'auto' | 'portrait-reverse' | 'landscape-reverse'
/**
* 设置屏幕方向参数定义
* 遵循 uni-app 统一的 API 风格
*/
export type SetScreenOrientationOptions = {
orientation: ScreenOrientationType
success?: SetScreenOrientationSuccessCallback | null
fail?: ScreenOrientationFailCallback | null
complete?: ScreenOrientationCompleteCallback | null
}
/**
* 获取屏幕方向参数定义
*/
export type GetScreenOrientationOptions = {
success?: GetScreenOrientationSuccessCallback | null
fail?: ScreenOrientationFailCallback | null
complete?: ScreenOrientationCompleteCallback | null
}
设计要点:
- 简化类型名称:使用
'portrait'、'landscape'等简单字符串,而非暴露鸿蒙原生的window.Orientation枚举 - 统一回调风格:采用
success、fail、complete三段式回调,与 uni-app 生态保持一致 - 可选参数设计:所有回调函数都是可选的,增强使用灵活性
3.3 错误码体系设计(unierror.uts)
完善的错误处理机制能够帮助开发者快速定位问题:
import { IScreenOrientationError } from './interface.uts'
/**
* 错误码定义
* 13xxx 段作为屏幕方向相关错误
*/
export type ScreenOrientationErrorCode =
13001 | // 系统不支持
13002 | // 无效的屏幕方向参数
13003 | // 设置屏幕方向失败
13004 // 获取窗口对象失败
/**
* 错误主题
*/
export const UniErrorSubject = 'uni-screen-orientation'
/**
* 错误信息映射表
*/
export const ScreenOrientationErrorMessages: Map<ScreenOrientationErrorCode, string> = new Map([
[13001, '系统不支持'],
[13002, '无效的屏幕方向参数'],
[13003, '设置屏幕方向失败'],
[13004, '获取窗口对象失败']
])
/**
* 错误实现类
*/
export class ScreenOrientationErrorImpl extends UniError implements IScreenOrientationError {
override errCode: ScreenOrientationErrorCode
constructor(errCode: ScreenOrientationErrorCode) {
super()
this.errSubject = UniErrorSubject
this.errCode = errCode
this.errMsg = ScreenOrientationErrorMessages.get(errCode) ?? ''
}
}
设计要点:
- 错误码分段管理:使用 13xxx 段,避免与其他插件冲突
- 错误信息集中管理:通过 Map 结构统一维护错误信息
- 继承 UniError 基类:保持与 uni-app 错误体系的兼容性
3.4 核心逻辑实现(app-harmony/index.uts)
3.4.1 类型映射机制
UTS 封装的核心是建立用户友好类型与原生类型之间的映射关系:
import window from '@ohos.window'
/**
* 屏幕方向映射表:用户类型 → 原生类型
* 将简单的字符串映射到鸿蒙的 window.Orientation 枚举
*/
const OrientationMap: Map<ScreenOrientationType, window.Orientation> = new Map([
['portrait', window.Orientation.PORTRAIT],
['landscape', window.Orientation.LANDSCAPE],
['auto', window.Orientation.AUTO_ROTATION],
['portrait-reverse', window.Orientation.PORTRAIT_INVERTED],
['landscape-reverse', window.Orientation.LANDSCAPE_INVERTED]
])
/**
* 反向映射表:原生类型 → 用户类型
* 用于将鸿蒙返回的枚举值转换为用户友好的字符串
*/
const ReverseOrientationMap: Map<window.Orientation, ScreenOrientationType> = new Map([
[window.Orientation.PORTRAIT, 'portrait'],
[window.Orientation.LANDSCAPE, 'landscape'],
[window.Orientation.AUTO_ROTATION, 'auto'],
[window.Orientation.PORTRAIT_INVERTED, 'portrait-reverse'],
[window.Orientation.LANDSCAPE_INVERTED, 'landscape-reverse']
])
3.4.2 setScreenOrientation 实现
export const setScreenOrientation: SetScreenOrientation = function (options: SetScreenOrientationOptions) {
// 第一步:参数验证
const orientation = OrientationMap.get(options.orientation)
if (orientation == null) {
const err = new ScreenOrientationErrorImpl(13002)
options.fail?.(err)
options.complete?.(err)
return
}
try {
// 第二步:获取窗口实例
// UTSHarmony.getCurrentWindow() 是 UTS 提供的全局 API
const windowInstance = UTSHarmony.getCurrentWindow()
if (windowInstance == null) {
const err = new ScreenOrientationErrorImpl(13004)
options.fail?.(err)
options.complete?.(err)
return
}
// 第三步:调用原生 API 设置方向
windowInstance.setPreferredOrientation(orientation, (err) => {
if (err != null && err.code != 0) {
// 设置失败
const error = new ScreenOrientationErrorImpl(13003)
options.fail?.(error)
options.complete?.(error)
return
}
// 设置成功
const res: SetScreenOrientationSuccess = {
errMsg: 'setScreenOrientation:ok'
}
options.success?.(res)
options.complete?.(res)
})
} catch (e) {
// 捕获异常
const err = new ScreenOrientationErrorImpl(13003)
options.fail?.(err)
options.complete?.(err)
}
}
实现要点分析:
- 参数验证前置:在调用原生 API 之前先验证参数合法性,快速失败
- 使用 UTSHarmony 全局 API:
UTSHarmony.getCurrentWindow()是 UTS 框架提供的便捷方法,简化了窗口实例获取 - 完整的错误处理:覆盖参数错误、窗口获取失败、设置失败和异常捕获四种情况
- 回调时机准确:success 和 fail 互斥,complete 总是执行
3.4.3 getScreenOrientation 实现
export const getScreenOrientation: GetScreenOrientation = function (options?: GetScreenOrientationOptions | null) {
try {
// 第一步:获取窗口实例
const windowInstance = UTSHarmony.getCurrentWindow()
if (windowInstance == null) {
const err = new ScreenOrientationErrorImpl(13004)
options?.fail?.(err)
options?.complete?.(err)
return
}
// 第二步:获取当前方向
const currentOrientation = windowInstance.getPreferredOrientation()
// 第三步:类型转换
const orientationType = ReverseOrientationMap.get(currentOrientation) ?? 'portrait'
// 第四步:返回结果
const res: GetScreenOrientationSuccess = {
orientation: orientationType,
errMsg: 'getScreenOrientation:ok'
}
options?.success?.(res)
options?.complete?.(res)
} catch (e) {
const err = new ScreenOrientationErrorImpl(13003)
options?.fail?.(err)
options?.complete?.(err)
}
}
实现要点分析:
- 可选参数处理:使用可选链操作符
?.处理可能为空的 options 参数 - 反向映射应用:使用 ReverseOrientationMap 将原生枚举转换为用户友好的字符串
- 默认值保护:使用空值合并运算符
??提供默认值,防止未知枚举导致的问题
3.5 UTS 全局 API 的应用
在本插件中,我们使用了 UTS 框架提供的 UTSHarmony.getCurrentWindow() 全局 API。这个 API 封装了获取当前窗口实例的复杂逻辑,开发者无需关心 context 的获取和管理。
相比原生 ArkTS 实现,UTS 方式的优势:
// 原生 ArkTS 方式(需要 context)
let context = getContext(this) as common.UIAbilityContext;
let windowClass = window.getLastWindow(context);
// UTS 方式(无需 context)
const windowInstance = UTSHarmony.getCurrentWindow()
四、用户使用说明
4.1 插件安装
将插件复制到项目的 uni_modules 目录下:
your-project/
└── uni_modules/
└── harmony-screen-orientation/
4.2 基础使用示例
4.2.1 设置为横屏模式
<template>
<view class="container">
<button @click="setLandscape">切换到横屏</button>
</view>
</template>
<script setup lang="ts">
import { setScreenOrientation } from "@/uni_modules/harmony-screen-orientation"
const setLandscape = () => {
setScreenOrientation({
orientation: 'landscape',
success: (res) => {
console.log('横屏设置成功', res)
uni.showToast({
title: '已切换到横屏',
icon: 'success'
})
},
fail: (err) => {
console.error('横屏设置失败', err)
uni.showToast({
title: `设置失败: ${err.errMsg}`,
icon: 'none'
})
}
})
}
</script>
4.2.2 设置为自动旋转
import { setScreenOrientation } from "@/uni_modules/harmony-screen-orientation"
// 启用自动旋转(需要系统设置中开启自动旋转)
setScreenOrientation({
orientation: 'auto',
success: () => {
console.log('自动旋转已启用')
}
})
4.2.3 获取当前屏幕方向
<template>
<view class="container">
<text>当前方向: {{ currentOrientation }}</text>
<button @click="checkOrientation">检查方向</button>
</view>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { getScreenOrientation } from "@/uni_modules/harmony-screen-orientation"
const currentOrientation = ref<string>('未知')
const checkOrientation = () => {
getScreenOrientation({
success: (res) => {
currentOrientation.value = res.orientation
console.log('当前屏幕方向:', res.orientation)
}
})
}
</script>
错误处理最佳实践
import { setScreenOrientation } from "@/uni_modules/harmony-screen-orientation"
import type { IScreenOrientationError } from "@/uni_modules/harmony-screen-orientation"
const handleOrientationChange = (orientation: string) => {
setScreenOrientation({
orientation: orientation as any,
success: (res) => {
console.log('方向切换成功:', res)
},
fail: (err: IScreenOrientationError) => {
// 根据错误码进行不同处理
switch (err.errCode) {
case 13002:
console.error('参数错误,请检查 orientation 值')
break
case 13003:
console.error('设置失败,可能是系统限制')
break
case 13004:
console.error('无法获取窗口,请稍后重试')
break
default:
console.error('未知错误:', err.errMsg)
}
},
complete: () => {
console.log('操作完成')
}
})
}
TypeScript 类型支持
插件提供完整的 TypeScript 类型定义,享受类型提示和类型检查:
import {
setScreenOrientation,
getScreenOrientation,
type SetScreenOrientationOptions,
type GetScreenOrientationOptions,
type ScreenOrientationType
} from "@/uni_modules/harmony-screen-orientation"
// 类型安全的参数定义
const options: SetScreenOrientationOptions = {
orientation: 'landscape', // 类型提示可用值
success: (res) => {
// res 参数类型自动推导
console.log(res.errMsg)
}
}
setScreenOrientation(options)
学习资源
关注我
如果本文对你有帮助,欢迎点赞
一、插件开发背景
在移动应用开发中,屏幕方向控制是一个常见且重要的功能需求
本文将详细介绍如何开发一个完整的鸿蒙屏幕方向控制 UTS 插件,包括原生 API 的使用、UTS 封装的实现细节以及最佳实践。
二、鸿蒙原生实现分析
2.1 鸿蒙屏幕方向 API 概述
鸿蒙系统提供了完善的窗口管理能力,屏幕方向控制主要通过 @ohos.window 模块实现。核心 API 包括:
- window.Orientation 枚举:定义了所有可用的屏幕方向
- setPreferredOrientation() 方法:设置窗口的首选显示方向
- getPreferredOrientation() 方法:获取当前窗口的显示方向
2.2 window.Orientation 枚举值详解
enum Orientation {
UNSPECIFIED = 0, // 未指定方向
PORTRAIT = 1, // 竖屏
LANDSCAPE = 2, // 横屏
PORTRAIT_INVERTED = 3, // 反向竖屏
LANDSCAPE_INVERTED = 4, // 反向横屏
AUTO_ROTATION = 5, // 自动旋转(跟随传感器)
AUTO_ROTATION_PORTRAIT = 6, // 自动旋转(仅竖屏)
AUTO_ROTATION_LANDSCAPE = 7, // 自动旋转(仅横屏)
AUTO_ROTATION_RESTRICTED = 8, // 受限自动旋转
AUTO_ROTATION_PORTRAIT_RESTRICTED = 9, // 受限自动旋转(仅竖屏)
AUTO_ROTATION_LANDSCAPE_RESTRICTED = 10 // 受限自动旋转(仅横屏)
}
2.3 原生 ArkTS 实现示例
在纯鸿蒙应用中,屏幕方向控制的典型实现如下:
import window from '@ohos.window';
import { BusinessError } from '@kit.BasicServicesKit';
// 获取窗口实例
let windowClass: window.Window = window.getLastWindow(context);
// 设置为横屏模式
let orientation = window.Orientation.LANDSCAPE;
try {
windowClass.setPreferredOrientation(orientation, (err: BusinessError) => {
if (err.code) {
console.error('Failed to set window orientation. Cause: ' + JSON.stringify(err));
return;
}
console.info('Succeeded in setting window orientation.');
});
} catch (exception) {
console.error('Failed to set window orientation. Cause: ' + JSON.stringify(exception));
}
2.4 原生实现的关键点
- 窗口实例获取:必须先获取有效的 window 实例才能进行方向设置
- 异步回调处理:setPreferredOrientation 采用异步回调模式,需要正确处理成功和失败情况
- 异常捕获:需要使用 try-catch 捕获可能的运行时异常
- 错误码处理:回调函数中的 err.code 需要被正确检查
三、UTS 封装实现详解
3.1 插件目录结构设计
一个规范的 UTS 插件应该具有清晰的目录结构,便于代码复用和跨平台扩展:
uni_modules/harmony-screen-orientation/
├── utssdk/
│ ├── interface.uts # 跨平台类型定义
│ ├── unierror.uts # 统一错误码定义
│ └── app-harmony/ # 鸿蒙平台实现
│ └── index.uts # 主要逻辑实现
├── package.json # 插件元数据
└── readme.md # 使用文档
3.2 类型系统设计(interface.uts)
良好的类型定义是 UTS 插件开发的基础。我们需要定义用户友好的接口类型:
import { ScreenOrientationErrorCode } from './unierror.uts'
/**
* 屏幕方向类型
* 使用简单的字符串字面量类型,降低用户使用门槛
*/
export type ScreenOrientationType = 'portrait' | 'landscape' | 'auto' | 'portrait-reverse' | 'landscape-reverse'
/**
* 设置屏幕方向参数定义
* 遵循 uni-app 统一的 API 风格
*/
export type SetScreenOrientationOptions = {
orientation: ScreenOrientationType
success?: SetScreenOrientationSuccessCallback | null
fail?: ScreenOrientationFailCallback | null
complete?: ScreenOrientationCompleteCallback | null
}
/**
* 获取屏幕方向参数定义
*/
export type GetScreenOrientationOptions = {
success?: GetScreenOrientationSuccessCallback | null
fail?: ScreenOrientationFailCallback | null
complete?: ScreenOrientationCompleteCallback | null
}
设计要点:
- 简化类型名称:使用
'portrait'、'landscape'等简单字符串,而非暴露鸿蒙原生的window.Orientation枚举 - 统一回调风格:采用
success、fail、complete三段式回调,与 uni-app 生态保持一致 - 可选参数设计:所有回调函数都是可选的,增强使用灵活性
3.3 错误码体系设计(unierror.uts)
完善的错误处理机制能够帮助开发者快速定位问题:
import { IScreenOrientationError } from './interface.uts'
/**
* 错误码定义
* 13xxx 段作为屏幕方向相关错误
*/
export type ScreenOrientationErrorCode =
13001 | // 系统不支持
13002 | // 无效的屏幕方向参数
13003 | // 设置屏幕方向失败
13004 // 获取窗口对象失败
/**
* 错误主题
*/
export const UniErrorSubject = 'uni-screen-orientation'
/**
* 错误信息映射表
*/
export const ScreenOrientationErrorMessages: Map<ScreenOrientationErrorCode, string> = new Map([
[13001, '系统不支持'],
[13002, '无效的屏幕方向参数'],
[13003, '设置屏幕方向失败'],
[13004, '获取窗口对象失败']
])
/**
* 错误实现类
*/
export class ScreenOrientationErrorImpl extends UniError implements IScreenOrientationError {
override errCode: ScreenOrientationErrorCode
constructor(errCode: ScreenOrientationErrorCode) {
super()
this.errSubject = UniErrorSubject
this.errCode = errCode
this.errMsg = ScreenOrientationErrorMessages.get(errCode) ?? ''
}
}
设计要点:
- 错误码分段管理:使用 13xxx 段,避免与其他插件冲突
- 错误信息集中管理:通过 Map 结构统一维护错误信息
- 继承 UniError 基类:保持与 uni-app 错误体系的兼容性
3.4 核心逻辑实现(app-harmony/index.uts)
3.4.1 类型映射机制
UTS 封装的核心是建立用户友好类型与原生类型之间的映射关系:
import window from '@ohos.window'
/**
* 屏幕方向映射表:用户类型 → 原生类型
* 将简单的字符串映射到鸿蒙的 window.Orientation 枚举
*/
const OrientationMap: Map<ScreenOrientationType, window.Orientation> = new Map([
['portrait', window.Orientation.PORTRAIT],
['landscape', window.Orientation.LANDSCAPE],
['auto', window.Orientation.AUTO_ROTATION],
['portrait-reverse', window.Orientation.PORTRAIT_INVERTED],
['landscape-reverse', window.Orientation.LANDSCAPE_INVERTED]
])
/**
* 反向映射表:原生类型 → 用户类型
* 用于将鸿蒙返回的枚举值转换为用户友好的字符串
*/
const ReverseOrientationMap: Map<window.Orientation, ScreenOrientationType> = new Map([
[window.Orientation.PORTRAIT, 'portrait'],
[window.Orientation.LANDSCAPE, 'landscape'],
[window.Orientation.AUTO_ROTATION, 'auto'],
[window.Orientation.PORTRAIT_INVERTED, 'portrait-reverse'],
[window.Orientation.LANDSCAPE_INVERTED, 'landscape-reverse']
])
3.4.2 setScreenOrientation 实现
export const setScreenOrientation: SetScreenOrientation = function (options: SetScreenOrientationOptions) {
// 第一步:参数验证
const orientation = OrientationMap.get(options.orientation)
if (orientation == null) {
const err = new ScreenOrientationErrorImpl(13002)
options.fail?.(err)
options.complete?.(err)
return
}
try {
// 第二步:获取窗口实例
// UTSHarmony.getCurrentWindow() 是 UTS 提供的全局 API
const windowInstance = UTSHarmony.getCurrentWindow()
if (windowInstance == null) {
const err = new ScreenOrientationErrorImpl(13004)
options.fail?.(err)
options.complete?.(err)
return
}
// 第三步:调用原生 API 设置方向
windowInstance.setPreferredOrientation(orientation, (err) => {
if (err != null && err.code != 0) {
// 设置失败
const error = new ScreenOrientationErrorImpl(13003)
options.fail?.(error)
options.complete?.(error)
return
}
// 设置成功
const res: SetScreenOrientationSuccess = {
errMsg: 'setScreenOrientation:ok'
}
options.success?.(res)
options.complete?.(res)
})
} catch (e) {
// 捕获异常
const err = new ScreenOrientationErrorImpl(13003)
options.fail?.(err)
options.complete?.(err)
}
}
实现要点分析:
- 参数验证前置:在调用原生 API 之前先验证参数合法性,快速失败
- 使用 UTSHarmony 全局 API:
UTSHarmony.getCurrentWindow()是 UTS 框架提供的便捷方法,简化了窗口实例获取 - 完整的错误处理:覆盖参数错误、窗口获取失败、设置失败和异常捕获四种情况
- 回调时机准确:success 和 fail 互斥,complete 总是执行
3.4.3 getScreenOrientation 实现
export const getScreenOrientation: GetScreenOrientation = function (options?: GetScreenOrientationOptions | null) {
try {
// 第一步:获取窗口实例
const windowInstance = UTSHarmony.getCurrentWindow()
if (windowInstance == null) {
const err = new ScreenOrientationErrorImpl(13004)
options?.fail?.(err)
options?.complete?.(err)
return
}
// 第二步:获取当前方向
const currentOrientation = windowInstance.getPreferredOrientation()
// 第三步:类型转换
const orientationType = ReverseOrientationMap.get(currentOrientation) ?? 'portrait'
// 第四步:返回结果
const res: GetScreenOrientationSuccess = {
orientation: orientationType,
errMsg: 'getScreenOrientation:ok'
}
options?.success?.(res)
options?.complete?.(res)
} catch (e) {
const err = new ScreenOrientationErrorImpl(13003)
options?.fail?.(err)
options?.complete?.(err)
}
}
实现要点分析:
- 可选参数处理:使用可选链操作符
?.处理可能为空的 options 参数 - 反向映射应用:使用 ReverseOrientationMap 将原生枚举转换为用户友好的字符串
- 默认值保护:使用空值合并运算符
??提供默认值,防止未知枚举导致的问题
3.5 UTS 全局 API 的应用
在本插件中,我们使用了 UTS 框架提供的 UTSHarmony.getCurrentWindow() 全局 API。这个 API 封装了获取当前窗口实例的复杂逻辑,开发者无需关心 context 的获取和管理。
相比原生 ArkTS 实现,UTS 方式的优势:
// 原生 ArkTS 方式(需要 context)
let context = getContext(this) as common.UIAbilityContext;
let windowClass = window.getLastWindow(context);
// UTS 方式(无需 context)
const windowInstance = UTSHarmony.getCurrentWindow()
四、用户使用说明
4.1 插件安装
将插件复制到项目的 uni_modules 目录下:
your-project/
└── uni_modules/
└── harmony-screen-orientation/
4.2 基础使用示例
4.2.1 设置为横屏模式
<template>
<view class="container">
<button @click="setLandscape">切换到横屏</button>
</view>
</template>
<script setup lang="ts">
import { setScreenOrientation } from "@/uni_modules/harmony-screen-orientation"
const setLandscape = () => {
setScreenOrientation({
orientation: 'landscape',
success: (res) => {
console.log('横屏设置成功', res)
uni.showToast({
title: '已切换到横屏',
icon: 'success'
})
},
fail: (err) => {
console.error('横屏设置失败', err)
uni.showToast({
title: `设置失败: ${err.errMsg}`,
icon: 'none'
})
}
})
}
</script>
4.2.2 设置为自动旋转
import { setScreenOrientation } from "@/uni_modules/harmony-screen-orientation"
// 启用自动旋转(需要系统设置中开启自动旋转)
setScreenOrientation({
orientation: 'auto',
success: () => {
console.log('自动旋转已启用')
}
})
4.2.3 获取当前屏幕方向
<template>
<view class="container">
<text>当前方向: {{ currentOrientation }}</text>
<button @click="checkOrientation">检查方向</button>
</view>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { getScreenOrientation } from "@/uni_modules/harmony-screen-orientation"
const currentOrientation = ref<string>('未知')
const checkOrientation = () => {
getScreenOrientation({
success: (res) => {
currentOrientation.value = res.orientation
console.log('当前屏幕方向:', res.orientation)
}
})
}
</script>
错误处理最佳实践
import { setScreenOrientation } from "@/uni_modules/harmony-screen-orientation"
import type { IScreenOrientationError } from "@/uni_modules/harmony-screen-orientation"
const handleOrientationChange = (orientation: string) => {
setScreenOrientation({
orientation: orientation as any,
success: (res) => {
console.log('方向切换成功:', res)
},
fail: (err: IScreenOrientationError) => {
// 根据错误码进行不同处理
switch (err.errCode) {
case 13002:
console.error('参数错误,请检查 orientation 值')
break
case 13003:
console.error('设置失败,可能是系统限制')
break
case 13004:
console.error('无法获取窗口,请稍后重试')
break
default:
console.error('未知错误:', err.errMsg)
}
},
complete: () => {
console.log('操作完成')
}
})
}
TypeScript 类型支持
插件提供完整的 TypeScript 类型定义,享受类型提示和类型检查:
import {
setScreenOrientation,
getScreenOrientation,
type SetScreenOrientationOptions,
type GetScreenOrientationOptions,
type ScreenOrientationType
} from "@/uni_modules/harmony-screen-orientation"
// 类型安全的参数定义
const options: SetScreenOrientationOptions = {
orientation: 'landscape', // 类型提示可用值
success: (res) => {
// res 参数类型自动推导
console.log(res.errMsg)
}
}
setScreenOrientation(options)
学习资源
关注我
如果本文对你有帮助,欢迎点赞
收起阅读 »【鸿蒙征文】uni-app 鸿蒙闪光灯插件开发:从原生 API 到 UTS 封装
开发背景
在移动应用开发中,闪光灯(手电筒)是一个常见且实用的功能。随着 HarmonyOS Next 的推出,越来越多的开发者开始将应用迁移到鸿蒙平台。我们开发了 harmony-flashlight 插件。该插件基于 UTS 封装鸿蒙原生 Camera Kit API,为 uni-app 开发者提供了一套简洁易用的闪光灯控制接口。插件完全遵循 uni-app 的 API 设计规范,支持 success/fail/complete 回调模式,让开发者能够以熟悉的方式在鸿蒙平台上实现手电筒功能。
这个过程非常适合学习和了解如何开发鸿蒙 uts 插件,特地编写此文用于展示整个过程。
鸿蒙原生实现
HarmonyOS Next 通过 Camera Kit 提供了完整的相机功能支持,其中包括闪光灯(Torch)控制能力。要在鸿蒙平台实现闪光灯控制,需要理解以下核心概念和 API:
Camera Manager
Camera Manager 是鸿蒙相机功能的核心管理器,负责相机设备的枚举、创建和配置。获取 Camera Manager 实例是使用相机相关功能的前提:
camera.getCameraManager(context) 方法用于获取相机管理器实例,需要传入 UIAbility 的 Context 上下文对象。该实例在整个应用生命周期中应该被复用,避免重复创建造成资源浪费。
Torch Mode 控制
鸿蒙系统定义了 camera.TorchMode 枚举,包含两种模式:
TorchMode.ON:开启闪光灯(手电筒模式)TorchMode.OFF:关闭闪光灯
在实际使用前,必须进行两项检查:
- 通过
isTorchSupported()方法检查设备是否支持手电筒功能。部分低端设备或特殊硬件可能不具备闪光灯,此方法可避免在不支持的设备上调用相关 API 导致异常。 - 通过
isTorchModeSupported(mode)方法检查指定的 Torch Mode 是否被支持。虽然大多数设备同时支持 ON 和 OFF 两种模式,但规范的做法是在使用前进行验证。 - 通过
setTorchMode(mode)方法设置闪光灯模式。该方法会立即生效,改变设备闪光灯的状态。
权限配置
闪光灯控制依赖于相机权限。在 module.json5 配置文件中,必须声明 ohos.permission.CAMERA 权限。
错误处理
鸿蒙原生 API 在发生错误时会抛出 BusinessError 异常,主要错误码包括:
7400102:操作不被允许(如权限未授予、设备被占用)7400201:相机服务内部错误(如服务异常、硬件故障)
规范的错误处理需要捕获异常并根据错误码进行相应的提示和处理。
UTS 封装实现
UTS 是 uni-app 推出的面向跨平台原生开发的类型化语言。它允许开发者使用接近 TypeScript 的语法调用各平台的原生 API,同时保持类型安全。本插件的 UTS 封装主要包含三个核心文件:
类型定义层(interface.uts)
类型定义层定义了插件对外暴露的所有类型和接口,确保 API 调用的类型安全性。
主要定义包括:
FlashlightSuccess类型定义成功回调的返回结构,包含errMsg字符串字段TurnOnFlashlightOptions和TurnOffFlashlightOptions类型定义了可选的配置参数,包括success、fail和complete三个回调函数- 回调函数类型采用函数签名定义,如
FlashlightSuccessCallback = (res: FlashlightSuccess) => void TurnOnFlashlight和TurnOffFlashlight函数类型定义了接口的调用签名
这种类型定义方式完全符合 uni-app 的 API 设计规范,与 uni-app 内置 API 保持一致的调用体验。
错误处理层(unierror.uts)
错误处理层通过继承 UniError 基类,实现了标准化的错误对象。
FlashlightErrorCode 类型使用 TypeScript 联合类型定义了四个错误码:
13001:设备不支持闪光灯(硬件能力限制)13002:操作不允许(权限问题或设备占用)13003:相机服务错误(系统服务异常)13004:未知错误(兜底错误码)
FlashlightFailImpl 类的构造函数接收错误码,通过 switch 语句映射到对应的错误消息。所有错误对象的 errSubject 统一设置为 'harmony-flashlight',便于开发者定位错误来源。
这种错误处理机制实现了鸿蒙原生错误码到 uni-app 错误规范的转换,屏蔽了平台差异,让开发者能够以统一的方式处理错误。
核心实现层(index.uts)
核心实现层是插件的主体逻辑,负责调用鸿蒙原生 API 并处理业务流程。
使用模块级变量 cameraManager 存储相机管理器实例,通过 getCameraManager() 函数实现懒加载和复用。首次调用时,通过 camera.getCameraManager(UTSHarmony.getUIAbilityContext()) 创建实例,后续调用直接返回缓存实例。这种设计避免了重复创建管理器的开销,提升了性能。
turnOnFlashlight 和 turnOffFlashlight 函数均采用多层检测机制:
第一层检测:确认 Camera Manager 是否成功获取。如果获取失败,返回 13003(相机服务错误)。
第二层检测:调用 isTorchSupported() 检查设备硬件是否支持手电筒。不支持时返回 13001(设备不支持闪光灯)。
第三层检测:调用 isTorchModeSupported(mode) 检查目标模式是否被支持。虽然极少出现部分模式不支持的情况,但这一检测确保了代码的健壮性。
通过检测后,才调用 setTorchMode(mode) 执行实际操作。
使用 try-catch 捕获所有可能的异常。捕获到的异常被转换为 BusinessError 类型,通过检查 error.code 属性进行错误码映射:
- 鸿蒙原生码
7400102映射为插件码13002 - 鸿蒙原生码
7400201映射为插件码13003 - 其他未知错误统一映射为
13004
这种映射机制实现了平台错误到业务错误的转换,为开发者提供了更友好的错误信息。
标准的回调执行模式
操作成功时,构造 FlashlightSuccess 对象,依次执行 success 和 complete 回调。操作失败时,构造 FlashlightFailImpl 对象,依次执行 fail 和 complete 回调。所有回调执行前都会进行空值检查(options?.success?.(res)),确保代码的安全性。
这种回调模式完全遵循 uni-app 的异步 API 规范,让开发者能够以统一的方式处理成功和失败情况。
使用说明
安装配置
将 harmony-flashlight 插件文件夹复制到项目的 uni_modules 目录下。插件采用 uni_modules 规范,HBuilderX 会自动识别并完成依赖安装。
基础用法
在 Vue 组件中导入所需的函数:
import { turnOnFlashlight, turnOffFlashlight } from "@/uni_modules/harmony-flashlight"
打开闪光灯示例:
turnOnFlashlight({
success: (res) => {
console.log('打开成功', res.errMsg)
uni.showToast({ title: '手电筒已打开', icon: 'success' })
},
fail: (err) => {
console.error('打开失败', err.errCode, err.errMsg)
uni.showToast({ title: err.errMsg, icon: 'none' })
},
complete: () => {
console.log('操作完成')
}
})
关闭闪光灯示例:
turnOffFlashlight({
success: (res) => {
console.log('关闭成功', res.errMsg)
uni.showToast({ title: '手电筒已关闭', icon: 'success' })
},
fail: (err) => {
console.error('关闭失败', err.errCode, err.errMsg)
uni.showToast({ title: err.errMsg, icon: 'none' })
}
})
完整应用示例
以下是一个完整的手电筒开关组件实现:
<script setup lang="ts">
import { turnOnFlashlight, turnOffFlashlight } from "@/uni_modules/harmony-flashlight"
import { ref } from 'vue'
const isFlashlightOn = ref(false)
const toggleFlashlight = () => {
if (isFlashlightOn.value) {
turnOffFlashlight({
success: () => {
isFlashlightOn.value = false
uni.showToast({ title: '手电筒已关闭', icon: 'success' })
},
fail: (err) => {
uni.showToast({ title: err.errMsg, icon: 'none' })
}
})
} else {
turnOnFlashlight({
success: () => {
isFlashlightOn.value = true
uni.showToast({ title: '手电筒已打开', icon: 'success' })
},
fail: (err) => {
uni.showToast({ title: err.errMsg, icon: 'none' })
}
})
}
}
</script>
<template>
<view class="container">
<button @click="toggleFlashlight" class="flashlight-btn">
{{ isFlashlightOn ? '关闭手电筒' : '打开手电筒' }}
</button>
</view>
</template>
错误处理建议
在生产环境中,建议根据错误码进行差异化处理:
turnOnFlashlight({
fail: (err) => {
if (err.errCode === 13001) {
uni.showModal({
title: '提示',
content: '您的设备不支持闪光灯功能',
showCancel: false
})
} else if (err.errCode === 13002) {
uni.showModal({
title: '权限提示',
content: '需要相机权限才能使用闪光灯,请在系统设置中授权',
confirmText: '去设置',
success: (res) => {
if (res.confirm) {
// 跳转到系统设置页面
}
}
})
} else {
uni.showToast({ title: '操作失败:' + err.errMsg, icon: 'none' })
}
}
})
注意事项
-
权限处理:首次使用时,系统会弹出相机权限授权对话框,用户拒绝授权会导致功能无法使用。建议在适当时机向用户说明权限用途。
-
生命周期管理:应用切换到后台或退出时,闪光灯会自动关闭。如需保持闪光灯状态,建议在
onShow生命周期中恢复。
如果有问题可留言评论。
开发背景
在移动应用开发中,闪光灯(手电筒)是一个常见且实用的功能。随着 HarmonyOS Next 的推出,越来越多的开发者开始将应用迁移到鸿蒙平台。我们开发了 harmony-flashlight 插件。该插件基于 UTS 封装鸿蒙原生 Camera Kit API,为 uni-app 开发者提供了一套简洁易用的闪光灯控制接口。插件完全遵循 uni-app 的 API 设计规范,支持 success/fail/complete 回调模式,让开发者能够以熟悉的方式在鸿蒙平台上实现手电筒功能。
这个过程非常适合学习和了解如何开发鸿蒙 uts 插件,特地编写此文用于展示整个过程。
鸿蒙原生实现
HarmonyOS Next 通过 Camera Kit 提供了完整的相机功能支持,其中包括闪光灯(Torch)控制能力。要在鸿蒙平台实现闪光灯控制,需要理解以下核心概念和 API:
Camera Manager
Camera Manager 是鸿蒙相机功能的核心管理器,负责相机设备的枚举、创建和配置。获取 Camera Manager 实例是使用相机相关功能的前提:
camera.getCameraManager(context) 方法用于获取相机管理器实例,需要传入 UIAbility 的 Context 上下文对象。该实例在整个应用生命周期中应该被复用,避免重复创建造成资源浪费。
Torch Mode 控制
鸿蒙系统定义了 camera.TorchMode 枚举,包含两种模式:
TorchMode.ON:开启闪光灯(手电筒模式)TorchMode.OFF:关闭闪光灯
在实际使用前,必须进行两项检查:
- 通过
isTorchSupported()方法检查设备是否支持手电筒功能。部分低端设备或特殊硬件可能不具备闪光灯,此方法可避免在不支持的设备上调用相关 API 导致异常。 - 通过
isTorchModeSupported(mode)方法检查指定的 Torch Mode 是否被支持。虽然大多数设备同时支持 ON 和 OFF 两种模式,但规范的做法是在使用前进行验证。 - 通过
setTorchMode(mode)方法设置闪光灯模式。该方法会立即生效,改变设备闪光灯的状态。
权限配置
闪光灯控制依赖于相机权限。在 module.json5 配置文件中,必须声明 ohos.permission.CAMERA 权限。
错误处理
鸿蒙原生 API 在发生错误时会抛出 BusinessError 异常,主要错误码包括:
7400102:操作不被允许(如权限未授予、设备被占用)7400201:相机服务内部错误(如服务异常、硬件故障)
规范的错误处理需要捕获异常并根据错误码进行相应的提示和处理。
UTS 封装实现
UTS 是 uni-app 推出的面向跨平台原生开发的类型化语言。它允许开发者使用接近 TypeScript 的语法调用各平台的原生 API,同时保持类型安全。本插件的 UTS 封装主要包含三个核心文件:
类型定义层(interface.uts)
类型定义层定义了插件对外暴露的所有类型和接口,确保 API 调用的类型安全性。
主要定义包括:
FlashlightSuccess类型定义成功回调的返回结构,包含errMsg字符串字段TurnOnFlashlightOptions和TurnOffFlashlightOptions类型定义了可选的配置参数,包括success、fail和complete三个回调函数- 回调函数类型采用函数签名定义,如
FlashlightSuccessCallback = (res: FlashlightSuccess) => void TurnOnFlashlight和TurnOffFlashlight函数类型定义了接口的调用签名
这种类型定义方式完全符合 uni-app 的 API 设计规范,与 uni-app 内置 API 保持一致的调用体验。
错误处理层(unierror.uts)
错误处理层通过继承 UniError 基类,实现了标准化的错误对象。
FlashlightErrorCode 类型使用 TypeScript 联合类型定义了四个错误码:
13001:设备不支持闪光灯(硬件能力限制)13002:操作不允许(权限问题或设备占用)13003:相机服务错误(系统服务异常)13004:未知错误(兜底错误码)
FlashlightFailImpl 类的构造函数接收错误码,通过 switch 语句映射到对应的错误消息。所有错误对象的 errSubject 统一设置为 'harmony-flashlight',便于开发者定位错误来源。
这种错误处理机制实现了鸿蒙原生错误码到 uni-app 错误规范的转换,屏蔽了平台差异,让开发者能够以统一的方式处理错误。
核心实现层(index.uts)
核心实现层是插件的主体逻辑,负责调用鸿蒙原生 API 并处理业务流程。
使用模块级变量 cameraManager 存储相机管理器实例,通过 getCameraManager() 函数实现懒加载和复用。首次调用时,通过 camera.getCameraManager(UTSHarmony.getUIAbilityContext()) 创建实例,后续调用直接返回缓存实例。这种设计避免了重复创建管理器的开销,提升了性能。
turnOnFlashlight 和 turnOffFlashlight 函数均采用多层检测机制:
第一层检测:确认 Camera Manager 是否成功获取。如果获取失败,返回 13003(相机服务错误)。
第二层检测:调用 isTorchSupported() 检查设备硬件是否支持手电筒。不支持时返回 13001(设备不支持闪光灯)。
第三层检测:调用 isTorchModeSupported(mode) 检查目标模式是否被支持。虽然极少出现部分模式不支持的情况,但这一检测确保了代码的健壮性。
通过检测后,才调用 setTorchMode(mode) 执行实际操作。
使用 try-catch 捕获所有可能的异常。捕获到的异常被转换为 BusinessError 类型,通过检查 error.code 属性进行错误码映射:
- 鸿蒙原生码
7400102映射为插件码13002 - 鸿蒙原生码
7400201映射为插件码13003 - 其他未知错误统一映射为
13004
这种映射机制实现了平台错误到业务错误的转换,为开发者提供了更友好的错误信息。
标准的回调执行模式
操作成功时,构造 FlashlightSuccess 对象,依次执行 success 和 complete 回调。操作失败时,构造 FlashlightFailImpl 对象,依次执行 fail 和 complete 回调。所有回调执行前都会进行空值检查(options?.success?.(res)),确保代码的安全性。
这种回调模式完全遵循 uni-app 的异步 API 规范,让开发者能够以统一的方式处理成功和失败情况。
使用说明
安装配置
将 harmony-flashlight 插件文件夹复制到项目的 uni_modules 目录下。插件采用 uni_modules 规范,HBuilderX 会自动识别并完成依赖安装。
基础用法
在 Vue 组件中导入所需的函数:
import { turnOnFlashlight, turnOffFlashlight } from "@/uni_modules/harmony-flashlight"
打开闪光灯示例:
turnOnFlashlight({
success: (res) => {
console.log('打开成功', res.errMsg)
uni.showToast({ title: '手电筒已打开', icon: 'success' })
},
fail: (err) => {
console.error('打开失败', err.errCode, err.errMsg)
uni.showToast({ title: err.errMsg, icon: 'none' })
},
complete: () => {
console.log('操作完成')
}
})
关闭闪光灯示例:
turnOffFlashlight({
success: (res) => {
console.log('关闭成功', res.errMsg)
uni.showToast({ title: '手电筒已关闭', icon: 'success' })
},
fail: (err) => {
console.error('关闭失败', err.errCode, err.errMsg)
uni.showToast({ title: err.errMsg, icon: 'none' })
}
})
完整应用示例
以下是一个完整的手电筒开关组件实现:
<script setup lang="ts">
import { turnOnFlashlight, turnOffFlashlight } from "@/uni_modules/harmony-flashlight"
import { ref } from 'vue'
const isFlashlightOn = ref(false)
const toggleFlashlight = () => {
if (isFlashlightOn.value) {
turnOffFlashlight({
success: () => {
isFlashlightOn.value = false
uni.showToast({ title: '手电筒已关闭', icon: 'success' })
},
fail: (err) => {
uni.showToast({ title: err.errMsg, icon: 'none' })
}
})
} else {
turnOnFlashlight({
success: () => {
isFlashlightOn.value = true
uni.showToast({ title: '手电筒已打开', icon: 'success' })
},
fail: (err) => {
uni.showToast({ title: err.errMsg, icon: 'none' })
}
})
}
}
</script>
<template>
<view class="container">
<button @click="toggleFlashlight" class="flashlight-btn">
{{ isFlashlightOn ? '关闭手电筒' : '打开手电筒' }}
</button>
</view>
</template>
错误处理建议
在生产环境中,建议根据错误码进行差异化处理:
turnOnFlashlight({
fail: (err) => {
if (err.errCode === 13001) {
uni.showModal({
title: '提示',
content: '您的设备不支持闪光灯功能',
showCancel: false
})
} else if (err.errCode === 13002) {
uni.showModal({
title: '权限提示',
content: '需要相机权限才能使用闪光灯,请在系统设置中授权',
confirmText: '去设置',
success: (res) => {
if (res.confirm) {
// 跳转到系统设置页面
}
}
})
} else {
uni.showToast({ title: '操作失败:' + err.errMsg, icon: 'none' })
}
}
})
注意事项
-
权限处理:首次使用时,系统会弹出相机权限授权对话框,用户拒绝授权会导致功能无法使用。建议在适当时机向用户说明权限用途。
-
生命周期管理:应用切换到后台或退出时,闪光灯会自动关闭。如需保持闪光灯状态,建议在
onShow生命周期中恢复。
如果有问题可留言评论。
收起阅读 »鸿图初展,蒙学破茧:与uniapp-x和tmui4.0共闯鸿蒙Next实战录
相识篇
2025年02月24日,这一天难忘。随着鸿蒙生态的蓬勃发展,我和小伙伴们也在不断学习、探索、交流中,得知了uniapp-x的官网:https://doc.dcloud.net.cn/uni-app-x地址, 这个网站里我读懂了2个很重要的信息。
其一:uni-app x,是下一代 uni-app,是一个跨平台应用开发引擎。uts在Android平台编译为kotlin、在iOS平台编译为swift、在鸿蒙next平台上编译为ArkTS、在Web和小程序平台编译为js。官方重心便宜至uniapp-x上科技的创新。
其二:在这个网页下面有个插件生态部分描述了:TMUI4.0:高品质UI库,插件大赛一等奖。
综合这两方面原因:我也深知原来无任何app开发经验的小白,必须需要借助uniapp-x和tmui4.0才有逆袭的机会。从此刻开始就暗自下定决心利用工作之外的时间冲刺鸿蒙Next的app开发。
后盾篇
利用工作日之外的时间,我还必须跟家庭表达我的真实想法要冲刺鸿蒙Next的app开发。跟他们沟通说:鸿蒙Next的app将来一定会越来越有前景和市场,尤其是在Ai时代背景下,做好鸿蒙Next的app开发,一定会有很大的发展。最终得到已怀孕老婆的支持,我也终于可以开始了。
学习过程
1. 笔记分享
2025年02月25日:
1.采购tmUI 4.0的Vip资料,并且官方给了一些资料。计划先学习下uniapp-x官方资料。
2.编译到微信时,
- 如果提示xanimations页面不存在,就改成下pages.json中的名称改成页面的xAnimationS
- 如果hbx编译成功后打不开微信工具,就自己手动打开工具,点导入项目,导入你根目录中的unpackage/dis/dev/mp-weixin
然后模拟器上方把热重载关闭下。 - 接着可能报echart.js,mqtt.js文件不存在。需要你手动复制到mp-weixin目录内,这个看我常文档:见问题页面。就是复制到对应目录结构内。
解释下原因:
第1点,是我复制的时候,是复制老的页面,名称忘记改了。
第2点,和第3点是同一个原因:hbx sdk 目录不支持import * as xxx这种 amd 类的js模块。只能改成require(xxx)导入,但改成这种导入方式后,hbx sdk编译时,又不会主动把文件复制到编译目录,所以需要手动导入
第3点为什么我 要把ecahrt.js单独放到页面上:原因为了包大小,因为只2mb限制。而且为了全量功能,单独放page内,它这个依赖会打到分包中,不会在主包中。这样。我的demo发布120个页面共6-10mb大小,也能发布。同理你们的也是
2025年02月26日:
1.学习配置uts的开发环境
2025年03月01日:
1.xRequest.uts的警告消除,已给官方反馈。
- 2025年03月15日:
1.泛型使用过一次就会丢失类型,需要重新的生成和定义。
2.import的页面组件,不能放到pages.json里面,组件就是组件,页面就是页面,必须分清楚。
3.2025年03月18日:
1.安装雷电模拟器9
2.制作自定义基座。
3.方便调试代码使用,依然是uts类型不熟练导致的,明天接着学习。我一定要拿下apk。
4.最终换成mumu模拟器来实现了,自定义打包,自定义基座。
2025年03月20日:
写插件流程
先预估与兼容平台:安卓,ios,web,mp
如果都有,可以先开发web,mp
再写安卓
再写ios( ios 相对简单),
2025年04月07日:
input插件,有个adjust-position参数可以控制是否键盘弹起时,是否自动上推页面。
2025年04月29日:MCP+TRAE
@Run🍀 你去试下看看https://context7.com/tmzdy888/tmui4-doc
2025年5月26日:解决x跨域的问题
2025年6月5日:
用require导入的模块在小程序这边。。x编译时直接自动忽略
2025年6月10日:Tmui4.0跨域本地H5跨域问题处理
参考官方网址新增文件:vite.config.js
https://doc.dcloud.net.cn/uni-app-x/web/#dev-server
export default defineConfig({
plugins: [uni()],
server: {
port: 9527,
proxy: {
'/api': {
target: 'https://zscXXXXX/api',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, ''),
}
},
}
});
修改下请求的开发环境,解决本地H5跨域的问题。解放后台。
2025年06月11日:
1.2025年05月03日:
首次尝鲜安装鸿蒙Next的开发工具,安装模拟器,然后成功运行一个示例工程。
2.2025年08月16日:
如果有鸿蒙next有2个软件,一个是:我的开发案例、HMOS代码工坊
Vip群开发的例子和demo:
plugin/README.md · HarmonyOS-Cases/Cases - Gitee.com
App上架的流程总结:
步骤一:首页需要在腾讯云/百度云等服务商进行app的ICP备案工作。
步骤二:完成App的上架工作(暂不需要app软著),上架时需要校验ICP备案结果。
步骤三:完成App上架后获取下载链接,在开通商户服务时需要找个地址信息。
步骤四:等待官方评审是否达到要求。
以上均是日常学习过程中的笔记真实分享,虽杂乱,但字里行间透露一种真诚,坚持、努力!
2. 给官方提出一个ISSUE:
https://issues.dcloud.net.cn/pages/issues/detail?id=22088,因此问题影响还比较大,最终得官方得认同后,及时修复完成。
3.参与开源项目uni-x-ai组件的使用和测试任务,也提了下优化的功能点。
活动契机:2025年激励计划
tmui4.0的官方群里得知,2025年的激励计划将会推出一个“鸿蒙应用开发大赛”,奖项将会奖励优秀的应用。我立马报名参加了。我登陆活动页面:https://developer.huawei.com/consumer/cn/activity/harmonyos-incentive/2025 我知道这是一次很好的机会,让自己学习到的uniapp-x语法和tmui4.0组件知识做一个综合项目,也算是将近200天的课外学习的付出有个结果。
我决定将开发一款鸿蒙next的app:《小张Ai运维智能体》,将此作品作为2025年激励计划的参赛作品。比赛期间:
1.我又学习到如何进行app备案,
2.如何进行app的自动化测试,
3.如何在鸿蒙开发平台agc上进行app包的调试工作。
4.如何进行发布和审核,
5.如何进行app的迭代更新。
截止写这篇文章时,我一个人已经独自完成app的前后端的开发工作,正在接收鸿蒙官方的审核。审核通过后将会发布应用市场,也衷心希望app能顺利让大家在鸿蒙Next平台上使用。
总结
冥冥之中:就在2025年11月02日tmui4.0的官方群里得知,官方有个https://ask.dcloud.net.cn/article/42142(【鸿蒙征文】星光不负,码向未来!分享你的uni-app鸿蒙开发实践,赢取精美好礼!)活动,我想着这又是一个很好的契机,所以我报名参加了。我就将过去真实的记录一起分享给大家,这也是对过去的努力做一个总结,也是开启下阶段继续学习鸿蒙next的动力,为生态发展贡献自己的一份力量。
望有更多的小伙伴们加入鸿蒙Next的开发,共同学习,共同推动鸿蒙生态的发展。也希望uniapp-x和tmui4.0做的越来越好。
后记
这段旅程,恰如千里之行。幸于起点处,得遇良器与明灯,更收获了温暖的港湾。
鸿图已展,蒙学初成。愿这份始于足下的热忱,能照亮更远的征途。
贵在坚持,与君共勉。
相识篇
2025年02月24日,这一天难忘。随着鸿蒙生态的蓬勃发展,我和小伙伴们也在不断学习、探索、交流中,得知了uniapp-x的官网:https://doc.dcloud.net.cn/uni-app-x地址, 这个网站里我读懂了2个很重要的信息。
其一:uni-app x,是下一代 uni-app,是一个跨平台应用开发引擎。uts在Android平台编译为kotlin、在iOS平台编译为swift、在鸿蒙next平台上编译为ArkTS、在Web和小程序平台编译为js。官方重心便宜至uniapp-x上科技的创新。
其二:在这个网页下面有个插件生态部分描述了:TMUI4.0:高品质UI库,插件大赛一等奖。
综合这两方面原因:我也深知原来无任何app开发经验的小白,必须需要借助uniapp-x和tmui4.0才有逆袭的机会。从此刻开始就暗自下定决心利用工作之外的时间冲刺鸿蒙Next的app开发。
后盾篇
利用工作日之外的时间,我还必须跟家庭表达我的真实想法要冲刺鸿蒙Next的app开发。跟他们沟通说:鸿蒙Next的app将来一定会越来越有前景和市场,尤其是在Ai时代背景下,做好鸿蒙Next的app开发,一定会有很大的发展。最终得到已怀孕老婆的支持,我也终于可以开始了。
学习过程
1. 笔记分享
2025年02月25日:
1.采购tmUI 4.0的Vip资料,并且官方给了一些资料。计划先学习下uniapp-x官方资料。
2.编译到微信时,
- 如果提示xanimations页面不存在,就改成下pages.json中的名称改成页面的xAnimationS
- 如果hbx编译成功后打不开微信工具,就自己手动打开工具,点导入项目,导入你根目录中的unpackage/dis/dev/mp-weixin
然后模拟器上方把热重载关闭下。 - 接着可能报echart.js,mqtt.js文件不存在。需要你手动复制到mp-weixin目录内,这个看我常文档:见问题页面。就是复制到对应目录结构内。
解释下原因:
第1点,是我复制的时候,是复制老的页面,名称忘记改了。
第2点,和第3点是同一个原因:hbx sdk 目录不支持import * as xxx这种 amd 类的js模块。只能改成require(xxx)导入,但改成这种导入方式后,hbx sdk编译时,又不会主动把文件复制到编译目录,所以需要手动导入
第3点为什么我 要把ecahrt.js单独放到页面上:原因为了包大小,因为只2mb限制。而且为了全量功能,单独放page内,它这个依赖会打到分包中,不会在主包中。这样。我的demo发布120个页面共6-10mb大小,也能发布。同理你们的也是
2025年02月26日:
1.学习配置uts的开发环境
2025年03月01日:
1.xRequest.uts的警告消除,已给官方反馈。
- 2025年03月15日:
1.泛型使用过一次就会丢失类型,需要重新的生成和定义。
2.import的页面组件,不能放到pages.json里面,组件就是组件,页面就是页面,必须分清楚。
3.2025年03月18日:
1.安装雷电模拟器9
2.制作自定义基座。
3.方便调试代码使用,依然是uts类型不熟练导致的,明天接着学习。我一定要拿下apk。
4.最终换成mumu模拟器来实现了,自定义打包,自定义基座。
2025年03月20日:
写插件流程
先预估与兼容平台:安卓,ios,web,mp
如果都有,可以先开发web,mp
再写安卓
再写ios( ios 相对简单),
2025年04月07日:
input插件,有个adjust-position参数可以控制是否键盘弹起时,是否自动上推页面。
2025年04月29日:MCP+TRAE
@Run🍀 你去试下看看https://context7.com/tmzdy888/tmui4-doc
2025年5月26日:解决x跨域的问题
2025年6月5日:
用require导入的模块在小程序这边。。x编译时直接自动忽略
2025年6月10日:Tmui4.0跨域本地H5跨域问题处理
参考官方网址新增文件:vite.config.js
https://doc.dcloud.net.cn/uni-app-x/web/#dev-server
export default defineConfig({
plugins: [uni()],
server: {
port: 9527,
proxy: {
'/api': {
target: 'https://zscXXXXX/api',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, ''),
}
},
}
});
修改下请求的开发环境,解决本地H5跨域的问题。解放后台。
2025年06月11日:
1.2025年05月03日:
首次尝鲜安装鸿蒙Next的开发工具,安装模拟器,然后成功运行一个示例工程。
2.2025年08月16日:
如果有鸿蒙next有2个软件,一个是:我的开发案例、HMOS代码工坊
Vip群开发的例子和demo:
plugin/README.md · HarmonyOS-Cases/Cases - Gitee.com
App上架的流程总结:
步骤一:首页需要在腾讯云/百度云等服务商进行app的ICP备案工作。
步骤二:完成App的上架工作(暂不需要app软著),上架时需要校验ICP备案结果。
步骤三:完成App上架后获取下载链接,在开通商户服务时需要找个地址信息。
步骤四:等待官方评审是否达到要求。
以上均是日常学习过程中的笔记真实分享,虽杂乱,但字里行间透露一种真诚,坚持、努力!
2. 给官方提出一个ISSUE:
https://issues.dcloud.net.cn/pages/issues/detail?id=22088,因此问题影响还比较大,最终得官方得认同后,及时修复完成。
3.参与开源项目uni-x-ai组件的使用和测试任务,也提了下优化的功能点。
活动契机:2025年激励计划
tmui4.0的官方群里得知,2025年的激励计划将会推出一个“鸿蒙应用开发大赛”,奖项将会奖励优秀的应用。我立马报名参加了。我登陆活动页面:https://developer.huawei.com/consumer/cn/activity/harmonyos-incentive/2025 我知道这是一次很好的机会,让自己学习到的uniapp-x语法和tmui4.0组件知识做一个综合项目,也算是将近200天的课外学习的付出有个结果。
我决定将开发一款鸿蒙next的app:《小张Ai运维智能体》,将此作品作为2025年激励计划的参赛作品。比赛期间:
1.我又学习到如何进行app备案,
2.如何进行app的自动化测试,
3.如何在鸿蒙开发平台agc上进行app包的调试工作。
4.如何进行发布和审核,
5.如何进行app的迭代更新。
截止写这篇文章时,我一个人已经独自完成app的前后端的开发工作,正在接收鸿蒙官方的审核。审核通过后将会发布应用市场,也衷心希望app能顺利让大家在鸿蒙Next平台上使用。
总结
冥冥之中:就在2025年11月02日tmui4.0的官方群里得知,官方有个https://ask.dcloud.net.cn/article/42142(【鸿蒙征文】星光不负,码向未来!分享你的uni-app鸿蒙开发实践,赢取精美好礼!)活动,我想着这又是一个很好的契机,所以我报名参加了。我就将过去真实的记录一起分享给大家,这也是对过去的努力做一个总结,也是开启下阶段继续学习鸿蒙next的动力,为生态发展贡献自己的一份力量。
望有更多的小伙伴们加入鸿蒙Next的开发,共同学习,共同推动鸿蒙生态的发展。也希望uniapp-x和tmui4.0做的越来越好。
后记
这段旅程,恰如千里之行。幸于起点处,得遇良器与明灯,更收获了温暖的港湾。
鸿图已展,蒙学初成。愿这份始于足下的热忱,能照亮更远的征途。
贵在坚持,与君共勉。
鸿蒙webview踩坑实录
鸿蒙WebView踩坑实录:这些问题我全遇到过!
做鸿蒙开发时,只要涉及加载网页、H5页面,就离不开WebView组件。但用起来总遇到各种小毛病——页面加载不出来、交互没反应、样式乱了,头都大了。今天把这些常见问题和解决办法整理出来,全是实战经验,新手照着做能少走很多弯路。
一、WebView连网页都加载不出来,咋整?
-
“网页无法打开,网络错误”
大概率是没加网络权限!鸿蒙应用要访问网络,必须在配置文件里声明权限,不然WebView连不上网。
解决:打开module.json5文件,在requestPermissions里加网络权限,代码如下:"requestPermissions": [ { "name": "ohos.permission.INTERNET", // 网络权限 "reason": "需要访问网络加载网页", "usedScene": { "ability": ["EntryAbility"], "when": "always" } } ]加完后重启项目,再试加载网页(比如加载“https://www.baidu.com”)。
-
加载本地HTML文件,显示“文件不存在”
本地HTML、CSS、JS文件要放在正确的目录里,不然WebView找不到。鸿蒙里本地资源得放在main_pages同级的rawfile文件夹下(没有就自己建)。
解决:- 新建
src/main/rawfile文件夹,把本地HTML文件(比如index.html)放进去; - 加载时用
$rawfile('index.html')获取路径,示例代码:Web({ src: $rawfile('index.html') }) .width('100%') .height('100%')
- 新建
-
HTTPS网页加载不了,提示“证书错误”
有些小众网站的HTTPS证书不被鸿蒙信任,WebView会拦截加载。开发测试时可以临时跳过证书验证(正式项目不建议,有安全风险)。
解决:在Web组件里加onCertificateError回调,返回true跳过验证:Web({ src: "https://xxx.com" }) .onCertificateError(() => { return true; // 跳过证书验证 })
二、WebView和H5交互没反应,咋回事?
- H5调用鸿蒙原生方法,没动静
得先给WebView设置“JS桥”,把原生方法暴露给H5,不然H5调用不到。
解决:- 第一步:用
WebController创建控制器,通过registerJavaScriptObject暴露原生方法; - 第二步:H5里用
window.xxx调用暴露的方法。
示例代码(鸿蒙侧):// 1. 创建Web控制器 private webController: WebController = new WebController();
- 第一步:用
build() {
Web({
src: "https://xxx.com",
controller: this.webController
})
.onPageEnd(() => {
// 2. 页面加载完成后,暴露原生方法给H5
this.webController.registerJavaScriptObject("鸿蒙原生对象名", {
原生方法名: (param: string) => {
// 原生方法逻辑,比如接收H5传的参数
console.log("H5传的参数:" + param);
}
});
})
}
H5侧调用代码:
```javascript
// 调用鸿蒙暴露的方法,传参数
window.鸿蒙原生对象名.原生方法名("我是H5的参数");
- 鸿蒙调用H5方法,没反应
要确保H5里的方法已经定义好,而且要在WebView页面加载完成后再调用,不然会找不到方法。
解决:在onPageEnd(页面加载完成)回调里调用H5方法,用runJavaScript:Web({ src: "https://xxx.com", controller: this.webController }) .onPageEnd(() => { // 调用H5里的方法,传参数(如果需要) this.webController.runJavaScript(`H5方法名("我是鸿蒙的参数")`); })
三、WebView样式乱了、适配有问题,咋调?
-
WebView里的文字太小/太大,适配不对
默认WebView的缩放比例可能和设备不匹配,得设置“视口(viewport)”让H5自适应鸿蒙设备屏幕。
解决:两种方式选一种:- 方式1:H5里加viewport meta标签(推荐,从源头适配):
<meta name="viewport" content="width=device-width, initial-scale=1.0"> - 方式2:鸿蒙侧用
setWebConfig设置缩放,示例:Web({ src: "https://xxx.com", controller: this.webController }) .setWebConfig({ viewport: { initialScale: 100, // 初始缩放比例100% width: WebViewportWidth.DEVICE_WIDTH // 视口宽度=设备宽度 } })
- 方式1:H5里加viewport meta标签(推荐,从源头适配):
-
WebView高度撑不满/滚不动,内容显示不全
默认WebView高度可能是“包裹内容”,如果H5内容多,会显示不全;或者没开滚动,导致滚不动。
解决:- 给WebView设固定高度(比如
height('80%'))或自适应父容器高度; - 开滚动:在WebView外层包个
List或Scroll组件,示例:Scroll() { Web({ src: "https://xxx.com" }) .width('100%') .height('auto') // 自适应内容高度 } .width('100%') .height('100%')
- 给WebView设固定高度(比如
四、其他小坑,遇到了别慌
- WebView加载页面时,白屏时间太长
可以加个“加载中”提示,提升用户体验。用onPageStart(开始加载)显示加载框,onPageEnd(加载完成)隐藏:@State isLoading: boolean = false;
build() {
Column() {
// 加载中提示
if (this.isLoading) {
Text("加载中...")
.margin(10)
}
// WebView
Web({ src: "https://xxx.com" })
.onPageStart(() => {
this.isLoading = true;
})
.onPageEnd(() => {
this.isLoading = false;
})
}
}
2. **WebView里的链接点了没反应,无法跳转**
默认WebView支持跳转,但如果是“_blank”(新窗口打开)的链接,鸿蒙会拦截。要处理的话,用`onUrlLoadIntercept`回调,手动处理跳转:
```typescript
Web({ src: "https://xxx.com" })
.onUrlLoadIntercept((event) => {
const newUrl = event.url;
// 手动加载新链接
this.webController.loadUrl(newUrl);
return true; // 拦截默认跳转,用自己的逻辑
})
以上就是WebView最常遇到的问题,其实核心就三点:权限要加对、交互要设桥、适配要调视口。如果还有其他坑,评论区可以一起交流,踩坑多了,自然就熟练了!
鸿蒙WebView踩坑实录:这些问题我全遇到过!
做鸿蒙开发时,只要涉及加载网页、H5页面,就离不开WebView组件。但用起来总遇到各种小毛病——页面加载不出来、交互没反应、样式乱了,头都大了。今天把这些常见问题和解决办法整理出来,全是实战经验,新手照着做能少走很多弯路。
一、WebView连网页都加载不出来,咋整?
-
“网页无法打开,网络错误”
大概率是没加网络权限!鸿蒙应用要访问网络,必须在配置文件里声明权限,不然WebView连不上网。
解决:打开module.json5文件,在requestPermissions里加网络权限,代码如下:"requestPermissions": [ { "name": "ohos.permission.INTERNET", // 网络权限 "reason": "需要访问网络加载网页", "usedScene": { "ability": ["EntryAbility"], "when": "always" } } ]加完后重启项目,再试加载网页(比如加载“https://www.baidu.com”)。
-
加载本地HTML文件,显示“文件不存在”
本地HTML、CSS、JS文件要放在正确的目录里,不然WebView找不到。鸿蒙里本地资源得放在main_pages同级的rawfile文件夹下(没有就自己建)。
解决:- 新建
src/main/rawfile文件夹,把本地HTML文件(比如index.html)放进去; - 加载时用
$rawfile('index.html')获取路径,示例代码:Web({ src: $rawfile('index.html') }) .width('100%') .height('100%')
- 新建
-
HTTPS网页加载不了,提示“证书错误”
有些小众网站的HTTPS证书不被鸿蒙信任,WebView会拦截加载。开发测试时可以临时跳过证书验证(正式项目不建议,有安全风险)。
解决:在Web组件里加onCertificateError回调,返回true跳过验证:Web({ src: "https://xxx.com" }) .onCertificateError(() => { return true; // 跳过证书验证 })
二、WebView和H5交互没反应,咋回事?
- H5调用鸿蒙原生方法,没动静
得先给WebView设置“JS桥”,把原生方法暴露给H5,不然H5调用不到。
解决:- 第一步:用
WebController创建控制器,通过registerJavaScriptObject暴露原生方法; - 第二步:H5里用
window.xxx调用暴露的方法。
示例代码(鸿蒙侧):// 1. 创建Web控制器 private webController: WebController = new WebController();
- 第一步:用
build() {
Web({
src: "https://xxx.com",
controller: this.webController
})
.onPageEnd(() => {
// 2. 页面加载完成后,暴露原生方法给H5
this.webController.registerJavaScriptObject("鸿蒙原生对象名", {
原生方法名: (param: string) => {
// 原生方法逻辑,比如接收H5传的参数
console.log("H5传的参数:" + param);
}
});
})
}
H5侧调用代码:
```javascript
// 调用鸿蒙暴露的方法,传参数
window.鸿蒙原生对象名.原生方法名("我是H5的参数");
- 鸿蒙调用H5方法,没反应
要确保H5里的方法已经定义好,而且要在WebView页面加载完成后再调用,不然会找不到方法。
解决:在onPageEnd(页面加载完成)回调里调用H5方法,用runJavaScript:Web({ src: "https://xxx.com", controller: this.webController }) .onPageEnd(() => { // 调用H5里的方法,传参数(如果需要) this.webController.runJavaScript(`H5方法名("我是鸿蒙的参数")`); })
三、WebView样式乱了、适配有问题,咋调?
-
WebView里的文字太小/太大,适配不对
默认WebView的缩放比例可能和设备不匹配,得设置“视口(viewport)”让H5自适应鸿蒙设备屏幕。
解决:两种方式选一种:- 方式1:H5里加viewport meta标签(推荐,从源头适配):
<meta name="viewport" content="width=device-width, initial-scale=1.0"> - 方式2:鸿蒙侧用
setWebConfig设置缩放,示例:Web({ src: "https://xxx.com", controller: this.webController }) .setWebConfig({ viewport: { initialScale: 100, // 初始缩放比例100% width: WebViewportWidth.DEVICE_WIDTH // 视口宽度=设备宽度 } })
- 方式1:H5里加viewport meta标签(推荐,从源头适配):
-
WebView高度撑不满/滚不动,内容显示不全
默认WebView高度可能是“包裹内容”,如果H5内容多,会显示不全;或者没开滚动,导致滚不动。
解决:- 给WebView设固定高度(比如
height('80%'))或自适应父容器高度; - 开滚动:在WebView外层包个
List或Scroll组件,示例:Scroll() { Web({ src: "https://xxx.com" }) .width('100%') .height('auto') // 自适应内容高度 } .width('100%') .height('100%')
- 给WebView设固定高度(比如
四、其他小坑,遇到了别慌
- WebView加载页面时,白屏时间太长
可以加个“加载中”提示,提升用户体验。用onPageStart(开始加载)显示加载框,onPageEnd(加载完成)隐藏:@State isLoading: boolean = false;
build() {
Column() {
// 加载中提示
if (this.isLoading) {
Text("加载中...")
.margin(10)
}
// WebView
Web({ src: "https://xxx.com" })
.onPageStart(() => {
this.isLoading = true;
})
.onPageEnd(() => {
this.isLoading = false;
})
}
}
2. **WebView里的链接点了没反应,无法跳转**
默认WebView支持跳转,但如果是“_blank”(新窗口打开)的链接,鸿蒙会拦截。要处理的话,用`onUrlLoadIntercept`回调,手动处理跳转:
```typescript
Web({ src: "https://xxx.com" })
.onUrlLoadIntercept((event) => {
const newUrl = event.url;
// 手动加载新链接
this.webController.loadUrl(newUrl);
return true; // 拦截默认跳转,用自己的逻辑
})
以上就是WebView最常遇到的问题,其实核心就三点:权限要加对、交互要设桥、适配要调视口。如果还有其他坑,评论区可以一起交流,踩坑多了,自然就熟练了!
收起阅读 »HarmonyOS ide签名
鸿蒙DevEco Studio签名那些事儿,避坑指南来了
做鸿蒙原生开发,签名绝对是绕不开的坎儿——没弄好签名,应用要么跑不起来,要么打包后安装不了。今天就把签名相关的常见问题、原因和解决办法捋清楚,都是实战里踩过的坑,新手看完能少走不少弯路。
一、签名文件创建不了,咋回事?
-
“密钥库文件已存在”报错
大概率是你选的保存路径里,已经有同名的.p12文件了。比如之前创建过签名,没删干净又选了同一个文件夹。
解决:换个文件名,或者把路径里的旧签名文件删掉,再重新创建。 -
“输入的密码不符合要求”
DevEco Studio对签名密码有规则:至少8位,得包含大小写字母、数字,还得有特殊符号(比如!、@)。别图省事设简单密码,比如“12345678”肯定过不了。
解决:按规则改密码,比如“Harmony123!”,记好别忘,后续用签名还要填。 -
创建时卡在“生成密钥”步骤
一般是电脑性能不够,或者DevEco Studio后台进程卡了。尤其老电脑,生成密钥需要一点时间,别着急关窗口。
解决:等1-2分钟,要是还没反应,重启DevEco Studio,关掉其他占内存的软件(比如浏览器多标签、微信)再试。
二、签名配置完,应用还是跑不起来?
-
“未找到匹配的签名信息”提示
常见两种情况:一是你配置的签名文件路径错了(比如文件移位置了,路径没更新);二是模块(module)没选对签名,比如entry模块用了release模块的签名。
解决:- 打开“File > Project Structure > Project Settings > Modules”,选中要配置的模块(比如entry);
- 点“Signing Configs”,检查“Key Store File”路径是不是正确,不对就重新选择签名文件;
- 再去“Build Types”,确认“Signing Config”选的是你配置好的签名(比如debug)。
-
真机运行提示“签名验证失败”
可能是你的真机没在鸿蒙开发者平台注册,或者签名里的“应用ID”和平台上注册的不一致。鸿蒙对真机调试的签名验证很严,必须一一对应。
解决:- 先去“鸿蒙开发者平台 > 设备管理”,把真机的设备SN码加进去;
- 再检查签名文件里的“Package Name”(应用ID),和平台上“应用管理”里的应用ID完全一致,多一个字母都不行。
三、打包时签名出问题,安装包用不了?
-
Release包打包失败,提示“签名文件损坏”
大概率是签名文件被误删、移动,或者之前创建时没保存好。比如把p12文件存在桌面,不小心删了,再打包就找不到了。
解决:如果有备份,就重新选择备份的签名文件;没有备份的话,只能重新创建签名,然后去鸿蒙开发者平台更新应用的签名信息(不然之前的设备用不了新包)。 -
安装Release包到设备,提示“安装失败,签名不匹配”
可能是你打包用的签名,和设备之前调试用的签名不是同一个。比如之前用debug签名跑过应用,现在换Release签名打包,安装时就会冲突。
解决:先把设备上原来的应用卸载干净,再安装新的Release包;或者打包时用和调试时相同的签名(如果是测试用的话)。
四、签名相关小技巧,少踩坑!
-
签名文件别乱存,及时备份
创建好的签名文件(比如myapp.p12),最好存在项目文件夹里,和项目一起备份(比如传到Git),别存在桌面或临时文件夹,丢了很麻烦。 -
密码记下来,别靠脑子
签名的“密钥库密码”和“密钥密码”,建议存在记事本里,和签名文件放一起。很多人创建时图快,过后就忘,只能重新创建签名,还得改平台配置。 -
debug和release签名分开用
开发时用debug签名(方便调试,不需要平台注册),打包发布时用release签名(必须在平台注册,用于正式安装包),别混着用,不然容易出现验证失败的问题。
以上就是DevEco Studio签名最常见的问题和解决办法,其实只要注意路径、应用ID、设备注册这几点,签名就不算难。要是还有其他问题,评论区可以一起讨论,毕竟大家都是踩坑过来的!
鸿蒙DevEco Studio签名那些事儿,避坑指南来了
做鸿蒙原生开发,签名绝对是绕不开的坎儿——没弄好签名,应用要么跑不起来,要么打包后安装不了。今天就把签名相关的常见问题、原因和解决办法捋清楚,都是实战里踩过的坑,新手看完能少走不少弯路。
一、签名文件创建不了,咋回事?
-
“密钥库文件已存在”报错
大概率是你选的保存路径里,已经有同名的.p12文件了。比如之前创建过签名,没删干净又选了同一个文件夹。
解决:换个文件名,或者把路径里的旧签名文件删掉,再重新创建。 -
“输入的密码不符合要求”
DevEco Studio对签名密码有规则:至少8位,得包含大小写字母、数字,还得有特殊符号(比如!、@)。别图省事设简单密码,比如“12345678”肯定过不了。
解决:按规则改密码,比如“Harmony123!”,记好别忘,后续用签名还要填。 -
创建时卡在“生成密钥”步骤
一般是电脑性能不够,或者DevEco Studio后台进程卡了。尤其老电脑,生成密钥需要一点时间,别着急关窗口。
解决:等1-2分钟,要是还没反应,重启DevEco Studio,关掉其他占内存的软件(比如浏览器多标签、微信)再试。
二、签名配置完,应用还是跑不起来?
-
“未找到匹配的签名信息”提示
常见两种情况:一是你配置的签名文件路径错了(比如文件移位置了,路径没更新);二是模块(module)没选对签名,比如entry模块用了release模块的签名。
解决:- 打开“File > Project Structure > Project Settings > Modules”,选中要配置的模块(比如entry);
- 点“Signing Configs”,检查“Key Store File”路径是不是正确,不对就重新选择签名文件;
- 再去“Build Types”,确认“Signing Config”选的是你配置好的签名(比如debug)。
-
真机运行提示“签名验证失败”
可能是你的真机没在鸿蒙开发者平台注册,或者签名里的“应用ID”和平台上注册的不一致。鸿蒙对真机调试的签名验证很严,必须一一对应。
解决:- 先去“鸿蒙开发者平台 > 设备管理”,把真机的设备SN码加进去;
- 再检查签名文件里的“Package Name”(应用ID),和平台上“应用管理”里的应用ID完全一致,多一个字母都不行。
三、打包时签名出问题,安装包用不了?
-
Release包打包失败,提示“签名文件损坏”
大概率是签名文件被误删、移动,或者之前创建时没保存好。比如把p12文件存在桌面,不小心删了,再打包就找不到了。
解决:如果有备份,就重新选择备份的签名文件;没有备份的话,只能重新创建签名,然后去鸿蒙开发者平台更新应用的签名信息(不然之前的设备用不了新包)。 -
安装Release包到设备,提示“安装失败,签名不匹配”
可能是你打包用的签名,和设备之前调试用的签名不是同一个。比如之前用debug签名跑过应用,现在换Release签名打包,安装时就会冲突。
解决:先把设备上原来的应用卸载干净,再安装新的Release包;或者打包时用和调试时相同的签名(如果是测试用的话)。
四、签名相关小技巧,少踩坑!
-
签名文件别乱存,及时备份
创建好的签名文件(比如myapp.p12),最好存在项目文件夹里,和项目一起备份(比如传到Git),别存在桌面或临时文件夹,丢了很麻烦。 -
密码记下来,别靠脑子
签名的“密钥库密码”和“密钥密码”,建议存在记事本里,和签名文件放一起。很多人创建时图快,过后就忘,只能重新创建签名,还得改平台配置。 -
debug和release签名分开用
开发时用debug签名(方便调试,不需要平台注册),打包发布时用release签名(必须在平台注册,用于正式安装包),别混着用,不然容易出现验证失败的问题。
以上就是DevEco Studio签名最常见的问题和解决办法,其实只要注意路径、应用ID、设备注册这几点,签名就不算难。要是还有其他问题,评论区可以一起讨论,毕竟大家都是踩坑过来的!
收起阅读 »鸿蒙原生开发经验分享大纲
鸿蒙原生开发常见问题汇总,纯干货分享!
咱直接开门见山,聊一聊鸿蒙原生开发里那些常遇到的麻烦事儿,顺便也讲讲对应的解决办法,不管你是刚接触鸿蒙开发的新手,还是已经有一定经验的开发者,希望这篇文章都能帮你少走点弯路。
一、环境搭建
- DevEco Studio安装失败:可能是电脑的系统环境不满足要求,比如内存不够、磁盘空间不足,或者是安装包下载不完整。解决办法就是先检查系统配置,清理出足够的内存和磁盘空间,然后重新下载安装包,最好从官方正规渠道下载,下载的时候确保网络稳定。
- 模拟器启动不了:电脑没开启虚拟化技术是常见原因,还有可能是装了像360安全卫士、火绒这类安全软件,把模拟器的服务禁用了,也可能是模拟器镜像下载不完整或者损坏。解决步骤如下:先重启电脑,进BIOS把虚拟化技术打开(不同品牌电脑进BIOS的快捷键不一样,联想一般按F2,惠普按F10 ,戴尔按F2,华硕按Del );然后把安全软件里拦截模拟器的功能关掉;最后在DevEco Studio里把原来下载的模拟器镜像删了重新下载。
二、代码编写
- ArkTS语法错误:ArkTS是静态类型语言,类型不匹配就很容易出错,比如你定义一个变量是数字类型,结果后面给它赋值成字符串了。还有就是API调用不当,鸿蒙的API在不同版本可能有变化。解决办法就是写代码的时候多注意类型声明,利用好IDE的自动补全和类型提示功能,调用API之前先去官方文档确认一下版本和用法。
- 函数调用没反应:有可能是函数参数传错了,或者函数内部逻辑有问题。遇到这种情况,先检查参数的类型和个数对不对,再在函数内部关键位置打印一些日志,看看程序执行到哪儿出问题了。
三、界面布局
- UI在不同设备上显示错乱:主要是布局没有做响应式设计,用了太多固定尺寸。在鸿蒙开发里,不同设备屏幕尺寸和分辨率都不一样,要是布局不灵活,就会出现按钮、文字显示不正常的情况。解决办法是多用鸿蒙提供的布局组件,像Column、Row、Flex 这些,尺寸单位用vp(视口单位)或者百分比,少用固定像素px 。
- 组件显示不全:可能是组件的层级关系没处理好,被其他组件盖住了,也可能是布局设置有问题,比如宽度、高度设置得不合理。检查一下组件的z - index属性,调整层级,再看看布局的设置,保证组件有足够空间显示。
四、权限相关
- 应用无法获取某些权限:像获取位置信息、相机权限这些,HarmonyOS对敏感权限管控很严格。如果在配置文件里没声明权限,应用就获取不了。要在module.json5文件里的“module”节点下添加“requestPermissions”数组,声明需要的权限,比如获取位置信息权限:
{ "module": { "package": "com.example.harmonyosdemo", "name": ".entry", "type": "entry", "description": "应用入口模块", "mainElement": "EntryAbility", // 新增:位置信息权限声明 "requestPermissions": [ { "name": "ohos.permission.LOCATION", "reason": "需要获取位置信息提供服务", "usedScene": { "ability": ["EntryAbility"], "when": "always" } } ], "abilities": [] } } - 动态权限申请失败:有些权限除了在配置文件声明,还需要动态申请,特别是在Android设备上运行的时候。申请的时候要注意权限申请的回调处理,确保用户同意授权后,应用能正常使用权限。
五、调试相关
- 调试时断点不起作用:有可能是代码优化设置影响了断点,或者是调试配置有问题。在DevEco Studio里,把代码优化选项关掉试试,再检查一下调试配置,确保断点设置在可执行代码行上。
- 日志打印不出来:检查一下日志级别设置,要是设置太高,低级别日志就打印不出来了。还有就是确认一下日志打印的方法有没有写错,比如HiLog的使用,要确保标签、日志级别这些参数都正确。
以上就是鸿蒙原生开发里比较常见的一些问题,希望能帮到大家,祝各位开发顺利,早日开发出超棒的鸿蒙应用!
鸿蒙原生开发常见问题汇总,纯干货分享!
咱直接开门见山,聊一聊鸿蒙原生开发里那些常遇到的麻烦事儿,顺便也讲讲对应的解决办法,不管你是刚接触鸿蒙开发的新手,还是已经有一定经验的开发者,希望这篇文章都能帮你少走点弯路。
一、环境搭建
- DevEco Studio安装失败:可能是电脑的系统环境不满足要求,比如内存不够、磁盘空间不足,或者是安装包下载不完整。解决办法就是先检查系统配置,清理出足够的内存和磁盘空间,然后重新下载安装包,最好从官方正规渠道下载,下载的时候确保网络稳定。
- 模拟器启动不了:电脑没开启虚拟化技术是常见原因,还有可能是装了像360安全卫士、火绒这类安全软件,把模拟器的服务禁用了,也可能是模拟器镜像下载不完整或者损坏。解决步骤如下:先重启电脑,进BIOS把虚拟化技术打开(不同品牌电脑进BIOS的快捷键不一样,联想一般按F2,惠普按F10 ,戴尔按F2,华硕按Del );然后把安全软件里拦截模拟器的功能关掉;最后在DevEco Studio里把原来下载的模拟器镜像删了重新下载。
二、代码编写
- ArkTS语法错误:ArkTS是静态类型语言,类型不匹配就很容易出错,比如你定义一个变量是数字类型,结果后面给它赋值成字符串了。还有就是API调用不当,鸿蒙的API在不同版本可能有变化。解决办法就是写代码的时候多注意类型声明,利用好IDE的自动补全和类型提示功能,调用API之前先去官方文档确认一下版本和用法。
- 函数调用没反应:有可能是函数参数传错了,或者函数内部逻辑有问题。遇到这种情况,先检查参数的类型和个数对不对,再在函数内部关键位置打印一些日志,看看程序执行到哪儿出问题了。
三、界面布局
- UI在不同设备上显示错乱:主要是布局没有做响应式设计,用了太多固定尺寸。在鸿蒙开发里,不同设备屏幕尺寸和分辨率都不一样,要是布局不灵活,就会出现按钮、文字显示不正常的情况。解决办法是多用鸿蒙提供的布局组件,像Column、Row、Flex 这些,尺寸单位用vp(视口单位)或者百分比,少用固定像素px 。
- 组件显示不全:可能是组件的层级关系没处理好,被其他组件盖住了,也可能是布局设置有问题,比如宽度、高度设置得不合理。检查一下组件的z - index属性,调整层级,再看看布局的设置,保证组件有足够空间显示。
四、权限相关
- 应用无法获取某些权限:像获取位置信息、相机权限这些,HarmonyOS对敏感权限管控很严格。如果在配置文件里没声明权限,应用就获取不了。要在module.json5文件里的“module”节点下添加“requestPermissions”数组,声明需要的权限,比如获取位置信息权限:
{ "module": { "package": "com.example.harmonyosdemo", "name": ".entry", "type": "entry", "description": "应用入口模块", "mainElement": "EntryAbility", // 新增:位置信息权限声明 "requestPermissions": [ { "name": "ohos.permission.LOCATION", "reason": "需要获取位置信息提供服务", "usedScene": { "ability": ["EntryAbility"], "when": "always" } } ], "abilities": [] } } - 动态权限申请失败:有些权限除了在配置文件声明,还需要动态申请,特别是在Android设备上运行的时候。申请的时候要注意权限申请的回调处理,确保用户同意授权后,应用能正常使用权限。
五、调试相关
- 调试时断点不起作用:有可能是代码优化设置影响了断点,或者是调试配置有问题。在DevEco Studio里,把代码优化选项关掉试试,再检查一下调试配置,确保断点设置在可执行代码行上。
- 日志打印不出来:检查一下日志级别设置,要是设置太高,低级别日志就打印不出来了。还有就是确认一下日志打印的方法有没有写错,比如HiLog的使用,要确保标签、日志级别这些参数都正确。
以上就是鸿蒙原生开发里比较常见的一些问题,希望能帮到大家,祝各位开发顺利,早日开发出超棒的鸿蒙应用!
收起阅读 »App 上架需要什么?从开发者账号到开心上架(Appuploader)免 Mac 上传的完整流程指南
'''对于初次上架 iOS 应用的开发者来说,“App 上架需要什么?”
往往是最常被问到的问题。
与 Android 市场相比,苹果 App Store 的上架流程更严格、步骤更多。
不仅需要合法的 Apple 开发者账号,还要准备好签名证书、隐私政策、截图描述、IPA 包等。
此外,上传环节传统上依赖 Mac + Xcode,但现在通过 开心上架(Appuploader)命令行工具 即便在 Windows 或 Linux 系统 中,也能轻松完成上架流程。
本文将以实战角度为你详细说明 iOS App 上架所需的全部条件与操作要点。
一、App 上架苹果商店前必备条件总览
要上架 App Store,你至少需要准备以下六项内容:
| 项目 | 说明 |
|---|---|
| Apple Developer 开发者账号 | 负责上架和签名认证 |
| 应用签名证书与描述文件 | 验证 App 合法性 |
| IPA 安装包 | 打包生成的 iOS 应用文件 |
| App 信息与截图 | 用于 App Store 展示 |
| 隐私政策链接 | 审核必需内容 |
| 上传工具 | 将 IPA 提交到 App Store |
每一项都不可缺少,否则应用将无法被苹果审核通过。
二、开发者账号:上架的第一步
注册开发者账号
访问 Apple Developer 官网 并注册账号。
你需要一个 Apple ID,并选择加入 Apple Developer Program(年费 99 美元)。
账号类型如下:
| 类型 | 适合对象 | 特点 |
|---|---|---|
| 个人账号 | 独立开发者 | 成本低、操作简单 |
| 企业账号 | 公司或团队 | 支持多人协作、团队证书共享 |
审核与激活
提交资料后,苹果会通过邮箱验证身份。
审核通过后,你的 Apple 开发者账号即可使用。
三、签名证书与描述文件(Provisioning Profile)
iOS 应用无法像 Android 一样随意打包上传,它必须经过苹果官方签名认证,才能被系统识别与安装。
证书类型:
| 证书名称 | 用途 |
|---|---|
| 开发证书(Development) | 用于测试和调试 |
| 发布证书(Distribution) | 用于 App Store 上架 |
| 推送证书(Push Certificate) | 用于 APNs 推送功能 |
传统方式(麻烦)
需要使用 Xcode + 钥匙串助手生成证书,仅限 Mac 用户操作。
使用 开心上架(Appuploader) 生成证书
- 无需 Xcode;
- 生成速度快;
- 支持多人共享证书文件;
- 团队协作开发更高效。
四、IPA 文件:App 上架的核心载体
IPA 文件相当于 iOS 应用的“安装包”。
无论你使用什么框架(原生、Flutter、uni-app、React Native),都必须最终打包出 .ipa 文件。
打包方式对照:
| 技术栈 | 打包方法 |
|---|---|
| 原生 iOS(Xcode) | Product → Archive → Export |
| uni-app(HBuilderX) | 云打包生成 IPA |
| Flutter / React Native | 命令行构建(需签名文件) |
| Hybrid / Cordova | Xcode 导出或第三方工具 |
对没有 Mac 的开发者而言,uni-app 云打包 + 开心上架 CLI 是最便捷组合。
五、App Store 提交资料与合规要求
在上传 IPA 之前,需要准备以下内容:
| 项目 | 说明 |
|---|---|
| 应用名称 | 符合苹果命名规范,避免关键词堆砌 |
| App 描述 | 介绍应用功能与优势 |
| 关键词 | 有助于搜索排名 |
| 截图 | 必须包含 6.5" 与 5.5" 屏幕尺寸 |
| 隐私政策链接 | 审核强制项,必须能访问 |
| 应用图标 | PNG 格式,1024×1024 像素 |
苹果审核特别重视 隐私与安全声明。
建议在网页托管隐私政策文件(如 GitHub Pages 或自有域名)。
六、上传工具选择与流程
传统上传方式包括:
- Xcode 上传(官方推荐,但仅限 macOS)
- Transporter App(拖拽式上传)
- altool / Fastlane(命令行上传)
这些方式都依赖苹果生态,跨平台开发者无法使用。
推荐方案:开心上架(Appuploader)
支持 图形界面 + 命令行,兼容多系统。
命令行上传示例:
appuploader_cli -u ios@team.com -p xxx-xxx-xxx-xxx -c 2 -f ./build/app.ipa
| 参数 | 含义 |
|---|---|
-u |
Apple 开发者账号 |
-p |
App 专用密码 |
-c |
上传通道(1=旧通道,2=新通道) |
-f |
指定 IPA 文件路径 |
支持:
- 批量上传;
- 上传日志输出;
- 多语言截图与元数据同步;
- 自动化上架脚本集成。
七、App Store Connect 配置与审核发布
IPA 上传完成后,前往 App Store Connect:
填写应用基本信息;
上传截图与隐私政策链接;
选择应用分级(年龄限制);
设置价格与上架区域;
点击 “提交审核”。
审核时间:
- 普通应用:1–3 个工作日;
- 含内购或推送的应用:3–5 天。
八、常见上架问题与解决方法
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 上传失败 Invalid Credentials | 密码错误 | 使用 App 专用密码 |
| “Invalid Bundle ID” | 包名不一致 | 核对 Bundle Identifier |
| 审核拒绝 | 隐私政策或截图问题 | 修改后重新提交 |
| “Missing Provisioning Profile” | 签名配置错误 | 重新生成证书 |
| 上传卡顿 | 网络不稳 | 切换上传通道 -c 1 或 -c 2 |
九、免 Mac 自动化上架实践
你可以将 Fastlane 与 Appuploader CLI 结合,实现全平台的持续集成自动上架。
# 自动构建
fastlane gym --scheme "MyApp" --output_directory "./build"
# 自动上传
appuploader_cli -u dev@icloud.com -p xxx-xxx-xxx-xxx -c 2 -f ./build/MyApp.ipa
支持:
- Jenkins、GitLab CI、GitHub Actions 集成;
- 定时构建 + 自动发布;
- 日志追踪与版本通知。
App 上架需要什么?
需要的不只是账号与证书,更是一套高效的自动化上架流程。
开心上架(Appuploader) 让跨平台上架成为现实,让开发者在任何系统中都能完成从打包、签名到上传审核的全过程。
没有 Mac?没问题。有 Appuploader,就能开心上架。'''
'''对于初次上架 iOS 应用的开发者来说,“App 上架需要什么?”
往往是最常被问到的问题。
与 Android 市场相比,苹果 App Store 的上架流程更严格、步骤更多。
不仅需要合法的 Apple 开发者账号,还要准备好签名证书、隐私政策、截图描述、IPA 包等。
此外,上传环节传统上依赖 Mac + Xcode,但现在通过 开心上架(Appuploader)命令行工具 即便在 Windows 或 Linux 系统 中,也能轻松完成上架流程。
本文将以实战角度为你详细说明 iOS App 上架所需的全部条件与操作要点。
一、App 上架苹果商店前必备条件总览
要上架 App Store,你至少需要准备以下六项内容:
| 项目 | 说明 |
|---|---|
| Apple Developer 开发者账号 | 负责上架和签名认证 |
| 应用签名证书与描述文件 | 验证 App 合法性 |
| IPA 安装包 | 打包生成的 iOS 应用文件 |
| App 信息与截图 | 用于 App Store 展示 |
| 隐私政策链接 | 审核必需内容 |
| 上传工具 | 将 IPA 提交到 App Store |
每一项都不可缺少,否则应用将无法被苹果审核通过。
二、开发者账号:上架的第一步
注册开发者账号
访问 Apple Developer 官网 并注册账号。
你需要一个 Apple ID,并选择加入 Apple Developer Program(年费 99 美元)。
账号类型如下:
| 类型 | 适合对象 | 特点 |
|---|---|---|
| 个人账号 | 独立开发者 | 成本低、操作简单 |
| 企业账号 | 公司或团队 | 支持多人协作、团队证书共享 |
审核与激活
提交资料后,苹果会通过邮箱验证身份。
审核通过后,你的 Apple 开发者账号即可使用。
三、签名证书与描述文件(Provisioning Profile)
iOS 应用无法像 Android 一样随意打包上传,它必须经过苹果官方签名认证,才能被系统识别与安装。
证书类型:
| 证书名称 | 用途 |
|---|---|
| 开发证书(Development) | 用于测试和调试 |
| 发布证书(Distribution) | 用于 App Store 上架 |
| 推送证书(Push Certificate) | 用于 APNs 推送功能 |
传统方式(麻烦)
需要使用 Xcode + 钥匙串助手生成证书,仅限 Mac 用户操作。
使用 开心上架(Appuploader) 生成证书
- 无需 Xcode;
- 生成速度快;
- 支持多人共享证书文件;
- 团队协作开发更高效。
四、IPA 文件:App 上架的核心载体
IPA 文件相当于 iOS 应用的“安装包”。
无论你使用什么框架(原生、Flutter、uni-app、React Native),都必须最终打包出 .ipa 文件。
打包方式对照:
| 技术栈 | 打包方法 |
|---|---|
| 原生 iOS(Xcode) | Product → Archive → Export |
| uni-app(HBuilderX) | 云打包生成 IPA |
| Flutter / React Native | 命令行构建(需签名文件) |
| Hybrid / Cordova | Xcode 导出或第三方工具 |
对没有 Mac 的开发者而言,uni-app 云打包 + 开心上架 CLI 是最便捷组合。
五、App Store 提交资料与合规要求
在上传 IPA 之前,需要准备以下内容:
| 项目 | 说明 |
|---|---|
| 应用名称 | 符合苹果命名规范,避免关键词堆砌 |
| App 描述 | 介绍应用功能与优势 |
| 关键词 | 有助于搜索排名 |
| 截图 | 必须包含 6.5" 与 5.5" 屏幕尺寸 |
| 隐私政策链接 | 审核强制项,必须能访问 |
| 应用图标 | PNG 格式,1024×1024 像素 |
苹果审核特别重视 隐私与安全声明。
建议在网页托管隐私政策文件(如 GitHub Pages 或自有域名)。
六、上传工具选择与流程
传统上传方式包括:
- Xcode 上传(官方推荐,但仅限 macOS)
- Transporter App(拖拽式上传)
- altool / Fastlane(命令行上传)
这些方式都依赖苹果生态,跨平台开发者无法使用。
推荐方案:开心上架(Appuploader)
支持 图形界面 + 命令行,兼容多系统。
命令行上传示例:
appuploader_cli -u ios@team.com -p xxx-xxx-xxx-xxx -c 2 -f ./build/app.ipa
| 参数 | 含义 |
|---|---|
-u |
Apple 开发者账号 |
-p |
App 专用密码 |
-c |
上传通道(1=旧通道,2=新通道) |
-f |
指定 IPA 文件路径 |
支持:
- 批量上传;
- 上传日志输出;
- 多语言截图与元数据同步;
- 自动化上架脚本集成。
七、App Store Connect 配置与审核发布
IPA 上传完成后,前往 App Store Connect:
填写应用基本信息;
上传截图与隐私政策链接;
选择应用分级(年龄限制);
设置价格与上架区域;
点击 “提交审核”。
审核时间:
- 普通应用:1–3 个工作日;
- 含内购或推送的应用:3–5 天。
八、常见上架问题与解决方法
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 上传失败 Invalid Credentials | 密码错误 | 使用 App 专用密码 |
| “Invalid Bundle ID” | 包名不一致 | 核对 Bundle Identifier |
| 审核拒绝 | 隐私政策或截图问题 | 修改后重新提交 |
| “Missing Provisioning Profile” | 签名配置错误 | 重新生成证书 |
| 上传卡顿 | 网络不稳 | 切换上传通道 -c 1 或 -c 2 |
九、免 Mac 自动化上架实践
你可以将 Fastlane 与 Appuploader CLI 结合,实现全平台的持续集成自动上架。
# 自动构建
fastlane gym --scheme "MyApp" --output_directory "./build"
# 自动上传
appuploader_cli -u dev@icloud.com -p xxx-xxx-xxx-xxx -c 2 -f ./build/MyApp.ipa
支持:
- Jenkins、GitLab CI、GitHub Actions 集成;
- 定时构建 + 自动发布;
- 日志追踪与版本通知。
App 上架需要什么?
需要的不只是账号与证书,更是一套高效的自动化上架流程。
开心上架(Appuploader) 让跨平台上架成为现实,让开发者在任何系统中都能完成从打包、签名到上传审核的全过程。
没有 Mac?没问题。有 Appuploader,就能开心上架。'''
收起阅读 »














