开发工具: 华为云码道

本文配套仓库: 上游 hizzd/json_viewer;OHOS 适配内容位于本地仓库未提交工作区(ohos/example/ohos/docs/ohos-necessity-evaluation.mddocs/ohos-evidence/lib/json_viewer.dart 空安全化、example/lib/main.dart 与测试重写等)。
鸿蒙适配后仓库https://atomgit.com/oh-flutter/json_viewer

json_viewer 是一个纯 Dart 实现的 JSON 树形展示组件:JsonViewerRoot 接收一个 JSON 对象(Map / List / 基本类型),根据类型递归生成可折叠节点;JsonViewerMapNode 渲染 Map 并支持展开/收起,JsonViewerListNode 渲染 List 并显示长度,JsonViewerNode 渲染叶子节点并按 null / bool / int 着色。平台通道只有一个模板方法 getPlatformVersion,核心渲染逻辑完全不经过原生。本文以 json_viewer 0.0.1 为例,介绍源码准备、OHOS 工程配置、ArkTS 最小实现、example 构建与真机验证。

插件目前支持 ohos 平台,上游源码位于 GitHub 仓库。文中的代码以上游 master 分支的初始提交 03704f0b2b005df5957f8bdb67dfbf9df7ada54e 为适配基线,OHOS 改动以本地未提交工作区形式存在。
在这里插入图片描述

OHOS 改动记录https://atomgit.com/oh-flutter/json_viewer在本地提交 feed9ffd3218574b7cc126ede4d846cf74b70f4c,并按 0.0.1-ohos-1.0.0-beta.1 打 TAG 发布。

在这里插入图片描述


一、插件简介与适配目标

在很多调试或数据展示场景中,需要把后端返回的 JSON 直接以树形结构呈现在 Flutter 页面上。json_viewer 提供了一种零依赖方案:只依赖 Flutter SDK,把一个动态对象递归渲染成可交互的树形节点,并支持通过 expandDeep 控制默认展开层级。

这套核心能力全部由纯 Dart widget 实现(单个 lib/json_viewer.dart 文件,约 345 行),不触碰任何平台 API,天然跨平台一致。插件真正的原生依赖只有一个模板方法:getPlatformVersion 通过 MethodChannel('json_viewer') 查询系统版本。

正因如此,这个插件的 OHOS 适配工作重点不是功能移植,而是:

  1. 把旧版 Dart 代码升级到当前 Flutter OHOS 工具链可编译的空安全语法(JsonNode? parentlate 字段、didUpdateWidget 重新应用 expandDeep 等);
  2. pubspec.yaml 声明 ohos 平台并生成 HAR 模块;
  3. 在 ArkTS 中实现 JsonViewerPlugin,用 deviceInfo.osFullName 返回与 Android/iOS 语义一致的版本字符串;
  4. 重写 example 和测试,使其能在 OHOS 真机上验证 JSON 树的渲染与展开。

获取复制后显示剪贴板内容 获取复制后显示剪贴板内容 获取复制后显示剪贴板内容 获取复制后显示剪贴板内容 获取复制后显示剪贴板内容

操作预期表现
自动展开层级 = 0仅展示根节点[root],全部子节点折叠,仅可点击展开
自动展开层级 = 1自动展开 root 一级子节点(name/description/author/tags 等一级字段),二级及更深节点保持折叠
自动展开层级 = 2自动展开 root、一级子节点,二级节点自动展开;三级及更深节点保持折叠
自动展开层级 = 3自动展开 root、一级、二级节点,三级节点自动展开;四级及更深节点保持折叠
自动展开层级 = 5自动展开 root、一级、二级、三级、四级、五级节点,所有层级全部自动展开
点击已展开节点左侧三角箭头折叠当前节点,隐藏其全部子节点内容
点击已折叠节点左侧三角箭头展开当前节点,展示其直接子节点内容,展开深度遵循全局自动展开层级配置

以下是操作的视屏,可以参考一下:

Example 启动授权 Example 启动授权


二、环境准备

环境搭建参考社区文档:Flutter OH 开发环境搭建,完成 Flutter OH SDK 安装、环境变量和 DevEco Studio 配置。

完成后,在宿主机终端执行以下命令,确认当前选中的是支持 OHOS 的 Flutter 工具链,并能发现目标设备:

flutter --version
flutter doctor -v
hdc list targets

在这里插入图片描述

在这里插入图片描述

编辑用户

工程使用的工具链和 SDK 配置如下:

项目版本或配置用途
Flutter OHOS SDK3.44.9+ohos-0.0.1-canary1Flutter 编译与 OHOS 平台工具链
Flutter 分支0.0.1-ohos-1.0.0-beta.1CPF-Flutter 对应开发分支
Dart SDK3.12.2Dart 语言与包管理环境
HarmonyOS 开发套件26.0.0(API 26)开发套件版本及对应的 API 级别
compatibleSdkVersion5.1.0(18)当前工程声明的最低兼容版本
runtimeOSHarmonyOS真机构建目标运行时
插件版本0.0.1pubspec.yaml 中的包版本
OHOS 发布 TAG(尚未创建)本次适配建议按 0.0.1-ohos-1.0.0-beta.1 发布
原生语言ArkTSHarmonyOS 插件实现
插件产物HAR被应用 entry 模块依赖

注意:当前仓库无已推送的 OHOS 发布 TAG,也未创建 AtomGit 配套仓库;交付前请先补全 LICENSE、创建 TAG 并推送到目标仓库。

2.1 开发套件版本与工程中的 SDK 版本配置

26.0.0(API 26) 涉及 HarmonyOS 开发套件版本(API 版本)及其底座 OpenHarmony 的版本号体系。在本文工程中,相关版本的含义与配置方式如下:

  • 26.0.0(API 26) 表示本机 DevEco Studio 安装的开发套件为 26.0.0,对应 API 26,Flutter 工具链构建时使用该 SDK;
  • 本工程的 example/ohos/build-profile.json5 没有显式声明 compileSdkVersiontargetSdkVersion,构建时按开发套件默认的 API 26 编译;
  • 5.1.0(18) 是本文工程中 compatibleSdkVersion 的属性值,声明最低兼容 API 18;
  • runtimeOSHarmonyOS,说明产物面向 HarmonyOS 真机运行。

对应的 product 配置为:

{
  "name": "default",
  "signingConfig": "default",
  "compatibleSdkVersion": "5.1.0(18)",
  "runtimeOS": "HarmonyOS"
}

在这里插入图片描述

本插件原生侧只用到了 @ohos.deviceInfoosFullName 字段,该能力自 API 7 起即可用,也不需要任何运行时权限,因此 API 18 及以上设备均可运行。本例真机验证环境为 OpenHarmony-6.1.1.120(API 24)。

三、从源码仓库开始准备适配工程

3.1 确认上游源码仓库与同步方式

适配已有第三方插件时,先从 Pub 包信息或项目 README 确认上游地址、包名、版本和许可证。同步仓库时保留源码、许可证和提交历史,方便后续跟踪上游更新。

在 AtomGit 网页的新建仓库流程中,找到从已有仓库导入的入口,填写上游 Git 地址,选择自己有写权限的组织或个人空间,设置目标仓库名称后执行导入。完成后检查目标分支、pubspec.yamlLICENSE 和提交历史是否完整,并记录适配起点的提交号。如果上游本身托管在 AtomGit,也可以通过 Fork 获得自己的工作仓库。

json_viewer 的上游位于 GitHub(仓库名与 Dart 包名均为 json_viewer)。上游 LICENSE 文件内容为 TODO: Add your license here.,尚未选定许可证;适配并发布前必须先与上游确认或自行选择许可证(本项目为纯 Dart 组件,通常可选 MIT/BSD/Apache-2.0 之一)。本仓库目前没有 AtomGit 镜像,也没有 README.OpenHarmony 文档;若后续需要在 AtomGit 发布,应创建配套仓库(社区适配仓库常按 fluttertpc_ 前缀命名)并同步更新安装说明。

3.2 将代码拉取到宿主机

在安装了 Flutter OH 和 DevEco Studio 的开发电脑上打开终端,进入准备存放项目的目录,执行:

git clone https://github.com/hizzd/json_viewer.git
cd json_viewer
pwd
ls
git remote -v
git status --short --branch
git rev-parse HEAD

在这里插入图片描述

git clone 会创建 json_viewer/ 目录;cd 后的位置就是下文所说的插件仓库根目录,这里应能看到 pubspec.yamllib/example/。本仓库的仓库名与 Dart 包名一致,都是 json_viewer,因此后续 --project-name 也传 json_viewer

需要使用与本文相同的代码版本时,切换到以下提交:

git switch --detach 03704f0b2b005df5957f8bdb67dfbf9df7ada54e

该提交即上游 master 分支的初始提交,也是本次 OHOS 适配的基线。适配其他插件时,使用该插件对应版本的 tag 或 commit 作为分支起点。

在这里插入图片描述

图 1:在宿主机终端输入仓库拉取命令。

3.3 在仓库根目录确认分支与发布 TAG

json_viewer 的鸿蒙改动建议基于上游默认分支 master 维护,并在发布时通过 TAG 标记 OHOS 版本。当前仓库状态为:本地 master 领先上游一个未提交的工作区(包含 ohos 平台骨架、example 改造、Dart 空安全化等),尚未生成 TAG。在仓库根目录执行:

git branch --show-current
git tag 0.0.1-ohos-1.0.0-beta.1
git tag -l

本例按仓库现有工作方式直接以 master + TAG 发布:将当前工作区提交后,TAG 0.0.1-ohos-1.0.0-beta.1 指向该提交。如果习惯使用适配分支,也可以先创建 feat/ohos_json_viewer_0.0.1,完成后合并回 master 再打 TAG。

建议先整理提交、剥离本机签名绝对路径,再补充并推送 TAG。

当前工作区仍有未提交文件,发布前请先整理提交并剥离本机签名绝对路径。

请添加图片描述

图 2:在 json_viewer 仓库根目录确认分支与 TAG。

3.4 自动补全 OHOS 适配结构

分支确认后,仍在同一个插件根目录执行结构补全。以下命令适用于尚无 ohos/ 目录的既有 Flutter 平台插件

flutter create --template=plugin --platforms=ohos --project-name json_viewer .
git status --short
git diff -- pubspec.yaml .metadata
  • --template=plugin 指定插件模板。
  • --platforms=ohos 指定需要补全的平台。
  • --project-name json_viewer 使用 Dart 包名,与 pubspec.yaml 中的 name 保持一致。
  • 最后的 . 表示在当前插件目录补全工程,不是另建一层目录。

在上游基线 03704f0 上执行后,git status --short 的输出预期为:

 M .metadata
 M pubspec.yaml
?? ohos/
?? example/ohos/

pubspec.yaml 的变化主要是新增 ohos: pluginClass: JsonViewerPlugin 并提升 environment.sdk>=3.0.0 <4.0.0.metadata 记录了 ohos 平台的创建信息;ohos/example/ohos/ 是新生成的 HAR 脚手架和宿主工程。

还要注意清理模板多余产物:flutter create 会按当前插件模板重建各平台,可能生成 federated 骨架或 web 文件。本仓库的 Dart 层改动主要围绕空安全化,清理后应保留真实业务文件。

如果生成后 example/ohos/ 仍不存在,进入已有示例应用补全平台:

cd example
flutter create --platforms=ohos .
cd ..

请添加图片描述

图 3:在插件根目录输入 OHOS 结构补全命令。

3.5 适配后的项目目录

适配后的关键目录如下:

json_viewer/
├── lib/
│   └── json_viewer.dart               # 对外 API(JsonViewerRoot / JsonViewer*Node)
├── ohos/
│   ├── index.ets
│   ├── oh-package.json5
│   ├── build-profile.json5
│   ├── hvigorfile.ts
│   └── src/main/
│       ├── ets/components/plugin/JsonViewerPlugin.ets
│       └── module.json5
├── example/
│   ├── lib/main.dart                  # 双示例 JSON + 展开层级 Slider
│   ├── test/widget_test.dart          # 渲染与展开断言
│   └── ohos/entry/
├── android/
├── ios/
├── web/
├── docs/
│   ├── ohos-necessity-evaluation.md   # 鸿蒙化必要性评估
│   └── ohos-evidence/                 # 真机截图与日志
└── pubspec.yaml

项目根目录如下,其中包含 ohos/example/ohos/、文档化的 docs/ohos-necessity-evaluation.md,以及归档真机证据的 docs/ohos-evidence/

请添加图片描述

图 4:适配后的 json_viewer 项目根目录。

文件主要职责
lib/json_viewer.dart对外入口:JsonViewerRootJsonViewerMapNodeJsonViewerListNodeJsonViewerNode
JsonViewerPlugin.ets响应 getPlatformVersion,返回系统版本字符串
插件 module.json5声明 HAR 模块
示例 entry module.json5声明宿主 Ability、设备类型和 INTERNET 权限
example/lib/main.dart完整 Demo:双示例 JSON、切换示例、展开层级 Slider
example/test/widget_test.dart渲染断言:节点存在、expandDeep 变化后深层节点出现
docs/ohos-evidence/真机运行截图与日志

四、Dart 接口与通道分析

OHOS 适配前先理清通道契约:这个插件绝大部分逻辑是纯 Dart,唯一经过平台通道的只有模板方法 getPlatformVersion。先阅读 lib/ 的全部文件和 Android/iOS 的原生实现,再在 ohos/src/main/ets/components/plugin/ 中实现对应的原生类。适配其他已有平台的插件时,也应保留其公开接口和其他平台实现。

本例的对应关系如下:

Dart 入口或模型实际依赖OHOS 实现应保持的行为
JsonViewerRoot / JsonViewer*Node纯 Dart无需适配跨平台行为一致
getPlatformVersion(模板方法)插件通道 json_viewerJsonViewerPlugin.ets 返回系统版本返回系统版本字符串

通道名和方法名属于跨语言协议。任何一端拼写不一致,都会让 getPlatformVersion 直接抛出 MissingPluginException

4.1 跨端架构与调用时序

Flutter 侧和 HarmonyOS 侧之间是一条极窄的单向拉取链路,没有事件订阅和平台视图:

  1. 原生链路:Flutter 页面读取平台版本,经 MethodChannel('json_viewer')invokeMethod('getPlatformVersion') 发起一次请求,JsonViewerPlugin.ets 返回系统版本字符串;
  2. 纯 Dart 链路:JSON 解析、节点构造、展开状态、样式着色全部在 Dart isolate 内完成,完全不经过原生,也就不存在跨端差异。
渲染错误: Mermaid 渲染失败: Lexical error on line 9. Unrecognized text. ... NP -.OpenHarmony-x.y.z.w.-> MC MC -----------------------^

插件通道一次调用、一次应答,没有需要取消的订阅。节点展开状态由 StatefulWidgetsetState 局部管理。

4.1.1 一次完整平台版本查询的时序
deviceInfo JsonViewerPlugin.ets JsonViewerRoot Flutter App deviceInfo JsonViewerPlugin.ets JsonViewerRoot Flutter App getPlatformVersion() invokeMethod('getPlatformVersion') try { 命令分发 } deviceInfo.osFullName "OpenHarmony-6.1.1.120" result.success("OpenHarmony-6.1.1.120") Future<String?>

4.2 对外 API 入口:lib/json_viewer.dart

JsonViewerRoot 是唯一对外入口,接收 jsonObjexpandDeep

class JsonViewerRoot extends StatefulWidget {
  JsonViewerRoot({
     this.jsonObj,
    this.expandDeep = 2,
    OnBuildNode? onBuildNode,
  }) {
    this.onBuildNode = onBuildNode ?? this.onBuildNodeDefault;
  }

  final dynamic jsonObj;
  final int expandDeep;
  late OnBuildNode onBuildNode;
}
成员签名行为
jsonObjdynamic要展示的 JSON 对象,支持 Map、List、基本类型与 null
expandDeepint自动展开层级,默认 2;大于 0 时 Map/List 默认展开
onBuildNodeOnBuildNode?自定义节点构造回调;为空时使用默认实现

这是库的核心入口;平台版本查询通常只在示例页展示,业务侧主要使用 JsonViewerRoot。适配中对 onBuildNode 进行了空安全化:JsonNode? parentlate OnBuildNode onBuildNode,并在 onBuildNodeDefault 中给 leftOffset 显式初始化为 0,避免旧代码在非空安全下的编译错误。

4.3 公开 API 与平台接口

公开 API 集中在单个文件,没有 platform_interface 抽象层,也没有 Stream

lib/
└── json_viewer.dart
    ├── JsonViewerRoot           # 根节点(StatefulWidget)
    ├── JsonNode<T>              # 节点抽象接口
    ├── JsonOpenNode             # 可展开节点接口
    ├── JsonViewerMapNode        # Map 节点(折叠/展开)
    ├── JsonViewerMapNodeState   # Map 节点状态(initState/didUpdateWidget)
    ├── JsonViewerListNode       # List 节点(折叠/展开)
    ├── JsonViewerListNodeState  # List 节点状态
    └── JsonViewerNode           # 叶子节点(文本 + 颜色)
公开 API说明
JsonViewerRoot(jsonObj, expandDeep, onBuildNode)根据 JSON 构建树形视图
JsonViewerMapNodeMap 类型节点,点击标题切换展开状态
JsonViewerListNodeList 类型节点,标题右侧显示 [length]
JsonViewerNode叶子节点,null 红色、bool 青色、int 浅绿、其他黑色
  • 构造链路:jsonObjonBuildNodeDefaultJsonViewerMapNode / JsonViewerListNode / JsonViewerNodebuild
  • 展开链路:GestureDetector.onTapsetState(() => isOpen = !isOpen) → 重建子树;
  • didUpdateWidget 中根据新的 expandDeep 重新计算 isOpen,使 Slider 调整层级时节点能立即展开/收起;
  • 颜色语义:与 Flutter material 无关,不依赖平台主题。

pubspec.yaml 中的多端 pluginClass: JsonViewerPlugin 用于原生插件注册。本库没有原生业务逻辑,OHOS 上无需任何原生对应物。

4.4 Dart 通道协议分析

4.4.1 通道名称必须两端完全一致

通道名称三端完全一致,都是 json_viewer

// Android
channel = MethodChannel(registrar.messenger(), "json_viewer")
// iOS
let channel = FlutterMethodChannel(name: "json_viewer", binaryMessenger: registrar.messenger())
// OHOS
this.channel = new MethodChannel(binding.getBinaryMessenger(), "json_viewer");

这是插件唯一的一条通道,OHOS 侧注册时必须与两端拼写一致。

4.4.2 命令处理与返回值模型

命令处理是"一问一答"模型:Dart 侧只调用 getPlatformVersion,原生侧只实现 getPlatformVersion

// Dart(模板测试中的调用)
final String? version = await _channel.invokeMethod('getPlatformVersion');
// OHOS
onMethodCall(call: MethodCall, result: MethodResult): void {
  if (call.method == "getPlatformVersion") {
    this.getPlatformVersion(result)
  } else {
    result.notImplemented()
  }
}

private getPlatformVersion(result: MethodResult): void {
  try {
    const osFullName: string = deviceInfo.osFullName;
    result.success(osFullName)
  } catch (e) {
    result.error("getPlatformVersion_failed", `get platform version error: ${JSON.stringify(e)}`, null)
  }
}

返回值约定:原生侧返回系统版本号字符串,Dart 侧映射为 String?。三端的返回语义一致:

平台返回值示例
Android"Android " + Build.VERSION.RELEASE(如 Android 13.0
iOS"iOS " + UIDevice.current.systemVersion(如 iOS 17.0
OHOSdeviceInfo.osFullName(如 OpenHarmony-6.1.1.120

注意:本仓库 Android/iOS 模板在返回值前加了平台前缀 "Android " / "iOS ",而 OHOS 实现直接返回 osFullName。若示例页需要统一前缀,可在 Dart 层拼接;模板方法本身只需保证返回系统版本字符串即可。未知命令一律 result.notImplemented(),与上游 Android/iOS 行为一致。

4.4.3 解绑与清理

插件没有需要取消的订阅。Engine 解绑时清理通道处理器:

onDetachedFromEngine(binding: FlutterPluginBinding): void {
  try {
    if (this.channel != null) {
      this.channel.setMethodCallHandler(null)
      this.channel = null
    }
  } catch (e) {
    console.error(`[JsonViewerPlugin] onDetachedFromEngine failed: ${JSON.stringify(e)}`)
  }
}

通道上没有需要持久保存的原生状态,getPlatformVersion 是无副作用的同步查询,调用结束即完成全部工作。StatefulWidget 的展开状态由 JsonViewerMapNodeState / JsonViewerListNodeState 在 Widget 销毁时随 Flutter 框架自动释放。

五、补全 OHOS 原生实现与工程配置

5.1 在 JsonViewerPlugin.ets 中实现原生能力

业务使用 JsonViewerRoot 渲染 JSON 树后,原生侧只需返回系统版本字符串;JSON 解析、节点构造、展开状态全部在 Dart 侧完成,原生不参与。

JsonViewerPlugin 只实现 FlutterPluginMethodCallHandler:前者接入 Engine 生命周期,后者组成命令处理链路。不需要 AbilityAware(没有权限弹窗),没有平台视图,也没有事件订阅。

原生插件位于(本库只有一个原生文件):

ohos/src/main/ets/components/plugin/JsonViewerPlugin.ets
5.1.1 引入 Flutter 和 HarmonyOS 能力
import { deviceInfo } from '@kit.BasicServicesKit';
import {
  FlutterPlugin,
  FlutterPluginBinding,
  MethodCall,
  MethodCallHandler,
  MethodChannel,
  MethodResult,
} from '@ohos/flutter_ohos';

其中:

  • FlutterPlugin 负责接入 Flutter Engine 生命周期;
  • MethodChannelMethodCallMethodCallHandlerMethodResult 组成命令处理的完整链路;
  • deviceInfo 是本插件唯一用到的系统能力,提供 osFullName 系统版本字段。

注意导入方式:当前实现使用命名导入 import { deviceInfo } from '@kit.BasicServicesKit',与 json_component 篇的 @ohos.deviceInfo 默认导入不同。这是因为不同 SDK 版本或工具链模板的设备信息能力可能位于 @kit.BasicServicesKit kit 包中,并通过命名导出暴露 deviceInfo。实际编写时应以本机 SDK 能编译通过的声明为准;若编译报错 “Module has no exported member ‘deviceInfo’”,则改用 import deviceInfo from '@ohos.deviceInfo'

5.1.2 连接 Flutter Engine
getUniqueClassName(): string {
  return "JsonViewerPlugin"
}

onAttachedToEngine(binding: FlutterPluginBinding): void {
  try {
    this.channel = new MethodChannel(binding.getBinaryMessenger(), "json_viewer");
    this.channel.setMethodCallHandler(this)
  } catch (e) {
    console.error(`[JsonViewerPlugin] onAttachedToEngine failed: ${JSON.stringify(e)}`)
  }
}

Engine 启动时创建通道并注册处理器,通道名与 Android/iOS 一致。getUniqueClassName 返回类名,供引擎侧的插件管理使用,必须与 pubspec.yaml 中的 pluginClass 一致。

5.1.3 读取系统版本:先查 .d.ts 再写 API

getPlatformVersion 的三端语义都是"系统发布版本号":Android 用 Build.VERSION.RELEASE,iOS 用 UIDevice.current.systemVersion。OHOS 的等价物是设备信息能力中的 osFullName 字段。

这里有一个真实的教训:OpenHarmony 的版本信息字段名需要先从本机 SDK 的类型声明核对,不要凭印象拼字段名。osFullName 在 SDK 中的典型声明如下:

// ohos/sdk/default/openharmony/ets/api/@ohos.deviceInfo.d.ts(节选)
/**
 * Describes the full name of the operating system (OS) version.
 *
 * @syscap SystemCapability.Startup.SystemInfo
 * @since 7
 */
const osFullName: string;

.d.ts 同时确认了两件事:osFullNamestring 类型、自 API 7 起可用(本工程最低兼容 API 18,满足要求)。

当前实现将 deviceInfo.osFullName 原样返回,不在前面加 "OpenHarmony " 前缀。若业务侧需要与 Android/iOS 模板统一显示风格,可在 Dart 层根据 Platform 判断后拼接。

5.1.4 命令处理与异常回传

命令处理把整个方法体包进 try/catch,异常时通过 result.error 回传,避免 Dart 侧的 Future 悬挂:

onMethodCall(call: MethodCall, result: MethodResult): void {
  if (call.method == "getPlatformVersion") {
    this.getPlatformVersion(result)
  } else {
    result.notImplemented()
  }
}

private getPlatformVersion(result: MethodResult): void {
  try {
    const osFullName: string = deviceInfo.osFullName;
    result.success(osFullName)
  } catch (e) {
    result.error("getPlatformVersion_failed", `get platform version error: ${JSON.stringify(e)}`, null)
  }
}
  • 已知命令:返回 deviceInfo.osFullName
  • 未知命令:result.notImplemented(),Dart 侧 invokeMethod 抛出 MissingPluginException,与两端一致;
  • 原生异常:以 getPlatformVersion_failed 为 code 回传错误详情,Dart 侧 invokeMethodPlatformException,调用方可以捕获处理。

上游模板的默认实现没有 try/catch 保护,这里的异常回传是适配时补充的增强项。

5.1.5 三端实现对照

三端实现逐行对照,契约完全一致:

环节Android(Kotlin)iOS(Swift)OHOS(ArkTS)
通道名"json_viewer""json_viewer""json_viewer"
命令getPlatformVersiongetPlatformVersiongetPlatformVersion
版本来源Build.VERSION.RELEASEUIDevice.current.systemVersiondeviceInfo.osFullName
返回值示例"Android 13.0""iOS 17.0""OpenHarmony-6.1.1.120"
未知命令result.notImplemented()result(FlutterMethodNotImplemented)result.notImplemented()
生命周期模板 attach/detach模板 attach/detachonAttachedToEngine / onDetachedFromEngine

业务侧不需要感知平台差异:示例页直接展示 getPlatformVersion 的返回值,同一个页面在 Android/iOS/OHOS 上会分别显示对应平台的版本号。JSON 树渲染则完全在 Dart 侧完成,三端行为一致。

5.1.6 Engine 解绑时释放资源
onDetachedFromEngine(binding: FlutterPluginBinding): void {
  try {
    if (this.channel != null) {
      this.channel.setMethodCallHandler(null)
      this.channel = null
    }
  } catch (e) {
    console.error(`[JsonViewerPlugin] onDetachedFromEngine failed: ${JSON.stringify(e)}`)
  }
}

Flutter Engine 销毁时清理通道 Handler。插件不持有通道之外的原生资源,解绑即完成全部清理。Widget 侧的展开状态由 JsonViewerMapNodeState / JsonViewerListNodeState 随 Widget 生命周期释放。

5.2 声明插件和宿主权限

本插件的原生侧只读取系统版本信息,不申请任何敏感权限,是权限配置最简单的一类插件。

5.2.1 插件 HAR 的权限

插件的 ohos/src/main/module.json5 只声明 HAR 模块信息,不带 requestPermissions

{
  "module": {
    "name": "json_viewer",
    "type": "har",
    "deviceTypes": ["default", "tablet"]
  }
}

权限统一由宿主应用声明,HAR 保持无权限依赖。

5.2.2 应用 entry 的权限

最终安装的是宿主应用。本例的 example/ohos/entry/src/main/module.json5 只保留了模板默认的 INTERNET

"requestPermissions": [
  {"name" :  "ohos.permission.INTERNET"}
]

INTERNET 是 Flutter Debug 模式接入开发工具的常规配置;读取 deviceInfo.osFullName 属于公开系统信息,不需要 user_grant 权限,因此无需 reason / usedScene 等声明。

5.3 注册并导出插件

pubspec.yaml 通过以下配置声明 OHOS 插件类:

flutter:
  plugin:
    platforms:
      ohos:
        pluginClass: JsonViewerPlugin

插件的 ohos/index.ets 需要导出实现:

import JsonViewerPlugin from './src/main/ets/components/plugin/JsonViewerPlugin';
export default JsonViewerPlugin;

执行 flutter pub get 和构建后,Flutter 工具会为应用生成插件注册代码,example/ohos/entry/.../GeneratedPluginRegistrant.ets 中会出现:

import { FlutterEngine, Log } from '@ohos/flutter_ohos';
import JsonViewerPlugin from 'json_viewer';

export class GeneratedPluginRegistrant {
  static registerWith(flutterEngine: FlutterEngine) {
    try {
      flutterEngine.getPlugins()?.add(new JsonViewerPlugin());
    } catch (e) {
      Log.e(TAG, "Tried to register plugins with FlutterEngine failed.");
    }
  }
}

通常不应手工编辑该文件,因为下次构建可能覆盖它。缺少 JsonViewerPlugin 会导致 getPlatformVersion 抛出 MissingPluginException

注册异常的排查步骤见第九节 MissingPluginException

5.4 检查 example 的 OHOS 应用结构

本例的 example/ohos/build-profile.json5 应在 products 中设置版本。下面是需核对的配置片段,请合并到现有工程;其中 signingConfig: "default" 需要与本机配置的签名名称一致,签名材料保留在本地:

{
  "app": {
    "products": [
      {
        "name": "default",
        "signingConfig": "default",
        "compatibleSdkVersion": "5.1.0(18)",
        "runtimeOS": "HarmonyOS"
      }
    ]
  },
  "modules": [
    {
      "name": "entry",
      "srcPath": "./entry",
      "targets": [
        {
          "name": "default",
          "applyToProducts": ["default"]
        }
      ]
    }
  ]
}

配置后,在 DevEco Studio 中执行一次 Sync Project。如果 entry 模块正常识别,Project 视图中会出现 entry,并能打开 entry 模块的签名配置。

宿主 app.json5bundleNamecom.hizzd.json_viewer_example,调试签名 profile 的 bundleName 必须与此一致,否则签名包无法安装。EntryAbility 保持模板原样:本例的演示闭环全部由 Dart 完成,宿主没有注册任何额外通道。

六、补全交付文件并提交适配分支

6.1 除代码外还要补全哪些文件

代码适配完成后,还需要整理安装说明、接口文档、版本记录和开源信息。接收仓库有专用模板时,按其格式填写:

文件应写清楚的内容
README.OpenSource上游名称、源码地址、适配版本或提交、版权及许可证信息;按仓库模板列出第三方依赖
README.md原项目说明、OHOS 支持入口、配套 Demo 和文档链接;保留上游信息
README.OpenHarmony_CN.md简介、安装方式、版本对应关系、环境约束、权限、接口表、示例、已验证范围和遗留问题
README.OpenHarmony.md与中文说明对应的英文文档
CHANGELOG.OpenHarmony.mdOHOS 新增能力、适配版本、兼容限制与测试范围
LICENSE / NOTICE保留上游许可证;NOTICE 按许可证和原项目要求保留或补充
example/README.md依赖方式、运行目录、签名、操作步骤与效果图
pubspec.yamlohos/oh-package.json5核对包名、版本、插件注册、仓库地址、许可证和依赖
.gitignore忽略构建缓存及本机签名材料,不漏提交必要源码和配置

本仓库当前状态特殊:

  1. 上游 LICENSE 文件内容为 TODO: Add your license here.,尚未选定许可证,发布前必须先确定许可证并替换;
  2. README.OpenHarmony_CN.md / README.OpenHarmony.md / CHANGELOG.OpenHarmony.md 文档,只有 docs/ohos-necessity-evaluation.md 评估报告与 docs/ohos-evidence/ 真机证据,发布前需补齐 README/CHANGELOG;
  3. ohos/oh-package.json5license 字段仍是脚手架默认值 Apache-2.0,应与最终选定的上游许可证保持一致;
  4. example/ohos/build-profile.json5 中包含本机调试签名的绝对路径与密钥口令(certpath/profile 指向 ~/.ohos/config/...),正式对外发布前应还原为占位配置,避免泄露本机材料;
  5. 工作区存在大量未提交改动(包括 lib/json_viewer.dart 空安全化、example/lib/main.dart 重写等),发布前需整理为一次或多次清晰提交,并从提交内容中剥离本机签名绝对路径。

6.2 提交前检查

提交前先完成第八节的插件、example 和真机测试,再从根目录检查改动:

git branch --show-current
git diff --check
git status --short
git diff --stat
git diff

检查 diff 中的接口、平台注册和依赖变化,移除本机路径及签名信息,并使文档中的版本和分支与提交内容一致。

6.3 提交并推送适配分支

文档和代码整理完成后,在根目录暂存并提交。文件名按项目实际情况调整(pubspec.lock 是否提交按项目约定;本例 pubspec.lock 未跟踪,可不提交):

git add lib pubspec.yaml .metadata
git add ohos example/ohos example/lib example/test example/pubspec.yaml
git add docs
git diff --cached --check
git diff --cached --stat
git diff --cached
git commit -m "feat: add OpenHarmony platform support"
git tag 0.0.1-ohos-1.0.0-beta.1
git remote -v
git branch --show-current
git push -u origin master
git push origin 0.0.1-ohos-1.0.0-beta.1

本例的基线提交为 03704f0,建议将当前工作区整理为一个适配提交后,再按 0.0.1-ohos-1.0.0-beta.1 打 TAG。DevEco 可能向 example/ohos/build-profile.json5 写入本机签名配置(certpath/profile 等指向本机绝对路径),提交前需要从暂存内容中移除或还原为占位(见 6.1 第 4 条)。推送时,origin 应指向自己有写权限的仓库;上游仓库在 GitHub,无权限直接推送时先推送到自己的镜像,再推送 TAG。

推送后在托管平台发起合并请求,说明上游来源和版本、OHOS 实现范围、依赖及权限、测试环境、操作结果、已知限制,并附 Demo 运行说明或运行图。目标分支和评审流程以接收仓库要求为准。

七、使用根目录 example 演示接入

仓库自带 example/,可以直接用来调试插件和体验 JSON 树形渲染。

7.1 本地适配时使用路径依赖

当前 example/pubspec.yaml 的依赖是:

dependencies:
  flutter:
    sdk: flutter
  cupertino_icons: ^1.0.9
  json_viewer:
    path: ../

../ 相对于 example/pubspec.yaml 指向插件根目录,修改根目录插件后可直接联调。environment.sdk 已从上游的 >=2.0.0-dev.68.0 <3.0.0 提升到 >=3.0.0 <4.0.0,满足当前工具链与空安全语法。

7.2 通过 Git 引入插件

业务应用通过 Git 引入时,将 json_viewerpath 配置替换为下面的 Git 依赖。这里固定到建议的发布 TAG(发布前需先在仓库创建并推送该 TAG):

dependencies:
  flutter:
    sdk: flutter
  json_viewer:
    git:
      url: https://github.com/hizzd/json_viewer.git
      ref: 0.0.1-ohos-1.0.0-beta.1

url 使用实际发布仓库——本仓库 README 直接使用了上游 GitHub 地址。若后续迁移到 AtomGit 发布,请将 url 改为对应的 AtomGit 仓库地址,ref 保持为已推送的 TAG。注意上游 GitHub 仓库的 master 分支当前虽然包含本次适配改动,但直接引用未打 TAG 的版本不利于版本追溯,建议固定到 TAG。

从插件根目录执行:

cd example
flutter pub get
flutter pub deps

检查 example/pubspec.lockjson_viewer 的来源为 git,并核对 urlrefresolved-ref。同时检查没有 dependency_overridespubspec_overrides.yaml 将其覆盖回本地依赖,确认应用使用的是 Git 依赖。

7.3 调用接口实现 JSON 树形渲染

仓库中的 example/lib/main.dart 已经是一个完整的演示页,包含两份示例 JSON 与一个展开层级 Slider:

JsonViewerRoot(
  jsonObj: _samples[_sampleIndex],
  expandDeep: _expandDeep,
)

最小接入代码如下:

import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:json_viewer/json_viewer.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: SingleChildScrollView(
          child: JsonViewerRoot(
            jsonObj: json.decode('{"name":"json_viewer","version":"0.0.1"}'),
            expandDeep: 2,
          ),
        ),
      ),
    );
  }
}

完整 Demo 在此基础上增加了:

  • 示例一:项目档案类 JSON,覆盖嵌套 Map、List、null、bool、int、double、空容器;
  • 示例二:设备配置类 JSON,验证深层嵌套与更多数据类型;
  • AppBar 操作:切换示例数据;
  • Slider:实时调整 expandDeep,验证 didUpdateWidget 重新应用展开状态。

7.4 页面退出时的资源处理

JsonViewerRoot 本身不持有需要释放的原生资源;页面退出时的资源处理主要在 Flutter 框架与业务 Widget 中完成:

  • JsonViewerMapNodeState / JsonViewerListNodeState 的展开状态 isOpen 是 Widget 状态,页面销毁时由 Flutter 框架自动回收;
  • 业务页面如果持有 ScrollController 等,应在 dispose 中统一释放;
  • 异步回调中的 setState 前检查 mounted,避免页面已销毁后更新状态;
  • 原生侧没有订阅和缓存资源,onDetachedFromEngine 只清理通道 Handler。

因此业务侧只需按常规 Flutter 页面管理资源即可,无需为 OHOS 做额外清理。

八、验证、构建与鸿蒙设备运行效果

8.1 分别验证插件与 example

从插件仓库根目录执行:

flutter pub get
flutter analyze
flutter test
cd example
flutter pub get
flutter analyze

本仓库当前的 flutter analyze 报告 7 条问题,但全部来自上游代码风格,与 OHOS 原生适配无关:

  • JsonViewerRoot.onBuildNode / JsonOpenNode.isOpen / JsonViewerMapNode 各字段 / JsonViewerListNode 各字段 / JsonViewerNode 各字段:must_be_immutable 警告,原因是这些类继承 Widget 但字段未声明为 final
  • pubspec.yaml:4:1The 'author' field is no longer used and can be removed

这些问题是上游 2019 年旧代码的风格遗留,不影响运行。由于适配原则是核心 Dart 渲染逻辑保持原貌,这些告警原样保留;接入方如需清理,建议先与上游沟通,或自行将字段改为 final/重构状态管理。

example/test/widget_test.dart 已改写为渲染断言:

  • 验证 "name""json_viewer""flutter" 等节点文本存在;
  • 验证拖动 Slider 增大 expandDeep 后深层节点 "since" 出现。

实测结果:flutter test 在 example 目录下 2 个用例全部通过。Dart 测试只能覆盖渲染与通道封装,getPlatformVersion 的真实返回和真机渲染还需要在鸿蒙设备上验证。

8.2 确认设备连接

hdc list targets
flutter devices

设备首次连接电脑时,需要在手机端确认调试授权。列表为空时,检查 USB 连接、调试模式和电脑授权。

8.3 配置签名

真机安装的 HAP 通常需要有效签名。推荐使用 DevEco Studio 为 entry 模块配置自动签名:

  1. 用 DevEco Studio 打开 example/ohos,不是仓库根目录;
  2. 等待工程 Sync 成功,确认 Project 视图中存在 entry 模块;
  3. 打开 File > Project Structure > Signing Configs
  4. default product 选择或生成签名;
  5. 确认设备、应用包名、证书和 Profile 匹配;
  6. 再回到终端执行 Flutter 构建或运行。

签名材料保存在本机,公开仓库中只保留构建所需的通用配置。

8.4 运行示例

以下命令在 example/ 目录执行,将 <device-id> 替换为设备列表中的实际 ID:

flutter run -d <device-id>

也可以先构建 HAP:

flutter build hap --debug

典型产物位于:

example/build/ohos/hap/

本例真机构建记录:Hvigor assembleHap 任务完成,产物为 entry-default-signed.hap。真机安装应选择与当前设备匹配的已签名产物。构建失败时按第九节的检查项排查签名与 SDK 配置后重试。

8.5 在设备上测试 JSON 树展开与切换

  1. 安装并启动应用,确认首页显示 json_viewer example(示例 1/2) 标题;
  2. 默认 expandDeep = 2,查看 Map/List 默认展开到第 2 层;
  3. 拖动 Slider 到 4/5,确认深层节点(如 "since""city""coords")展开;
  4. 点击节点标题,确认 Map/List 能正常折叠/展开;
  5. 点击 AppBar 切换按钮,切换到示例二,确认设备配置类 JSON 正确渲染;
  6. 观察叶子节点颜色:null 红色、bool 青色、int 浅绿、其他黑色;
  7. 与 Android/iOS 设备上相同 JSON 的输出对比,确认渲染结果一致(纯 Dart 实现保证跨平台一致)。

本例验证设备为 OpenHarmony-6.1.1.120(API 24),安装与启动日志节选:

FlutterEngineCxnRegistry --> Adding plugin: JsonViewerPlugin
...
start ability successfully.

8.6 鸿蒙设备运行效果

完成适配后,Flutter 应用可以在 OHOS 页面上完成 JSON 树形渲染节点折叠/展开展开层级动态调整

真机运行截图(OpenHarmony-6.1.1.120)与验证记录:


获取复制后显示剪贴板内容 获取复制后显示剪贴板内容 获取复制后显示剪贴板内容

操作预期表现
自动展开层级 = 0仅展示根节点[root],全部子节点折叠,仅可点击展开
自动展开层级 = 1自动展开 root 一级子节点(name/description/author/tags 等一级字段),二级及更深节点保持折叠
自动展开层级 = 2自动展开 root、一级子节点,二级节点自动展开;三级及更深节点保持折叠
自动展开层级 = 3自动展开 root、一级、二级节点,三级节点自动展开;四级及更深节点保持折叠
自动展开层级 = 5自动展开 root、一级、二级、三级、四级、五级节点,所有层级全部自动展开
点击已展开节点左侧三角箭头折叠当前节点,隐藏其全部子节点内容
点击已折叠节点左侧三角箭头展开当前节点,展示其直接子节点内容,展开深度遵循全局自动展开层级配置

首次编译真机时遇到的 FormatException。截图显示错误定位到 "version": 0.0.1,0.0.1 未加引号)。原因是 example 中某版 JSON 把版本号写成了未加引号的 0.0.1,而 JSON 不允许数字含多个小数点;修复为 "version": "0.0.1", 后应用正常启动。这个踩坑说明:即使是纯 Dart widget,example 里的硬编码 JSON 也要严格校验。*

获取复制后显示剪贴板内容 获取复制后显示剪贴板内容

图 6:应用正常运行后展示示例一的 JSON 树形结构。

Example 启动授权 Example 启动授权

图 7:拖动 Slider 将 expandDeep 调整到 4,深层节点全部展开。

操作预期表现
启动应用标题、示例数据与树形节点自上而下正常渲染
默认展开层级 2Map/List 默认展开到第 2 层
拖动 Slider展开层级实时变化,深层节点出现/收起
点击节点标题Map/List 正常折叠/展开
切换示例示例二的设备配置 JSON 正确渲染
颜色区分null 红、bool 青、int 浅绿、其他黑

运行日志(节选,归档于 docs/ohos-evidence/hilog-raw.txtplugin-register.log)显示 JsonViewerPlugin 已被正确注册,应用进程稳定运行无崩溃。该插件不依赖特殊系统能力,API 18 及以上设备均可运行。

九、FAQ:适配过程与使用问题

9.1 Missing SDK components

典型错误如下:

Missing SDK components. SDK path: ...,
missing components: toolchains,ets,js,native,previewer.

这个错误发生在 Hvigor 同步阶段。通常需要检查构建工具使用的 SDK 路径、组件是否完整,以及 Hvigor 与 SDK 的版本是否匹配。

处理顺序:

  1. 在 DevEco Studio SDK Manager 中确认 API 26 组件已经下载完整;
  2. 检查 Flutter 和 DevEco Studio 使用的 SDK 路径是否一致;
  3. 避免误用 /Applications/DevEco-Studio.app/Contents/sdk 之类的不完整目录;
  4. 确认 SDK 根目录下存在 toolchainsetsjsnativepreviewer
  5. 执行 flutter config --ohos-sdk <正确路径>
  6. 重新执行 flutter doctor -v 和 DevEco Studio Sync。
为什么连接 API 24 手机仍然会报这个错误?

因为 Sync 和 Compile 首先读取 Mac 本地 SDK。手机 API 版本只在部署、安装和运行时参与兼容判断。即使完全不连接手机,本地 SDK 不完整时也会得到相同错误。

当前工程的 compatibleSdkVersion 是 API 18,因此 API 24 在安装版本门槛上是满足的;但设备还必须满足签名要求;本插件不依赖特殊系统能力或权限。

9.2 DevEco Studio 中看不到 entry 模块

插件的 ohos/ 目录是 HAR 模块,可安装应用的 entry 模块位于 example/ohos/entry

请直接使用 DevEco Studio 打开:

json_viewer/example/ohos

如果仍看不到 entry,先解决 SDK Sync 错误,再检查 example/ohos/build-profile.json5modules 是否包含 ./entry。同步失败时,Project Structure 无法正确解析模块,签名界面也可能不显示 entry。

9.3 无法手动签名

签名配置依附于可构建的应用模块和 product。只有 HAR 插件模块、工程 Sync 失败,或者打开了错误目录时,DevEco Studio 都可能无法提供 entry 签名入口。

建议先确认:

  • 打开的是 example/ohos
  • SDK 组件完整并且 Sync 成功;
  • entry 的模块类型为 entry
  • default product 和 target 已正确关联;
  • 当前账号、证书和调试设备状态有效。

9.4 能安装但 JSON 不渲染或抛 FormatException

JSON 树不渲染或抛出 FormatException 时按以下顺序检查:

  1. 传给 JsonViewerRoot.jsonObj 的对象是否已通过 json.decode() 解析为 Dart 对象;直接传 JSON 字符串会报错;
  2. JSON 字符串本身是否合法,特别是数字、null、布尔值是否使用了正确的 JSON 语法;
  3. 是否在 setState 后传入了新的 jsonObj 但没有触发 Widget 重建;
  4. 查看日志中的异常栈,定位具体失败位置。

真实踩坑:本仓库 example 首次真机运行时出现 FormatException: Unexpected character (at line 4, character 17) "version": 0.0.1,,就是因为 0.0.1 未加引号。JSON 字符串中版本号应写作 "0.0.1"

9.5 MissingPluginException

这通常表示 Dart 通道找不到已注册的原生插件。新增原生插件后需要重新构建应用。从仓库根目录执行:

cd example
flutter clean
flutter pub get
flutter run -d <device-id>

如果仍然出现,检查自动生成的插件注册文件中是否包含 JsonViewerPlugin,同时核对 pubspec.yamlohos/index.etsoh-package.json5

9.6 Map/List 节点无法折叠或 expandDeep 不生效

现象:Map/List 节点无法折叠或展开。

原因与排查:

  1. JsonViewerMapNode / JsonViewerListNode 是否正确继承了 StatefulWidget 并实现了 JsonOpenNode
  2. State 中是否正确处理了 GestureDetector.onTap 并调用 setState(() => widget.isOpen = !widget.isOpen)
  3. expandDeep 变化时是否通过 didUpdateWidget 重新计算 isOpen,否则 Slider 调整层级不会生效。

当前适配在 JsonViewerMapNodeState / JsonViewerListNodeState 中补充了 didUpdateWidget,修复了旧代码中调整 expandDeep 不生效的问题。

9.7 flutter analyze / flutter test 报错

flutter analyzeflutter test 报错时,先确认错误来源:

  • 如果错误是 must_be_immutable,来自 JsonViewerRoot / JsonViewerMapNode / JsonViewerListNode / JsonViewerNode 的字段未声明为 final,这是上游代码风格问题,不影响运行;
  • 如果错误是 pubspec.yamlauthor 字段已弃用,也是上游模板遗留;
  • 如果是 ArkTS 编译错误,优先检查 deviceInfo 的导入方式与字段名是否与本机 SDK 声明一致。

修复建议:发布前可选择性重构状态管理(用 final 字段 + 构造函数初始化)以消除 must_be_immutable,但需保持公开 API 不变。

9.8 flutter create 不认识 ohos,或包名不合法

先执行 flutter --version,确认使用的是 OHOS 版工具链,环境配置回到第二节的社区链接核对。包名报错时,确认当前目录包含目标插件的 pubspec.yaml,并显式传入 --project-name json_viewer(本仓库包名与仓库名一致)。

如果报错与 Xcode 相关,参见 9.11。

9.9 Git 依赖提示找不到 TAG 或仓库

先检查 url 是否指向已包含 OHOS 适配的仓库,并确认 ref 写的是已推送的 TAG(如 0.0.1-ohos-1.0.0-beta.1)。TAG 未推送时 Git 依赖会解析失败;分支未包含 ohos/ 目录时构建也会失败。私有仓库还需在本机配置 Git 认证。

本仓库 README 直接使用 GitHub 地址,因此 url 应写 https://github.com/hizzd/json_viewer.git。若后续改用 AtomGit 发布,请同步替换为对应仓库地址。

9.10 改了本地 ArkTS,Demo 为什么没变化

现象:修改了 JsonViewerPlugin.ets 或 example 的 ArkTS 代码,重新构建后 Demo 行为没有变化。

常见原因与排查:

  1. 未执行 flutter pub get 重新生成插件注册代码,导致 GeneratedPluginRegistrant.ets 还是旧版本;
  2. example/ohos/build-profile.json5 中的签名 bundleName 与 AppScope/app.json5bundleName(本例为 com.hizzd.json_viewer_example)不一致,导致安装的是旧签名包;
  3. 设备上已安装同名 bundle 的旧版本,需先卸载再安装;
  4. 模板清理不彻底,ohos/example/ohos/ 中残留 probe 命名的包名或 bundleName,与实际项目不一致。

建议每次修改原生代码后执行 flutter clean + flutter pub get + flutter build hap --debug,并核对日志中安装的 bundleName。

9.11 flutter create 在本机崩溃(xcodebuild 退出码 64)

现象:在插件根目录执行 flutter create --template=plugin --platforms=ohos . 直接崩溃,日志中出现 xcodebuild -list -skipPackageUpdates ... 且退出码 64。

原因:本机 Xcode 13.2.1 过旧,不认识 -skipPackageUpdates 参数;而工程中存在 example/ios 时,Flutter 工具生成前会探测既有 iOS 工程,触发该调用。

处理方式任选其一:

  1. 在干净目录生成 ohos 模板后再整体拷贝 ohos/example/ohos/ 到仓库;
  2. 临时把 ios/example/ios/ 移出仓库,生成 ohos 平台后再恢复;
  3. 升级 Xcode 到支持该参数的版本。

相关链接

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐