适合谁看

  • 正在排查鸿蒙 Intents Kit 直达问题的人

  • 遇到"系统命中了,但页面没打开"的开发者

  • 想建立一套稳定排查顺序的人

问题背景

Intent 跳转问题最难的地方,不是它复杂,而是它跨层。如果没有固定排查顺序,很容易在错误层里反复打转。

常见错误排查顺序:

❌ 错误顺序:
  页面没打开 → 改 Flutter 页面 → 还没好 → 改路由映射 → 还没好 → 改执行器 → 还没好 → 改配置

✅ 正确顺序:
  页面没打开 → 检查配置 → 检查原生执行 → 检查 Flutter 路由 → 定位到具体层

项目中的真实场景

食界探味当前的完整链路:

文件

职责

配置层

insight_intent.json

声明入口、参数、关键词

执行层

InsightIntentExecutorImpl.ets

参数校验、转发

插件层

IntentNavigationPlugin.ets

桥接 Flutter、pending 缓存

Flutter 层

intent_navigation_channel.dart

路由映射、页面跳转

核心实现

第一层:先看配置层——insight_intent.json

排查步骤:

  1. 打开 app/ohos/entry/src/main/resources/base/profile/insight_intent.json

  2. 检查 intentName 是否正确

  3. 检查 pageIdenum 值是否包含你要跳转的入口

  4. 检查 keywords 是否覆盖了用户搜索的词

配置层常见问题:

问题

表现

修复

intentName 写错

系统找不到入口

改成 JumpFunctionPage

pageId 不在 enum 中

执行器校验失败

在 enum 中加一个值

keywords 覆盖不全

小艺搜索找不到

补充关键词

srcEntry 路径错误

执行器找不到

检查路径

配置层日志检查:

如果小艺搜索能找到你的入口 → 配置层没问题
如果小艺搜索找不到 → 检查 keywords 和 displayName

配置层代码检查:

{
  "insightIntents": [{
    "intentName": "JumpFunctionPage",
    "inputParams": [{
      "properties": {
        "pageId": {
          "type": "string",
          "enum": [
            { "value": "search", "displayName": "搜索美食", "keywords": ["搜索", "找菜"] },
            { "value": "explore", "displayName": "探索美食", "keywords": ["探索", "推荐"] },
            { "value": "dish_detail", "displayName": "查看菜品详情", "keywords": ["菜品", "详情"] }
          ]
        }
      }
    }]
  }]
}

确认清单:

□ intentName 是否正确?
□ 目标 pageId 是否在 enum 中?
□ keywords 是否覆盖用户可能搜索的词?
□ displayName 是否清晰?
□ srcEntry 路径是否正确?

第二层:再看原生执行与转发层

排查步骤:

  1. 打开 app/ohos/entry/src/main/ets/entryability/InsightIntentExecutorImpl.ets

  2. 检查 VALID_PAGE_IDS 是否包含目标 pageId

  3. 检查执行器日志,确认是否命中了 JumpFunctionPage

  4. 检查参数校验是否通过

  5. 检查 IntentNavigationPlugin.getInstance() 是否返回实例

原生层常见问题:

问题

表现

修复

VALID_PAGE_IDS 不包含目标 pageId

执行器返回 -1

加入白名单

dish_detail 没有 dishId

执行器返回错误

确保传入 dishId

IntentNavigationPlugin.getInstance() 返回 null

进入 pending 分支

检查插件注册

执行器没有日志

不确定是否执行

加 console.info

原生层日志检查:

// InsightIntentExecutorImpl.ets

private jumpFunctionPage(param: Record<string, Object>): Promise<insightIntent.ExecuteResult> {
  return new Promise((resolve) => {
    const pageId = param.pageId as string;
    console.info(TAG, `jumpFunctionPage: pageId="${pageId}"`);  // ← 检查这条日志

    if (!VALID_PAGE_IDS.includes(pageId)) {
      console.error(TAG, `unknown pageId: ${pageId}`);  // ← 检查这条日志
      resolve(makeResult(-1, `unknown pageId: ${pageId}`));
      return;
    }

    const plugin = IntentNavigationPlugin.getInstance();
    if (plugin !== null) {
      console.info(TAG, `plugin found, navigating to pageId="${pageId}"`);  // ← 检查这条日志
      plugin.navigateToPage(pageId, dishId);
    } else {
      console.warn(TAG, `plugin not found, storing as pending`);  // ← 检查这条日志
      IntentNavigationPlugin.setPendingNavigation(pageId, dishId);
    }

    resolve(makeResult(0, 'success'));
  });
}

插件层日志检查:

// IntentNavigationPlugin.ets

navigateToPage(pageId: string, dishId?: string): void {
  if (this.channel) {
    console.info(TAG, `pushing pageId "${pageId}" to Flutter`);  // ← 检查这条日志
    this.channel.invokeMethod('onIntentNavigation', args);
  } else {
    console.warn(TAG, `channel not ready, storing as pending`);  // ← 检查这条日志
    IntentNavigationPlugin.pendingNavigation = { pageId, dishId };
  }
}

确认清单:

□ VALID_PAGE_IDS 是否包含目标 pageId?
□ dish_detail 是否校验了 dishId?
□ IntentNavigationPlugin.getInstance() 是否返回实例?
□ 是走 navigateToPage 还是 pending 分支?
□ 插件层日志是否有 "pushing pageId" 或 "storing as pending"?

第三层:最后看 Flutter 路由承接层

排查步骤:

  1. 打开 app/lib/core/platform/intent_navigation_channel.dart

  2. 检查 init() 是否被调用

  3. 检查 _pageIdToRoute 是否包含目标 pageId

  4. 检查 _navigate() 是否被触发

  5. 检查路由是否正确跳转

Flutter 层常见问题:

问题

表现

修复

init() 没调用

通道没初始化

在 App 启动时调用

_pageIdToRoute 不包含目标 pageId

路由映射失败

加一行映射

consumePendingNavigation 失败

pending 没消费

检查日志

详情页 go+push 逻辑错误

页面没打开

检查 _navigate 代码

Flutter 层日志检查:

// intent_navigation_channel.dart

static void _navigate(_NavigationPayload payload) {
  // 特殊处理:AI 助手需要检查功能开关
  if (payload.pageId == 'ai_assistant' && !AppConfig.enableAi) {
    AppLogger.info('Intent navigation blocked: pageId="${payload.pageId}"');  // ← 检查
    _router?.go('/explore');
    return;
  }

  // 特殊处理:详情页需要 go + push
  if (payload.pageId == 'dish_detail') {
    final dishId = payload.dishId;
    if (dishId == null || dishId.isEmpty) {
      AppLogger.warning('Missing dishId for dish_detail intent');  // ← 检查
      return;
    }
    AppLogger.info(
      'Intent navigation: pageId="${payload.pageId}" -> route="/dish/$dishId"',  // ← 检查
    );
    _router?.go('/explore');
    scheduleMicrotask(() {
      _router?.push('/dish/$dishId');
    });
    return;
  }

  // 通用处理
  final route = _pageIdToRoute[payload.pageId];
  if (route == null) {
    AppLogger.warning('Unknown intent pageId: ${payload.pageId}');  // ← 检查
    return;
  }
  AppLogger.info(
    'Intent navigation: pageId="${payload.pageId}" -> route="$route"',  // ← 检查
  );
  _router?.go(route);
}

确认清单:

□ init() 是否被调用?
□ _pageIdToRoute 是否包含目标 pageId?
□ _navigate() 是否被触发?
□ 路由跳转是否正确?
□ 详情页的 go+push 逻辑是否正确?

四、完整的排查流程图

页面没打开
  │
  ▼
第 1 层:检查配置
  │
  ├─ insight_intent.json 有目标 pageId?
  │   ├─ 没有 → 加入 enum
  │   └─ 有 → 继续
  │
  ├─ keywords 覆盖用户搜索词?
  │   ├─ 没覆盖 → 补充关键词
  │   └─ 覆盖了 → 继续
  │
  ▼
第 2 层:检查原生执行
  │
  ├─ 执行器日志有 "jumpFunctionPage"?
  │   ├─ 没有 → 配置层问题,回到第 1 层
  │   └─ 有 → 继续
  │
  ├─ VALID_PAGE_IDS 包含目标 pageId?
  │   ├─ 不包含 → 加入白名单
  │   └─ 包含 → 继续
  │
  ├─ plugin 不为 null?
  │   ├─ 为 null → 插件未注册,检查 EntryAbility
  │   └─ 不为 null → 继续
  │
  ├─ 日志有 "pushing pageId"?
  │   ├─ 有 → Flutter 已收到,检查第 3 层
  │   └─ 有 "storing as pending" → Flutter 未 ready,检查 pending 消费
  │
  ▼
第 3 层:检查 Flutter 路由
  │
  ├─ init() 是否调用?
  │   ├─ 没调用 → 通道未初始化
  │   └─ 调用了 → 继续
  │
  ├─ _pageIdToRoute 包含目标 pageId?
  │   ├─ 不包含 → 加一行映射
  │   └─ 包含 → 继续
  │
  ├─ _navigate() 是否触发?
  │   ├─ 没触发 → 检查 pending 消费
  │   └─ 触发了 → 继续
  │
  ├─ 路由跳转是否正确?
  │   ├─ 不正确 → 检查 go/push 逻辑
  │   └─ 正常 → 问题在更深层
  │
  ▼
问题定位完成

五、日志对照表

日志关键词

说明

配置层

小艺搜索能找到入口

配置正确

执行层

jumpFunctionPage: pageId="xxx"

执行器命中

执行层

unknown pageId: xxx

pageId 不在白名单

执行层

plugin found, navigating

正常转发

执行层

plugin not found, storing as pending

Flutter 未 ready

插件层

pushing pageId "xxx" to Flutter

已推给 Flutter

插件层

channel not ready, storing as pending

Flutter 未 ready

Flutter 层

Intent navigation: pageId="xxx" -> route="xxx"

路由跳转

Flutter 层

Unknown intent pageId: xxx

pageId 不在映射表

Flutter 层

Missing dishId for dish_detail

详情页缺参数

关键代码位置

文件

排查层

app/ohos/entry/src/main/resources/base/profile/insight_intent.json

配置层

app/ohos/entry/src/main/ets/entryability/InsightIntentExecutorImpl.ets

执行层

app/ohos/entry/src/main/ets/plugins/IntentNavigationPlugin.ets

插件层

app/lib/core/platform/intent_navigation_channel.dart

Flutter 层

常见坑

  • 一看到没跳转就先改 Flutter 页面 — 应该先检查配置和原生层

  • 配置里的 pageId 和执行器白名单不一致 — 两边必须同步

  • 原生已缓存 pending navigation,但 Flutter 没主动消费_consumePending() 必须在 init() 中调用

  • 详情页这种特殊跳转没有单独检查 — dish_detail 需要 go+push,不是简单 go

  • 没有检查小艺搜索是否能找到入口 — 配置层的 keywords 很关键

  • 没有在执行器中加日志 — 不确定是否执行了

可复用模板

三层排查清单

第 1 层:配置
  □ intentName 是否正确?
  □ pageId 是否在 enum 中?
  □ keywords 是否覆盖?
  □ srcEntry 路径是否正确?

第 2 层:原生执行
  □ VALID_PAGE_IDS 是否包含?
  □ dish_detail 是否校验 dishId?
  □ plugin 是否注册?
  □ 是走 navigateToPage 还是 pending?

第 3 层:Flutter 路由
  □ init() 是否调用?
  □ _pageIdToRoute 是否包含?
  □ _navigate() 是否触发?
  □ 路由跳转是否正确?

日志检查模板

按顺序检查日志:
  1. 执行器:jumpFunctionPage: pageId="xxx"
  2. 执行器:plugin found / plugin not found
  3. 插件:pushing pageId / storing as pending
  4. Flutter:Intent navigation: pageId="xxx" -> route="xxx"
  5. Flutter:Unknown intent pageId / Missing dishId

本篇总结

Intent 跳转问题最适合按层排查,而不是凭感觉到处试。先配置、再原生、后 Flutter,这个顺序最稳:

  1. 配置层insight_intent.json 的 pageId 和 keywords

  2. 原生层InsightIntentExecutorImpl 的白名单校验 + IntentNavigationPlugin 的转发

  3. Flutter 层intent_navigation_channel.dart 的路由映射 + pending 消费

只要每层都能拿到明确证据,定位会快很多。

Logo

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

更多推荐