查看: 340|回复: 0

微信小程序迁移鸿蒙ASCF:组件接口权限差异与踩坑修复

[复制链接]
发表于 1 小时前 | 显示全部楼层 |阅读模式
把微信小程序迁移到鸿蒙元服务,如果选择 ASCF 框架,理论上只需要调整 API 调用,但实际操作后会发现框架、组件、接口、权限都存在差异。这篇文章从实战角度梳理迁移过程中遇到的典型问题,以及对应的处理方式,希望能给正在做类似迁移的开发者一些参考。

ASCF 框架的底层机制

ASCF 是 HarmonyOS 元服务的开发框架,运行时依赖 ASCF Runtime 加载编译后的资源文件。和微信小程序的最大区别在于全局对象:小程序使用 wx,ASCF 使用 has(harmony atomic service)。文件后缀也不一样,但语法基本保持一致,迁移时批量替换后缀即可,一般不会出现语法兼容问题。

用 ASCF Converter 做批量转换

DevEco Studio 内置了 ASCF Converter 转换工具,菜单路径是 Tools > ASCF Devtools > ASCF Converter。打开后选择小程序源码目录和输出目录,工具会自动完成文件后缀替换、wx 到 has 的批量改写。

使用时有几个需要注意的点。转换前要确保 ascf 目录为空,否则可能覆盖已有代码。如果小程序源码经过压缩混淆,建议加上 --notaddtodo 参数,否则转换器会在混淆代码里插入大量 TODO 注释,反而把代码搞乱。

转换完成后会生成两个文件:ascf/ascf_src/transform.log 和 ascf/ascf_src/_ascfConvertReport/index.html。transform.log 里记录了不支持的接口位置,转换报告可以在浏览器中打开,列出哪些接口和组件被成功转换、哪些暂不支持。实际迁移时建议对着这份报告逐个处理,比对着官方文档排查效率高很多。

Converter 能处理的只是机械性替换,框架差异和业务逻辑仍然需要手动调整。以下几个问题在转换后经常出现。

let 作用域差异

小程序里 let 声明的变量在某些场景下跨块可访问,但 ASCF 对块级作用域检查更严格,超出块作用域就访问不到。IDE 会直接提示这类错误,跟随提示修改声明位置即可。

0.5px 导致边框渲染异常

ASCF 要求 px 值必须是整型,写 0.5px 会导致显示效果异常。实际遇到的情况是渐变边框在开发者工具里显示正常,但真机上边框直接消失,排查很久才发现是 0.5px 的问题,改成 1px 后恢复正常。

toast 组件必须换成 API 调用

小程序模板里可以直接使用 <toast> 组件,但 ASCF 不支持这种写法,需要改成 has.showToast 调用。Converter 不会自动处理这个差异,因为组件名和 API 差异较大,只能手动替换。弹窗一直不出现的场景,优先检查是不是用了 <toast> 组件。

开源库需要手动复制源码

如果项目依赖了 vant-weapp 这类开源库,Converter 不会自动处理 node_modules 里的代码。需要把开源库的小程序源码手动拷贝到源码目录下,让转换器能扫描到这部分代码,具体操作可参考官方文档中“使用 npm 包”的说明。

三方框架编译 ASCF 的方式

除了直接用 Converter 转换,Uniapp 和 Taro 项目也可以直接编译成 ASCF 元服务。

Uniapp 从 HarmonyOS 元服务支持开始,可以使用 MP-HARMONY 条件编译隔离元服务和其他平台的代码,编译产物拷贝到 ascf/ascf_src 目录即可运行。
  1. // MP-HARMONY 条件编译示例
  2. // #ifdef MP-HARMONY
  3. console.info('这段代码只在元服务 ASCF 上跑');
  4. // #endif
  5. // #ifdef WEB
  6. console.info('这段代码只在 WEB 上跑');
  7. // #endif
复制代码

Taro 从 4.1.5 版本开始支持 ASCF,通过 process.env.TARO_ENV === 'ascf' 做条件编译。
  1. if (process.env.TARO_ENV === 'ascf') {
  2.   require('path/to/ascf/name')
  3. } else if (process.env.TARO_ENV === 'h5') {
  4.   require('path/to/h5/name')
  5. }
复制代码

这两种方式的优势是后续只需要维护一份代码框架,ASCF 工程通过工具输出。但转换完成后仍然需要做平台功能适配,比如接入华为账号、隐私托管等。

分包大小与 tabbar 页面限制

ASCF 支持分包,但限制和微信小程序不一样。单个包不超过 2MB,总包不超过 10MB,可以申请更大额度。

更需要留意的是 tabbar 页面必须在主包中。小程序里 tabbar 页面可以放在分包,但 ASCF 不允许,迁移时如果把 tabbar 页面放到分包,运行时会直接白屏。

平板适配问题

元服务在平板上默认居中显示,且无法设置强制竖屏,这一点和小程序不同。如果元服务只设计了竖屏布局,在平板上会出现显示异常。目前华为有规划优化这个问题,但现阶段需要开发者自己做响应式适配。

hjs 中 constructor 返回函数

hjs(内联脚本)中,数组的 constructor 返回值不是字符串,而是一个函数。
  1. // 小程序里
  2. let arr = [1, 2, 3];
  3. console.log(arr.constructor); // 输出: "Array"
  4. // ASCF 里
  5. let arr = [1, 2, 3];
  6. console.log(arr.constructor); // 输出: function Array() { ... }
复制代码

如果代码里用 constructor 做类型判断,会永远返回 false。需要改成 typeof 或 Array.isArray()。

导航栏标题白色不生效

API version 12 时,globalStyle 里设置 "navigationBarTextStyle": "white" 实际显示黑色,因为系统导航栏不支持设置为白色。解决方案是在 app.json 里把 navigationStyle 改成 custom,使用自定义导航栏。
  1. {
  2.   "window": {
  3.     "navigationStyle": "custom"
  4.   }
  5. }
复制代码

改完后自己实现导航栏,颜色样式可以自由控制。

自定义组件不支持 getPageId

小程序里自定义组件可以通过 getPageId() 获取页面 ID,ASCF 暂时不支持这个方法。可以用在组件 properties 里传入页面 ID 的方式替代。

接口层面的兼容性差异

has.getClipboardData 在 ASCF 中暂不支持,系统对剪贴板权限管控较严格。如果元服务需要读取剪贴板内容(比如自动填充验证码),目前无法实现,只能等后续版本支持。

has.getAccountInfoSync 获取不到 appId 时,可以从 AppScope/app.json5 的 bundleName 里获取。
  1. // 替代方案
  2. const appConfig = require('../../AppScope/app.json5');
  3. const appId = appConfig.app.bundleName;
复制代码

权限差异是最容易踩坑的地方。

addPhoneContact 不需要授权

小程序里调用 addPhoneContact 需要先申请 scope.addPhoneContact 权限,但 ASCF 中直接调用即可。如果按小程序的习惯先调用 has.authorize,反而会报错说 scope 不存在。
  1. // 小程序里需要这样
  2. wx.authorize({
  3.   scope: 'scope.addPhoneContact',
  4.   success() {
  5.     wx.addPhoneContact({ ... });
  6.   }
  7. });
  8. // ASCF 里直接调用就行
  9. has.addPhoneContact({
  10.   firstName: '张三',
  11.   mobilePhoneNumber: '13800138000',
  12.   success() {
  13.     console.info('添加成功');
  14.   }
  15. });
复制代码

保存到相册不需要授权

has.saveImageToPhotosAlbum 和 has.saveVideoToPhotosAlbum 也不需要 scope.writePhotosAlbum 权限,直接调用即可。
  1. // 直接调用,不需要授权
  2. has.saveImageToPhotosAlbum({
  3.   filePath: '/tmp/test.png',
  4.   success() {
  5.     console.info('保存成功');
  6.   }
  7. });
复制代码

迁移检查清单

从微信小程序迁移到 ASCF,整体改动量不大,核心是文件后缀替换和权限差异。最容易踩坑的是权限部分,有的接口在小程序里需要授权,在 ASCF 里反而不需要。

转换阶段:用 ASCF Converter 批量转换文件后缀和 wx 到 has;压缩源码加 --notaddtodo 避免 TODO 干扰;转换前确认 ascf 目录为空;转换后查看 transform.log 和 _ascfConvertReport 报告定位问题。

手动调整阶段:检查 let 作用域报错;非整型 px(如 0.5px)改为整型;<toast> 组件改为 has.showToast 调用;开源库源码手动拷贝到项目目录;Uniapp/Taro 项目考虑用条件编译直接输出 ASCF。

文件层面:.wxml 改成 .hxml,.wxss 改成 .css,.wxs 改成 .hjs,wx. 改成 has.。

框架层面:检查 tabbar 页面是否在主包;检查分包大小是否超限;检查 getPageId() 调用;检查 constructor 类型判断。

接口层面:getClipboardData 暂不支持需要替代方案;getAccountInfoSync 用 bundleName 替代;废弃接口不支持需要替换。

权限层面:addPhoneContact 不需要授权;saveImageToPhotosAlbum 不需要授权;saveVideoToPhotosAlbum 不需要授权;其他权限保持不变。

如果遇到 ASCF 还没支持的接口,可以发邮件到 atomicservice@huawei.com 反馈,邮件标题格式为 [ASCF框架接口诉求]-[元服务名称]-[APP ID]-[Developer ID]。实际反馈过一次,三个工作日就收到了回复。
回复

使用道具 举报

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

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

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

官方核心成员

关注微信公众号

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

GMT+8, 2026-8-27 14:40 , Processed in 0.020611 second(s), 17 queries , Gzip On, Redis On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部