Flutter 鸿蒙实战:用三方库接入小艺语音指令与智能体,跑通 Skill 声明到操作闭环

示例仓库:https://atomgit.com/dijun_520/flutter_ohos_ai_agent

社区引导:框架源码与版本发布见 https://atomgit.com/CPF-Flutter/flutter_flutter/tree/oh-3.41.9-release

CPF-Flutter 鸿蒙社区:https://atomgit.com/CPF-Flutter


项目版本
开发工具DevEco Studio 26.0(内置 SDK:DevEco Studio/sdk)
系统 APIHarmonyOS 7.0.0 / API 26(compatibleSdkVersion: 26.0.0)
Flutter3.41.9
实测设备华为(nova 14)

全文基于 flutter_ohos_ai_agent 三方库 + 随声记 示例 App,包括最关键的:Flutter 页面一键调起小艺智能体对话面板。

一、痛点:跨端框架对接鸿蒙系统 AI 能力:痛点不在框架,而在系统 Kit 碎片化与环境隔离

跨端框架接鸿蒙系统 AI 能力,痛点与框架无关:

  1. 能力是碎片化的。语音识别在 CoreSpeechKit,语音合成在 textToSpeech,智能体在 AgentFrameworkKit,意图在 Intents Kit / InsightIntent,技能声明在 SkillSkill 体系。一个「语音指令 → 操作」闭环要横跨四五个 Kit。
  2. 能力是有条件的。AgentFrameworkKit 依赖 agentKitHsp,模拟器上没有;小艺 bundle 对三方是不可读的(GET_BUNDLE_INFO_PRIVILEGED);意图回传要 API 23+。能力探测本身就是一个需要设计的功能。
  3. 跨端框架只管渲染,不管系统能力。Flutter 引擎跑在 ArkUI 之上,但 FunctionComponent(智能体官方组件)只能活在 ArkUI 页面里;Flutter 渲染树里塞不进它。
  4. 真机与模拟器是两个世界。模拟器缺 agentKitHsp、没麦克风;真机有全量能力,但安装需要华为签发的调试证书。两端的行为差异必须在库里抹平。

跨端框架接入鸿蒙系统 AI,瓶颈不在框架本身:鸿蒙 AI 相关能力分散在多个独立 Kit 中,一条语音指令链路就要串联多个套件;各类 AI 能力还有版本、依赖、权限限制,需要专门做能力探测;跨端引擎只负责渲染,原生智能组件无法嵌入 Flutter/RN 渲染树;同时模拟器和真机环境差异巨大,依赖包、硬件、证书条件不一致,适配层需要抹平两边行为。

Flutter 鸿蒙(flutter_ohos)的三方插件体系给一个干净的落点:把系统能力封装成 plugin,Dart 侧拿到的就是一个纯 Dart API。应用开发者不需要知道 AgentFrameworkKit 是懒加载的、不需要知道小艺深链怎么拼——AIAgent.openAgent() 一行搞定。


二、效果先行:两端实测

模拟器:能力探测 + 文本指令闭环

模拟器没有 agentKitHsp 和麦克风,库的能力探测如实降级:

模拟器能力探测

点示例句 chip,走「文本兜底 → 匹配 → 执行 → 状态回写」:

  • add-expense · 1.00 · 2ms,「午餐花了三十五块」→ 餐饮 ¥35,中文数字正确解析成 35;
  • 「今天花了多少」→ query-today,TTS 朗读「今天一共花了 61 元……」;
  • 「撤销上一笔」→ undo-last,账单回滚。

真机:全绿能力面板

HUAWEI TLR-AL00(API 26)上,能力面板全绿:

真机能力探测

逐项含义:

探测项真机结果依据
API26 · TLR-AL00deviceInfo.sdkApiVersion
AgentKit✓ AgentFrameworkKitcanIUse('SystemCapability.AI.Agent.AgentKit')
语音识别✓ CoreSpeechKitSystemCapability.AI.SpeechRecognizer
语音合成✓ textToSpeechSystemCapability.AI.TextToSpeech
结果回传✓ API 23+insightIntentProvider 可用
小艺✓ 链路可达canOpenLink('vassistant://voice/main')
已声明 Skill✓ add-expense@1.0.0skillManager.getSkillInfosForSelf()

真机:语音闭环实测

文本 chip 命中 add-expense · 1.00 · 9ms;「按住说话」后 CoreSpeechKit 真实起会话,事件日志出现两次「识别开始,请说指令」;TTS 朗读账单汇总。整条链路的延迟在个位数毫秒级(本地匹配),语音部分的耗时取决于说话本身。

真机语音闭环

真机:Flutter 一键调起小艺智能体

这是本次最重要的一张图。点「调起智能体」后:

  1. 插件 openAgent 走第一优先级路径:startAbility 到宿主的 AgentHostAbility 承载页(hilog:openAgent via=host ability=AgentHostAbility agentId=com.example.flutter_ohos_ai_agent_example.LedgerAgent);
  2. 承载页渲染 AgentFrameworkKit 官方 FunctionComponent;
  3. 点击「小艺」入口,小艺语音面板从页面底部弹出(「点击或按住说话」);
  4. 事件流回抛 agentDialogOpened,Dart 侧事件日志记录「智能体弹层 opened」。

小艺智能体弹层

完整的调用链是:

Flutter(Dart) → MethodChannel → ArkTS 插件 → startAbility(AgentHostAbility)
             → ArkUI 承载页 → FunctionComponent → 小艺语音面板
                                  ↑ agentDialogOpened 事件原路回抛 ↑

这就是「三方库 ↔ 小艺」双向互通的形态:出向由库拉起小艺,入向小艺侧的对话事件通过 EventChannel 回到 Flutter。对话框内加载具体智能体卡片,需要 agentId 在小艺开放平台完成注册(见第六节)。

真机事件日志

三、原理:小艺能力全景与 Flutter 的桥接姿势

3.1 四块能力的分工

能力Kit我们的用法
端侧语音识别CoreSpeechKit(speechRecognizer)「按住说话」,实时回抛中间/最终文本
端侧语音合成CoreSpeechKit(textToSpeech)朗读执行结果(「记下了,餐饮 35 元」)
智能体调起AgentFrameworkKit(FunctionComponent)承载页 + 官方组件,弹出小艺面板
意图接入Skill 体系 + InsightIntent小艺入口能「找到」应用;系统意图路由回 App

外加一个纯 Dart 的本地意图匹配器(三路加权 + 中文数字槽位),让「不经过云端」的语音闭环也能成立——这是示例 App 真正执行操作的地方。

3.2 两条硬边界

  1. AgentFrameworkKit 没有「命令式打开智能体」的 API。唯一的拉起入口是 ArkUI 组件 FunctionComponent,而 Flutter 渲染不了 ArkUI 组件——所以必须有一个 ArkUI 承载页做跳板。这是 Flutter 与 RN 在这一环节的本质差异:RN 版可以用 TurboModule 起一个ArkUI 页面,Flutter 版一样要起,只是发起方从 JS bridge 换成了 MethodChannel。
  2. agentId 是云侧资产。FunctionComponent 只负责渲染与对话通道,智能体卡片来自小艺开放平台。没注册的 agentId 不会报错,但面板里是空的(本文示例即如此)。

3.3 Flutter OHOS 插件的桥接链路

RN 版的桥是「TS spec + 手写 C++ 方法表(免 codegen)」;Flutter 版标准姿势简单得多:

  • MethodChannel(flutter_ohos_ai_agent/methods):请求-响应,13 个方法一个 switch 搞定;
  • EventChannel(flutter_ohos_ai_agent/events):单通道 + kind 区分(voice / intent / agentDialog),Dart 侧只广播一个 Stream<AIAgentEvent>;
  • 编解码由 StandardMethodCodec 约定,没有任何生成步骤。

一个必须建立的心智模型:ArkTS 侧的普通对象经 StandardMethodCodec 到 Dart 后是 Map<Object?, Object?>。所有模型类都从 Map 还原、字段级兜底,绝不让一个字段打死整张卡片:

factory AgentCapability.fromMap(Object? raw) {
  final m = raw is Map ? raw : const {};
  bool b(String k) => m[k] == true;
  return AgentCapability(
    agentKitAvailable: b('agentKitAvailable'),
    speechRecognizerAvailable: b('speechRecognizerAvailable'),
    // …
    skills: (m['skills'] as List? ?? const [])
        .whereType<Map>()
        .map(SkillDescriptor.fromMap)
        .toList(),
  );
}

四、核心实现:

4.1 库结构总览

flutter_ohos_ai_agent/
├── lib/
│   ├── flutter_ohos_ai_agent.dart      # 出口:export + 常量
│   └── src/
│       ├── models.dart                 # 通道数据模型(ArkTS ↔ Dart 一一对应)
│       ├── skill_registry.dart         # 本地意图匹配:三路加权 + 中文数字
│       ├── ai_agent.dart               # 门面:MethodChannel + EventChannel
│       └── ai_agent_controller.dart    # ChangeNotifier 状态机(Flutter 版 useAIAgent)
├── ohos/
│   └── src/main/ets/components/plugin/
│       ├── FlutterOhosAiAgentPlugin.ets # 主插件:通道 + 探测 + ASR/TTS + openAgent
│       └── AgentFeature.ets             # AgentFrameworkKit 薄封装(动态 import 懒加载)
├── example/
│   ├── lib/main.dart                    # 随声记:语音记账示例
│   └── ohos/entry/
│       ├── skills/add-expense/          # 小艺 Skill 声明(SKILL.md + 脚本)
│       └── src/main/
│           ├── module.json5             # 权限/querySchemes/意图 metadata/承载页
│           ├── ets/pages/AgentHost.ets  # 智能体承载页(FunctionComponent)
│           ├── ets/entryability/AgentHostAbility.ets
│           └── ets/intents/AddExpenseIntentExecutor.ets
└── scripts/oh_run.sh                    # 一键构建 + 签名 + 安装 + 启动

4.2 通道契约:

ArkTS 侧 onMethodCall 就是一张明牌:

async onMethodCall(call: MethodCall, result: MethodResult): Promise<void> {
  try {
    switch (call.method) {
      case 'detect':          result.success(await this.detect()); break;
      case 'listSkills':      result.success(await this.listSkills()); break;
      case 'getAgentCard':    result.success(await this.getAgentCard()); break;
      case 'startListening':  await this.startListening(this.parseListenOptions(call)); result.success(null); break;
      case 'stopListening':   await this.stopListening(); result.success(null); break;
      case 'cancelListening': await this.cancelListening(); result.success(null); break;
      case 'isAgentSupported': result.success(await this.isAgentSupported(call.argument('agentId') as string ?? '')); break;
      case 'openAgent':       result.success(await this.openAgent(call.argument('optionsJson') as string ?? '{}')); break;
      case 'speak':           await this.speak(call.argument('text') as string ?? ''); result.success(null); break;
      case 'shareIntent':     await this.shareIntent(call.argument('intentJson') as string ?? '{}'); break;
      case 'completeIntent':  await this.completeIntent(call.argument('instanceId') as number ?? 0,
                                                        call.argument('resultJson') as string ?? '{}'); break;
      default: result.notImplemented();
    }
  } catch (e) {
    // 业务错误统一按 PlatformException(code=aiAgent) 回给 Dart,不撕裂成原生异常
    result.error('aiAgent', message, null);
  }
}

事件统一走一条 EventChannel,kind 区分:语音事件(start/result/vadBegin/vadEnd/error/complete)、系统意图(intent)、智能体弹层(agentDialog)。Dart 侧:

Stream<AIAgentEvent> get events {
  _events ??= _eventsChannel.receiveBroadcastStream(null)
      .map(AIAgentEvent.fromMap);
  return _events!;
}

4.3 能力探测:把「能不能用」做成一个方法

private async detect(): Promise<AgentCapability> {
  const apiVersion = deviceInfo.sdkApiVersion;
  const skills = await this.listSkills();
  const xiaoyiInstalled = await this.hasXiaoyi();
  const cap: AgentCapability = {
    agentKitAvailable: this.syscapOk('SystemCapability.AI.Agent.AgentKit'),
    speechRecognizerAvailable: this.syscapOk('SystemCapability.AI.SpeechRecognizer'),
    ttsAvailable: this.syscapOk('SystemCapability.AI.TextToSpeech'),
    intentProviderAvailable: apiVersion >= 23 && this.syscapOk('SystemCapability.AI.InsightIntent'),
    xiaoyiInstalled: xiaoyiInstalled,
    apiVersion: apiVersion,
    deviceModel: deviceInfo.productModel,
    skills: skills,
  };
  return cap;
}

「小艺可达」判定是三档兜底,与 RN 版同一套结论:

  1. getBundleInfo(小艺) —— 真机上必失败(见踩坑 #2);
  2. canOpenLink('vassistant://voice/main') —— 需要宿主声明 querySchemes;
  3. getSkillInfosForSelf() —— 自家 Skill 被技能中心收录即代表 AI 入口可达。

4.4 AgentFrameworkKit 懒加载:别让缺失的 hsp 杀死进程

这是本次最大的坑,值一整节。AgentFeature.ets 顶层 import 了 @kit.AgentFrameworkKit;模拟器没有 agentKitHsp,静态 import 会让进程启动时直接 abort——不是 try/catch 能救的那种,是压根跑不起来。现象是:App 点开即闪退,faultlog 里只有一条 cppcrash。

解法:动态 import 懒加载,把失败窗口收窄到真正用到它的那一次调用:

private async isAgentSupported(agentId: string): Promise<boolean> {
  if (!this.syscapOk(SYSCAP_AGENT_KIT) || agentId === '' || this.ability === null) {
    return false;
  }
  // AgentFrameworkKit 由 agentKitHsp 提供,模拟器等环境可能没有:
  // 顶层静态 import 会让进程在启动时直接 abort,必须动态 import 懒加载
  try {
    const feature = await import('./AgentFeature');
    return await feature.isAgentSupport(this.ability.context, agentId);
  } catch (e) {
    const err = e as BusinessError;
    // hsp 缺失 / 隐私协议未同意(1022400011) / 未登录(1022400012) → 归为「不可用」
    console.warn(`${TAG} isAgentSupport(${agentId}) failed: ${err.code} ${err.message}`);
    return false;
  }
}

同理,承载页(AgentHost.ets)也只在 canIUse('SystemCapability.AI.Agent.AgentKit') 成立时才渲染 FunctionComponent,否则给出文案兜底。

4.5 端侧语音识别与权限

speechRecognizer 是 user_grant 麦克风权限,顺序必须是:先申请权限,再建引擎。不申请权限直接建引擎,只会收到 1002200002,报错文案不含「缺权限」三个字——排查半天是常态。插件里先 requestPermissionsFromUser,再 createEngine,然后把五类回调原样翻译成事件:

engine.setListener({
  onStart:  (sid, msg) => this.emitVoice({ kind: 'start', sessionId: sid }),
  onEvent:  (sid, code, msg) => this.emitVoice({ kind: code === 1 ? 'vadBegin' : 'vadEnd', sessionId: sid }),
  onResult: (sid, result) => this.emitVoice({
    kind: 'result', sessionId: sid,
    result: { sessionId: sid, text: result.result, isFinal: result.isFinal, isLast: result.isLast },
  }),
  onComplete: (sid, msg) => this.emitVoice({ kind: 'complete', sessionId: sid }),
  onError:  (sid, code, msg) => this.emitVoice({ kind: 'error', sessionId: sid, errorCode: code, errorMessage: msg }),
});

Dart 侧 AIAgentController 把 result(isLast=true) 直接喂给 dispatch(utterance)——语音到操作的最后一步是纯 Dart 逻辑,与 RN 版共用同一套匹配器设计。

4.6 本地意图匹配:三路加权 + 中文数字

云端大模型当然能做意图理解,但记账这种高频低复杂度场景,端侧规则匹配是 1ms 级、零成本、可解释的。matchCommand 三路加权:

for (final skill in _registry.values) {
  double score;
  if (skill.examples.any((e) => e == u)) {
    score = 1.0;                                   // ① 示例句精确命中
  } else {
    double bestSim = 0;
    for (final e in skill.examples) {              // ② 编辑距离相似度
      bestSim = max(bestSim, similarity(u, e));
    }
    score = bestSim * 0.6;
    final hits = skill.keywords.where((k) => u.contains(k)).length;
    score += (hits * 0.18).clamp(0.0, 0.9);        // ③ 关键词命中
  }
  // …取最高分,低于阈值返回 null
}

槽位抽取含一个手写中文数字解析器(三十五→35、两百零五→205、三千五百→3500、一万二→12000),并处理口语省略。这里藏过一个真 bug,见踩坑 #9。

4.7 调起智能体:承载页 + 官方组件

AgentFrameworkKit 没有命令式 API,唯一入口是 ArkUI 组件。所以 openAgent 的优先级设计是:

  1. 第 1 条路(真路径):startAbility 到宿主的 AgentHostAbility,由承载页渲染官方组件;
  2. 第 0 条兜底:openLink('vassistant://voice/main') 走系统链接解析;
  3. 深链三连:VoiceAbility + viewData / qiankun action / 纯 ability。
private async openAgent(optionsJson: string): Promise<OpenAgentResult> {
  const opts = JSON.parse(optionsJson) as OpenAgentOptions;
  // …第 1 条路:
  const hostWant: Want = {
    bundleName: selfBundle,
    abilityName: hostAbility,           // 'AgentHostAbility'
    parameters: { 'agentId': agentId, 'queryText': queryText },
  };
  await ability.context.startAbility(hostWant);
  return { opened: true, via: 'host', message: `已打开智能体承载页 ${hostAbility}` };
  // …失败则依次降级 openLink / 深链三连,全部失败时区分 16000001 给出人话
}

承载页只有一件事——把官方组件挂出来:

@Entry
@Component
struct AgentHost {
  @StorageLink('agentHostAgentId') agentId: string = '';
  @StorageLink('agentHostQuery') queryText: string = '';
  private controller: FunctionController = new FunctionController();

  aboutToAppear(): void {
    this.controller.on('agentDialogOpened',
        () => console.info('[AgentHost] dialog opened'));
    this.controller.on('agentDialogClosed',
        () => console.info('[AgentHost] dialog closed'));
  }

  build() {
    Column() {
      Text('随声记 · 智能体') /* … */
      if (canIUse('SystemCapability.AI.Agent.AgentKit') && this.agentId !== '') {
        FunctionComponent({
          agentId: this.agentId,
          options: { queryText: this.queryText, title: '小艺' } as FunctionOptions,
          controller: this.controller,
          onError: (err: BusinessError) =>
            console.error(`[AgentHost] agent error ${err.code} ${err.message}`),
        })
      } else { /* 文案兜底 */ }
    }
  }
}

agentDialogOpened/Closed 事件经 AgentHostAbility 写回 AppStorage/事件流,最终在 Flutter 侧事件日志里显示「智能体弹层 opened」——双向互通的证据链闭合。

4.8 反向桥:系统意图怎么「渡」进 Dart

小艺/技能中心通过 InsightIntent 调起应用时,入口是宿主的意图执行器(UIAbility external ability)。执行器本身在宿主工程里(意图声明必须挂在宿主),但它可以通过插件的静态单例把意图转交回 Dart:

// AddExpenseIntentExecutor.ets(宿主侧,示意)
import FlutterOhosAiAgentPlugin from 'flutter_ohos_ai_agent';

export default class AddExpenseIntentExecutor {
  onExecute(params: Record<string, Object>, callback: AsyncCallback<insightIntentProvider.ExecuteResult>): void {
    FlutterOhosAiAgentPlugin.routeIntent('AddExpense', params)
      .then(() => callback({ code: 0 }))     // Dart 侧稍后用 completeIntent 回填真实结果
      .catch((e: BusinessError) => callback({ code: e.code }));
  }
}

Dart 侧注册处理器:

AIAgent.registerIntentHandler('AddExpense', (invocation, params) async {
  final amount = (params['amount'] as num?)?.toDouble() ?? 0;
  ledger.add(amount);
  await AIAgent.speak('记下了,餐饮 $amount 元');
  return SkillResult.ok({'amount': amount});
});

意图注册的关键在 module.json5:意图 profile 必须以 metadata 挂在 UIAbility 上,否则 profile 就是一份没人读的 JSON:

"metadata": [
  { "name": "ohos.insightIntent.config", "resource": "$profile:insight_intent" }
]

4.9 Skill 声明:让小艺「找得到」应用

skills/add-expense/SKILL.md 声明技能的语义(输入/输出/示例句),打包进 hap 后由系统收录到技能中心。真机上 getSkillInfosForSelf 返回 1 条:add-expense@1.0.0 · system · EntryAbility——这正是能力面板「已声明 Skill ✓」的来源,也是「小艺可达」第三档判定的依据。

4.10 状态机:Flutter 版的 useAIAgent

RN 版暴露 useAIAgent() hook;Flutter 的对等物是 AIAgentController extends ChangeNotifier,内置状态机:

idle → listening(ASR)→ recognizing(拿最终文本)→ matching → executing
     → speaking(TTS)→ idle;任何一步出错 1.2s 后自动回 idle

UI 只需要 AnimatedBuilder(animation: controller) 就能拿到全部状态与事件日志,示例 App 因此很薄。

4.11 一键脚本:模拟器/真机双模式

scripts/oh_run.sh 自动识别签名方式:

  • 工程 build-profile.json5 里配置了 signingConfigs.material(DevEco 自动签名产物)→ 直接用 hvigor 已签名 hap——这是真机唯一可行路径;
  • 否则回退 OpenHarmony SDK 调试证书链本地签名——仅适用模拟器/开发板。
# 模拟器
./scripts/oh_run.sh example debug
# 真机(UDID 自动读取,多设备时用 HDC_TARGET 指定)
HDC_TARGET=<你的设备序列号> ./scripts/oh_run.sh example debug

五、我踩过的坑(每一条都有真实报错)

坑一:静态 import AgentFrameworkKit,模拟器启动即闪退。 模拟器缺 agentKitHsp,顶层 import { … } from '@kit.AgentFrameworkKit' 让进程在启动时直接 abort。faultlog 里只有一条 cppcrash-com.example.flutter_ohos_ai_agent_example-*.log,hilog 里连插件第一行日志都打不出来。修复是动态 import 懒加载(5.2 节)。教训:凡是系统 Kit,先 canIUse 再 import,且 import 必须懒。

坑二:真机查询小艺包信息被拒。 真机日志原文:

[AIAgentFlutter] getBundleInfo(com.huawei.hmos.vassistant) failed: 201 BusinessError 201:
Permission denied. An attempt was made to GetBundleInfo forbidden by permission:
ohos.permission.GET_BUNDLE_INFO_PRIVILEGED.

GET_BUNDLE_INFO_PRIVILEGED 是系统应用专属权限。别把它当「小艺没装」——三档判定因此必需(5.1 节)。

坑三:真机拒收 OpenHarmony 调试签名。 真机 hdc install 原文:

error: failed to install bundle. code:9568257 error: fail to verify pkcs7 file.

HarmonyOS 商用系统只信任华为 AGC 签发的证书链,OpenHarmony 链只对模拟器/开发板有效。解法:DevEco Studio → Project Structure → Signing Configs → Automatically generate signature,一次点击生成 .p12/.cer/.p7b 并写入工程 signingConfigs;profile 与 bundleName、设备 UDID 绑定。验证 profile 覆盖设备:

openssl cms -verify -noverify -inform DER -in <p7b> -out -
# 看输出里 debug-info.device-ids 与 bundle-info.bundle-name

坑四:canOpenLink 报 17700056。 scheme 未在宿主 module.json5 的 querySchemes 声明,深链解析直接拒绝。补上 "querySchemes": ["vassistant"] 才可能返回 true。这个权限模型和 Android 的 <queries> 一个思路:能查谁的 scheme,要自己先声明。

坑五:未配置签名时 flutter build hap 退出码为 1,但产物已生成。 终端提示 请通过DevEco Studio打开ohos工程后配置调试签名…,退出码 1,但 entry-default-unsigned.hap 已经落盘。构建脚本对退出码做了容忍,只认 hap 文件是否存在。教训:Flutter OHOS 工具链的「失败」不总是失败,以产物为准。

坑六:ArkTS 侧对象到 Dart 是 Map<Object?, Object?>。 StandardMethodCodec 把 ArkTS 普通对象解码成 Dart Map,字段类型不匹配就变 null。所有模型类做字段级兜底、列表元素 whereType<Map>() 过滤——绝不让一个字段打死整张卡片。

坑七:ArkTS 严格类型的两处收敛。 agentCards: ESObject[] 在 lint 下过不了,改 Object[];插件字段声明 common.UIAbility 会与注入实例的类型不兼容,直接 import UIAbility from '@ohos.app.ability.UIAbility' 用具体类型。ArkTS 的「严格」不是烦人,是把运行时类型坑提前到编译期。

坑八:意图执行器 import 插件要用默认导出。 import { FlutterOhosAiAgentPlugin } from 'flutter_ohos_ai_agent' 在 ohpm 产物下解析不到,改 import FlutterOhosAiAgentPlugin from 'flutter_ohos_ai_agent' 立刻通过。ohpm 对命名导出的解析规则和 npm 不完全一致,跨包引 ArkTS 类优先默认导出。

坑九:中文数字口语省略。 初版把「一百二」解析成 1(应为 120)、「一万二」解析成 2(应为 12000)。修复是补两条缺省规则:位值后缺省 ×10、万段后缺省 ×10000。排查时的坑外坑:dart run 直跑与 flutter test 环境行为不一致,验证必须放到 flutter test 里做,并用 三十五/一百二/一万二/两百零五/三千五百 五个用例固化。

坑十:麦克风权限不申请,ASR 只报 1002200002,文案不提「权限」二字。先 requestPermissionsFromUser 再 createEngine,顺序焊死在同一个入口里(5.3 节)。

坑十一:热重启时 EventChannel 先 onCancel 再 onListen。 onCancel 里若销毁 ASR/TTS 引擎,二次 listen 后事件全丢。只清引用、不销毁,真正的清理放在 onDetachedFromEngine 之后的引擎销毁里。

坑十二:双设备在线,hdc install 会装错地方。 本机同时在线真机和模拟器,不带 -t 的 install 走默认目标,应用静悄悄装错了设备。所有命令带 -t 是纪律;排查方法也简单:装完 hdc -t <目标> shell bm dump -n <包名> 核对版本,别靠猜。

坑十三:FunctionComponent 只能活在 ArkUI 页面。 Flutter 渲染树塞不进它,这是 Flutter 与纯 ArkUI 应用的本质差异,承载页方案是唯一解(5.5 节)。RN 版可以用 TurboModule 起 ArkUI 页面,Flutter 版一样要起,只是发起方不同。

坑十四:agentId 未注册时,FunctionComponent 不报错但面板无卡片。 onError 安静、面板可对话,很容易误判成「代码写错了」。排查时先确认 agentId 是否已在小艺开放平台注册,再怀疑代码。真机验证时我们的面板就是这种状态:链路全通、卡片为空——这是预期行为,不是 bug。


七、现在怎么用:从 三方库 到依赖

这个工程现在是两层结构:flutter_ohos_ai_agent 是插件本体(Dart API + ArkTS 实现),example(随声记)演示从 Skill 声明到智能体调起的完整宿主配置。

接入自己的 Flutter 鸿蒙工程,四步:

  1. 引入插件:
dependencies:
  flutter_ohos_ai_agent:
    path: /path/to/flutter_ohos_ai_agent
  1. 宿主 module.json5 补四样(示例工程可直接抄):ohos.permission.MICROPHONE 权限、querySchemes: ["vassistant"]、UIAbility 的 ohos.insightIntent.config metadata、AgentHostAbility 承载页。
  2. Dart 侧注册技能(示例句 + 关键词 + 槽位 + handler),UI 挂 AIAgentController。
  3. 需要智能体调起时,在小艺开放平台注册智能体,把 agentId 填进 openAgent()——库与示例都做成了配置项,注册完成后填入即可,代码零改动。

运行示例:

# 真机:先在 DevEco 里给 example/ohos 配一次自动签名,之后全自动
HDC_TARGET=<设备序列号> bash scripts/oh_run.sh example debug

总结:

本文基于 Flutter OHOS 3.41.9、鸿蒙 API 26,落地了 flutter_ohos_ai_agent 三方插件,以「随声记」语音记账 Demo 完整跑通从 Skill 声明、语音交互、意图解析到小艺智能体面板唤起的全链路闭环。

鸿蒙原生AI能力分散在多个独立Kit,同时存在依赖、权限、版本、环境等前置约束,并且官方 FunctionComponent 智能体组件无法嵌入 Flutter 渲染树,这是跨端接入的核心卡点,和 Flutter 框架本身无关。插件的核心思路就是搭建一层 ArkTS 桥接适配层,通过 MethodChannel 处理请求调用、EventChannel 流式回抛语音、意图、智能体弹窗事件,对外收敛成简洁统一的 Dart API,业务侧无需感知底层各个Kit的差异。

为解决模拟器缺少 agentKitHsp 导致启动闪退的致命问题,插件对 AgentFrameworkKit 采用动态懒加载导入;同时实现一套多判据的能力探测逻辑,自动识别当前设备支持的语音识别、TTS、智能体、意图能力,区分模拟器与真机环境做降级兜底。语音链路严格遵循先申请麦克风权限再初始化识别引擎的顺序;本地意图匹配器采用加权策略+中文数字槽位解析,适合记账这类轻量端侧指令场景,延迟低、不依赖云端。

智能体唤起是整套方案的关键:依靠独立的 ArkUI 承载 Ability 承载 FunctionComponent 官方组件,再通过事件回传把弹窗状态同步给 Flutter,打通了 Flutter 页面和小艺面板的双向通信;同时支持 InsightIntent 系统意图路由,小艺技能中心下发的指令可以转发到 Dart 层执行业务逻辑。

相关推荐

RN 鸿蒙安全三方库落地:react-native-digital-shield,密钥不出 TEE,AES-GCM/RSA-JWT 跨端身份打通

本文基于 RNOH 0.84 与 HarmonyOS API 26,自研数字盾库 react-native-digital-shield,把 ArkTS 专属的 HUKS、asset 能力经TurboModule 桥接给 JS:提供 AES-256-GCM 加解密与密钥托管、敏感资产存储、RSA-2048 签发校验 RS256 JWT,并以 JWK 公钥和 HS256 共享密钥实现跨端身份互认,密钥明文始终不出 TEE。文中还复盘 TurboModule 双侧注册、GCM 需拆分 16 字节

白天写代码,晚上追AI大模型,偶尔搞点八卦 开源动态|技术干货|实习机会|生态活动 我负责分享,你负责变强 15

Flutter 修复鸿蒙 WebView Cookie 同名键丢失:离线回读与开发助手复核实录

修复了 Flutter 三方库 webview_cookie_manager 鸿蒙端因同名键误判导致的 Cookie 名称丢失问题,确保业务键如 path、domain 等在回读时正确保留。修复后,模拟器与真机测试均实现四组数据完整恢复,值中多等号也保持不变。补丁已提交至 CPF-Flutter 官方仓库,提升插件在鸿蒙平台的可靠性。

白天写代码,晚上追AI大模型,偶尔搞点八卦 开源动态|技术干货|实习机会|生态活动 我负责分享,你负责变强 25

Flutter 鸿蒙启动图撤销后编译失败:用 DevEco Code 复核三方库修复

本文针对 Flutter 鸿蒙启动图撤销时导致编译失败的问题,修复了 flutter_native_splash_ohos 库在移除启动图时误删仍被引用资源的缺陷。通过保留1×1透明图片并透传自定义模块路径,确保资源引用完整性,使工程可正常构建。修复已提交至官方仓库,支持幂等操作与多场景验证,提升开发体验。

白天写代码,晚上追AI大模型,偶尔搞点八卦 开源动态|技术干货|实习机会|生态活动 我负责分享,你负责变强 38

Flutter 接入鸿蒙 ArkWeb 预初始化:帮助页首开时机与主线程成本实测

为解决Flutter鸿蒙版webview_flutter无法在无视图状态下提前初始化引擎的问题,我在其原生实现中新增可选静态入口initializeWebEngine()。实测表明,在2秒预热窗口下,页面首屏渲染(FCP)耗时从中位数1791ms降至1019ms,显著提升首次打开体验;而在零延迟场景下,总路径耗时略有上升,需权衡预热时机与用户等待成本。该补丁已提交至CPF-Flutter官方仓库,支持社区协作优化。

白天写代码,晚上追AI大模型,偶尔搞点八卦 开源动态|技术干货|实习机会|生态活动 我负责分享,你负责变强 35

Flutter 优化鸿蒙 printing_ohos 多页 PDF 光栅化:原生资源释放与缓冲复用

针对鸿蒙端 printing_ohos 插件存在的页码映射错误与高内存占用问题,本文提出并实现三项优化:修正页码索引映射、引入原生资源分层释放机制、复用像素缓冲区。修复后,第三页显示正确,内存增长显著降低——在模拟器上PSS增量中位数下降65.8%,真机测试下降64.4%。完整补丁已提交至官方仓库,支持社区协作与问题反馈。

白天写代码,晚上追AI大模型,偶尔搞点八卦 开源动态|技术干货|实习机会|生态活动 我负责分享,你负责变强 29

React Native 鸿蒙权限审计实战:让每一项权限都有人认领

本文介绍一款纯 JS 编写的 React Native 鸿蒙权限审计工具,解决权限声明与使用对账难、最小权限集计算矛盾、审核必填字段缺失三大痛点。通过 module.json5 声明、使用台账与源码扫描三路输入对账,自动识别未使用权限、补全 reason/usedScene、生成可粘贴的最小清单,并支持 CI 卡控与风险分评估。工具内核独立,离线运行,兼顾准确性与安全性,助力应用高效通过审核。

白天写代码,晚上追AI大模型,偶尔搞点八卦 开源动态|技术干货|实习机会|生态活动 我负责分享,你负责变强 12

Cordova 鸿蒙 WebView 安全实战:能改的运行时拦,改不了的构建期审

本文通过 cordova-plugin-harmony-webguard 插件,解决 Cordova/HarmonyOS 应用中导航安全、引擎不可修改配置、JS 门面静默降级三大难题。基于运行时策略闸门(onPageStart + JS 预检)与构建期审计 CLI(扫描 MainPage.ets、config.xml 等),实现协议拦截、白名单校验、高危配置阻断,支持 CI 失败退出,将安全基线可视化、可测化,真正落地“能改的运行时拦,改不了的构建期审”。

白天写代码,晚上追AI大模型,偶尔搞点八卦 开源动态|技术干货|实习机会|生态活动 我负责分享,你负责变强 24

Flutter 鸿蒙供应链审计实战:让高危依赖卡在 CI 门口

本文介绍了一个基于纯 Dart CLI 与 Flutter Dashboard 的依赖审计工具,解决鸿蒙工程中三套锁文件(pubspec.lock、oh-package-lock.json5、package-lock.json)统一读取、离线快照与 OSV 在线情报选择、以及高危依赖通过退出码卡在 CI 的问题。工具以锁文件为事实依据,支持离线快照(4 条真实 GHSA)与在线查询,输出 SBOM(CycloneDX 1.5)、Markdown/JSON 报告,并通过退出码实现 CI 阻断,性能秒级

白天写代码,晚上追AI大模型,偶尔搞点八卦 开源动态|技术干货|实习机会|生态活动 我负责分享,你负责变强 116

React Native 鸿蒙端侧 OCR 实战:TurboModule 与纯 TS 引擎的逐字契约

本文以鸿蒙真机上的 React Native 0.84 工程为例,详解三大难题:通过 TurboModule 接入 HarmonyOS Core Vision Kit 实现端侧离线 OCR;规避 Metro 预置头导致的 require 不存在问题;实现 npm 包与 HAR 双形态交付。项目采用 codegen 生成 ArkTS 接口,结合纯 TS 回退引擎,确保跨引擎逐字符一致,并通过 autolinking 支持无缝集成。

白天写代码,晚上追AI大模型,偶尔搞点八卦 开源动态|技术干货|实习机会|生态活动 我负责分享,你负责变强 57

Flutter 鸿蒙端侧 OCR 实战:让文字识别留在设备上

本文通过一个运行在鸿蒙真机上的 Flutter 插件工程,系统解决了三大核心问题:如何统一内存、文件、相册三类输入的识别链路;如何实现与 KMP 版本的 JSON 契约逐字节对齐;以及在系统不提供置信度时如何诚实处理。基于 HarmonyOS Core Vision Kit,插件实现端侧离线 OCR,全程无网络、无权限、无密钥,支持真实小票与截图识别,性能稳定(312~507ms),并通过 35 项单元测试与真机集成验证。

白天写代码,晚上追AI大模型,偶尔搞点八卦 开源动态|技术干货|实习机会|生态活动 我负责分享,你负责变强 144

跨端 RN 鸿蒙碰一碰分享库实战:基于 Share Kit 封装 react-native-ohos-knock-share,实现卡片、文件一碰传

本文介绍基于React Native的鸿蒙碰一碰分享库,解决RN开发者在鸿蒙生态中无法便捷使用Share Kit碰一碰功能的痛点。通过封装NFC/星闪触碰、3秒发送窗口、沙箱文件URI转换等核心逻辑,实现跨设备快速传递链接、文件、图片等内容。支持手机、平板、PC多端适配,提供回环演示与真机实测验证,显著降低接入门槛,提升跨端协作效率。

白天写代码,晚上追AI大模型,偶尔搞点八卦 开源动态|技术干货|实习机会|生态活动 我负责分享,你负责变强 178

React Native 鸿蒙实战:给应用接入小艺语音指令,跑通 Skill 声明到操作闭环

本文介绍如何在 React Native 鸿蒙(RNOH)工程中实现小艺技能闭环,通过开源库 react-native-ohos-ai-agent 封装技能声明、语音指令接收、端侧执行与结果回传全流程。针对三方应用权限限制,精准定位可操作边界,实现“被唤起→执行→反馈”链路贯通。结合五张真机截图验证:技能注册、指令匹配、意图上报、智能体调起及对话层弹出等关键节点均成功,完整打通语音交互闭环,助力应用无需入口即可被用户“叫”到。

白天写代码,晚上追AI大模型,偶尔搞点八卦 开源动态|技术干货|实习机会|生态活动 我负责分享,你负责变强 168

Flutter 鸿蒙实现精准碰一碰分享:tap_share_ohos 三方库打通真机传文件与传卡片

本文针对Flutter在鸿蒙系统上“碰一碰”分享功能缺失的痛点,基于DevEco Studio 26.0、HarmonyOS 7.0 API 26与Flutter 3.41.9实测环境,提出并实现开源库tap_share_ohos。该库封装NFC、Share Kit、权限管理及分布式能力,通过Dart门面层统一接口,利用MethodChannel与BasicMessageChannel对接原生ArkTS逻辑,实现文件与卡片的碰一碰分享。真机测试显示,可无缝调起系统分享面板,支持华为分享接力

白天写代码,晚上追AI大模型,偶尔搞点八卦 开源动态|技术干货|实习机会|生态活动 我负责分享,你负责变强 161

RNOH 原生内存泄漏定位与治理:借助 LeakyGuard 实现图片解码降采样、LRU 字节缓存、资源生命周期管控,长列表图片页面峰值内存优化

本文面向 RNOH 0.84 长列表图片场景,剖析滑动数分钟后进程被系统杀掉的根因:原图解码尺寸失控、缓存按条数限流、PixelMap未显式 release。基于自研LeakyGuar,TurboModule 库,给出 desiredSize 真降采样、字节预算 LRU 缓存(逐出必 release)、资源登记与快照 diff、卸载即释放 Hook 的闭环方案,实测单图内存降 98.6%,24 图峰值由 1098.6MB 降至15.8MB。并总结双侧注册、ArkTS 语法差异、vp 转像

白天写代码,晚上追AI大模型,偶尔搞点八卦 开源动态|技术干货|实习机会|生态活动 我负责分享,你负责变强 232

Flutter 鸿蒙空间音频实战:让音乐播放器的声音“长出方位感“

本文通过一个真实运行的 Flutter 工程,系统解析了在鸿蒙系统上实现空间音频的三大核心问题:基于双耳时间差(ITD)、声级差(ILD)和频谱整形的方位感算法;耳机切换与音频焦点管理;以及播放器与音效的集成。项目使用自研插件 spatial_audio,结合原生 HarmonyOS 接口,实现了跨设备的空间音频体验,支持普通耳机,无需硬件依赖,并提供实时参数反馈与系统状态监听。附带完整代码仓库与实测效果展示,为 Flutter on HarmonyOS 的音频开发提供了可复用的技术方案。

白天写代码,晚上追AI大模型,偶尔搞点八卦 开源动态|技术干货|实习机会|生态活动 我负责分享,你负责变强 282

Flutter 鸿蒙 HiTrace 请求归因:图片压缩等待时,主线程在做什么

为定位鸿蒙平台图片压缩性能瓶颈,我在 flutter_native_image 插件中新增可选的 HiTrace 阶段追踪功能,支持按请求开启解码、缩放、编码与资源释放阶段的耗时分析。通过对比模拟器与真机(华为畅享 100 Pro Max)数据,精准识别出耗时主要集中在解码与编码阶段,显著提升诊断效率。相关代码已提交至官方仓库,助力开发者快速定位性能问题。

白天写代码,晚上追AI大模型,偶尔搞点八卦 开源动态|技术干货|实习机会|生态活动 我负责分享,你负责变强 1万+

Flutter 适配鸿蒙折叠屏铰链角度按需订阅:支架调节页用完即停与重入实测

本文介绍对 Flutter 三方库 dual_screen 的优化:针对支架调节页等短时观察场景,保留原有缓存入口的同时,新增按需订阅机制。通过按需启停监听,实现页面退出后停止原生回调,避免无效数据更新。实测显示,无消费者时原生回调从3条降至0条,重进页面则等待新事件,更符合临时工具页的使用逻辑。完整代码已开源,支持鸿蒙折叠屏角度动态感知,适用于需精准控制生命周期的折叠屏应用开发。

白天写代码,晚上追AI大模型,偶尔搞点八卦 开源动态|技术干货|实习机会|生态活动 我负责分享,你负责变强 1万+

Flutter 适配鸿蒙手表屏幕形状:让计时卡片按圆屏和方屏布局

本文基于 wear_plus 1.2.4 版本,为鸿蒙系统补全屏幕形状查询功能,使 WatchShape 能正确返回 round 等形状信息。通过在原 Dart 接口不变的前提下,新增鸿蒙平台处理器,实现与 Android 一致的异步查询逻辑。对照实验验证:适配后页面可从“查询未接入”变为“圆屏已确认”,日志成功接收系统回执,布局行为保持一致。完整代码开源至 oh-flutter/wear_plus,支持 Flutter 鸿蒙穿戴设备开发。

白天写代码,晚上追AI大模型,偶尔搞点八卦 开源动态|技术干货|实习机会|生态活动 我负责分享,你负责变强 1万+

Flutter 优化鸿蒙剪贴板大图复制卡顿:从主线程同步阻塞到异步文件描述符直解

针对鸿蒙系统下 flutter_image_clipboard 插件复制高清图片时阻塞主线程的问题,本文提出三项优化:异步文件描述符直解、异步剪贴板写入及原生资源逆序释放。实测显示,模拟器事件循环最大间隔从300.32ms降至54.36ms(降幅81.9%),真机上更从133.20ms降至11.20ms(降幅91.59%),显著提升页面响应性。完整代码已开源,支持直接使用与社区交流。

白天写代码,晚上追AI大模型,偶尔搞点八卦 开源动态|技术干货|实习机会|生态活动 我负责分享,你负责变强 1万+

Flutter 三方库 petalmaps_ohos 的 OpenHarmony 适配实战(0 → 1 全记录)

本文详细记录了从零构建 Flutter 三方库 petalmaps_ohos 并适配 OpenHarmony/HarmonyOS 平台的全过程,涵盖项目初始化、原生实现(基于 ArkTS 和 MethodCallHandler)、插件注册、功能验证及升级至 HarmonyOS SDK 26 的关键步骤。重点解析了为何需实现 AbilityAware 获取 UIAbilityContext 以确保地图调起成功,并通过分层架构、枚举封装与兼容性设计,实现功能完整、易用且低维护成本的“调起系”地图插件,

白天写代码,晚上追AI大模型,偶尔搞点八卦 开源动态|技术干货|实习机会|生态活动 我负责分享,你负责变强 59

Flutter 三方库 holding 的 OpenHarmony 适配实战:从 0 到 1 开发一个鸿蒙感知插件

本文详述了从零实现开源 Flutter 插件 holding 并适配 OpenHarmony/HarmonyOS 的全过程。基于鸿蒙专属 MultimodalAwarenessKit,实现握持手与操作手状态感知,覆盖事件流订阅、状态查询及 API 26 新增接口,确保功能一致、性能高效、接口稳定。通过 Dart 层封装、ArkTS 原生桥接、真机验证与单元测试,完成插件工程化落地,并发布至 pub.dev,为同类系统能力插件的鸿蒙化提供可复用的技术路径。

白天写代码,晚上追AI大模型,偶尔搞点八卦 开源动态|技术干货|实习机会|生态活动 我负责分享,你负责变强 28

Flutter 三方库 gesturesshare 从 0 到 1:鸿蒙隔空传送分享插件的开发、升级与发布实战

本文详述了 Flutter for OpenHarmony 三方库 gesturesshare 从零开发到发布全过程:基于 HarmonyOS 隔空传送能力,实现跨设备图片与 App Linking 一键分享。涵盖双端代码设计、API 26 升级、真机验证及 Pub 发布流程,提供 Dart/ArkTS 对照与踩坑复盘。项目填补 Flutter 生态空白,推动鸿蒙多设备交互能力普及,助力开发者快速接入系统级功能。

白天写代码,晚上追AI大模型,偶尔搞点八卦 开源动态|技术干货|实习机会|生态活动 我负责分享,你负责变强 28

Qt 鸿蒙沉浸光感实战:让玻璃的每个像素自己发光

本文通过一个 QML 模块与 Qt for OpenHarmony 构建实践,完整解答了三个核心问题:如何用 81 行 GLSL 实现无图片依赖的动态玻璃材质(含光核漂移、视差、SDF 圆角与颗粒);如何在 Qt Quick 中通过 C++ 控制器实现弹层锚定与翻转;以及如何将 Qt 应用交叉编译并以 HAR 形式部署至鸿蒙系统。项目基于 Qt 5.12.12,利用 ShaderEffect 实现纯渲染级视觉效果,兼顾性能与跨平台兼容性,提供可复用的开源方案。

白天写代码,晚上追AI大模型,偶尔搞点八卦 开源动态|技术干货|实习机会|生态活动 我负责分享,你负责变强 22

开源鸿蒙平台 KMP_CMP 三方库「端侧语音转文字」适配全流程

本项目实现KMP/CMP在OpenHarmony鸿蒙平台的语音转文字(TTS)完整链路适配,通过Kotlin/Native共享模型、C ABI/N-API桥接与ArkTS交互,解决权限、音频格式、生命周期及跨平台契约等难题。支持中文、英文、日文多语言识别,提供统一结果模型与JSON序列化,实测于华为Mate 80 Pro Max模拟器,验证了JVM测试、Native动态库、HAP签名部署及真机识别全流程。项目结构清晰,分六阶段推进,确保代码复用与平台无关性,为KMP在鸿蒙生态落地提供可复用的技术范式。

白天写代码,晚上追AI大模型,偶尔搞点八卦 开源动态|技术干货|实习机会|生态活动 我负责分享,你负责变强 30

开源鸿蒙平台 KMP_CMP 三方库「端侧OCR」新特性适配

本项目实现Kotlin Multiplatform(KMP)在OpenHarmony平台的端侧OCR适配,基于HarmonyOS 7.0 SDK与Compose Multiplatform 1.9.2,成功打通JVM、Kotlin/Native与ArkTS间的数据交互。通过C ABI/N-API桥接层,实现KMP模型与Core Vision Kit识别结果的跨语言共享,支持中、英、日、韩四语识别。

白天写代码,晚上追AI大模型,偶尔搞点八卦 开源动态|技术干货|实习机会|生态活动 我负责分享,你负责变强 13

开源鸿蒙平台 KMP/CMP 三方库「智感握姿」新特性

本项目实现鸿蒙KMP/CMP平台下智感握姿能力的跨端适配,基于Kotlin Multiplatform构建共享状态模型,通过C ABI与ArkTS桥接,支持左手、右手、双手等五种握持状态的稳定传递。项目打通ohosArm64目标、Native动态库构建与DevEco Studio集成链路,提供统一API与真机验证示例,确保状态模型、事件序列与生命周期在多端一致。

白天写代码,晚上追AI大模型,偶尔搞点八卦 开源动态|技术干货|实习机会|生态活动 我负责分享,你负责变强 19

Electron 鸿蒙沉浸光感实战:把玻璃交给操作系统去发光

本文通过一个 Electron 库与 HarmonyOS 三方库,系统解决三大核心问题:跨平台材质路径对齐(macOS vibrancy、Windows acrylic、鸿蒙 backgroundBlurStyle)、菜单子窗口精准定位(坐标转换与工作区适配)、以及无脚本菜单文档的安全事件回传(自定义 URL scheme 与焦点管理)。基于 CPF-Electron 鸿蒙化分支,实现桌面级玻璃效果——材质由操作系统合成器采样,网页仅渲染薄色层与光斑,确保视觉一致性与性能优化。

白天写代码,晚上追AI大模型,偶尔搞点八卦 开源动态|技术干货|实习机会|生态活动 我负责分享,你负责变强 21

Flutter 修复 flutter_secure_storage 鸿蒙入口路由与前缀隔离:让多账号登录凭证在手机上独立读写与清理

本文针对 flutter_secure_storage 在鸿蒙平台的适配问题,修复了主包缺失 TargetPlatform.ohos 路由导致的 unsupported_platform 错误,并统一鸿蒙子包多账号前缀的读写与清理范围,解决键值覆盖、前缀错用及批量操作匹配过宽等问题。修复后,业务层可继续使用统一接口实现跨账号安全存储,保障数据隔离性。完整代码已开源至 abaoge/flutter_secure_storage。

白天写代码,晚上追AI大模型,偶尔搞点八卦 开源动态|技术干货|实习机会|生态活动 我负责分享,你负责变强 1万+

Cordova 鸿蒙沉浸光感实战:让弹层玻璃“喝到“背景的光

本文通过一个 HarmonyOS 模拟器上的 Cordova 项目,详解了在 WebView 中实现“玻璃拟态”效果的三大核心问题:利用 backdrop-filter 实现背景实时模糊与提亮,构建四层结构(采样、渐变底、光场、噪点)模拟真实玻璃质感;通过锚点定位与动态布局实现弹层贴边生长;并集成焦点管理、系统返回键及 inert 属性,确保交互礼仪完整。插件为纯 JS 无原生依赖,基于 ArkWeb 内核,兼顾性能与真实背景采样,适用于菜单、浮层等场景。

白天写代码,晚上追AI大模型,偶尔搞点八卦 开源动态|技术干货|实习机会|生态活动 我负责分享,你负责变强 28

CMP 鸿蒙透明玻璃实战:让悬浮导航栏真正透出光场

本文通过一个KMP/CMP工程,详解如何在鸿蒙上用Kotlin实现沉浸光感玻璃材质的逐像素渲染。核心解决三大问题:透明感源于环境光场与带alpha的柔光混合、玻璃“透光”依赖alpha保留的屏幕混合算法、跨平台一致性通过软件光栅器与原生桥接实现。项目以纯代码生成全屏光场与悬浮玻璃组件,无图片资源,支持动态切换调色板,实测模拟器下亚秒级重绘,完整复现官方“沉浸光感”视觉效果。仓库地址:https://atomgit.com/lqjmac/spatial-glass-cmp。

白天写代码,晚上追AI大模型,偶尔搞点八卦 开源动态|技术干货|实习机会|生态活动 我负责分享,你负责变强 28
上一篇: RNOH 原生内存泄漏定位与治理:借助 LeakyGuard 实现图片解码降采样、LRU 字节缓存、资源生命周期管控,长列表图片页面峰值内存优化
下一篇: Flutter 鸿蒙实现精准碰一碰分享:tap_share_ohos 三方库打通真机传文件与传卡片
AtomGit 代码君
AtomGit 代码君 企业官方账号 企业官方账号
博客等级 码龄6年 2万+粉丝 856原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值