跨端路由统一方案:Flutter 与 OpenHarmony ArkTS 页面跳转的无缝集成

跨端路由统一方案:Flutter 与 OpenHarmony ArkTS 页面跳转的无缝集成

作者 :L、218
发布平台 :CSDN
发布时间 :2025年12月9日
关键词:Flutter、OpenHarmony、跨端路由、页面跳转、统一导航、DeepLink、Scheme 协议、Navigation 2.0、ArkTS Router


引言

在混合架构应用中,我们常遇到这样的场景:

❓ 用户在 OpenHarmony 原生首页点击"商品推荐",如何跳转到 Flutter 实现的商品详情页?

❓ 反之,Flutter 页面中的"我的订单"按钮,又该如何打开 ArkTS 编写的个人中心?

如果处理不当,就会出现:

  • ❌ 白屏或崩溃
  • ❌ 栈混乱(无法返回)
  • ❌ 数据传递失败

本文将由 L、218 带你构建一套 Flutter + OpenHarmony 统一路由系统,实现:

✅ 任意页面间自由跳转

✅ 支持参数传递与结果回调

✅ 兼容 DeepLink 和通知栏唤醒

✅ 统一协议格式 ohrouter://page/detail?id=123

这不是简单的 Navigator.push,而是一套真正可落地的跨框架导航解决方案


一、为什么需要统一路由?

场景 问题
多团队协作 Flutter 团队用 /product/123,ArkTS 团队用 Pages/ProductPage?pid=123
分布式流转 手机上点击链接,在智慧屏上打开对应页面
推送唤醒 点击通知,跳转至指定 Flutter 页面

若无统一标准,最终只能靠硬编码对接,维护成本极高。

我们的目标是:

🔗 写一次跳转逻辑,两端都能识别


二、整体架构设计

复制代码
+----------------------------+
|        DeepLink / Notification      |
|         ohrouter://...     |
+--------------↑-------------+
               |
       +--------↓--------+
       |   Router Center   | ← 统一入口
       | (C++/NDK Layer)   |
       +--------↑--------+
                |
     +----------+-----------+------------------+
     |                      |                  |
+----↓----+          +------↓------+    +------↓------+
| Flutter |          | OpenHarmony  |    | Other Device|
| Navigator|<--------| Router API  |    | (Distributed)|
+---------+  Bridge  +-------------+    +-------------+

所有跳转请求都通过中央路由表解析并分发。


三、定义统一协议:ohrouter://

我们自定义一种 Scheme 协议:

复制代码
ohrouter://{page_name}?{key=value}&{key=value}

示例

目标页面 跳转 URL
商品详情 ohrouter://product/detail?id=789&from=recommend
订单列表 ohrouter://order/list?type=paid
设置页 ohrouter://settings/theme?dark=true

💡 可结合 Figma 或语义化命名规范统一管理 page_name


四、实战步骤:从零搭建跨端路由系统

🧩 功能目标

  • 在 ArkTS 页面点击按钮,跳转到 Flutter 商品页
  • 支持传参 id=123
  • 返回时栈正确

步骤 1:创建中央路由注册表(C++ 层)

router_registry.h
cpp 复制代码
#ifndef ROUTER_REGISTRY_H
#define ROUTER_REGISTRY_H

#include <string>
#include <functional>
#include <map>

// 定义跳转处理器
typedef std::function<bool(const std::map<std::string, std::string>&)> RouteHandler;

class RouterRegistry {
public:
    static RouterRegistry& GetInstance();

    // 注册页面
    void RegisterRoute(const std::string& path, RouteHandler handler);

    // 解析并跳转
    bool Navigate(const std::string& url);

    // 辅助:解析 query 参数
    static std::map<std::string, std::string> ParseQuery(const std::string& query);

private:
    std::map<std::string, RouteHandler> routes_;
};

// C 导出函数
extern "C" {
    void register_route(const char* path, void* handler_fn);
    bool navigate_to(const char* url);
}

#endif
router_registry.cpp
cpp 复制代码
#include "router_registry.h"
#include <regex>

RouterRegistry& RouterRegistry::GetInstance() {
    static RouterRegistry instance;
    return instance;
}

void RouterRegistry::RegisterRoute(const std::string& path, RouteHandler handler) {
    routes_[path] = handler;
}

bool RouterRegistry::Navigate(const std::string& url) {
    // 解析 URL: ohrouter://product/detail?id=123
    std::regex pattern(R"(ohrouter://([^?]+)(?:\?(.*))?)");
    std::smatch match;
    if (!std::regex_match(url, match, pattern)) {
        return false;
    }

    std::string page = match[1].str();
    std::string query = match.size() > 2 ? match[2].str() : "";

    auto params = ParseQuery(query);

    auto it = routes_.find(page);
    if (it != routes_.end()) {
        return it->second(params);
    }

    return false;
}

std::map<std::string, std::string> RouterRegistry::ParseQuery(const std::string& query) {
    std::map<std::string, std::string> result;
    std::regex pair_regex("([^&=]+)=([^&]*)");
    auto begin = std::sregex_iterator(query.begin(), query.end(), pair_regex);
    auto end = std::sregex_iterator();

    for (auto i = begin; i != end; ++i) {
        std::string key = i->str(1);
        std::string value = i->str(2);
        result[key] = value;
    }
    return result;
}

// C 接口实现
void register_route(const char* path, void* handler_fn) {
    auto handler = reinterpret_cast<RouteHandler::result_type (*)(const std::map<std::string, std::string>&)>(handler_fn);
    RouterRegistry::GetInstance().RegisterRoute(std::string(path), [handler](const std::map<std::string, std::string>& p) {
        return handler(p);
    });
}

bool navigate_to(const char* url) {
    return RouterRegistry::GetInstance().Navigate(std::string(url));
}

步骤 2:Flutter 端注册页面

创建 lib/router/flutter_router.dart
dart 复制代码
import 'dart:ffi';
import 'package:ffi/ffi.dart';

class FlutterRouter {
  final DynamicLibrary _dylib;
  final int Function(Pointer<Utf8>) _registerRoute;
  final bool Function(Pointer<Utf8>) _navigateTo;

  FlutterRouter(String soPath)
      : _dylib = DynamicLibrary.open(soPath),
        _registerRoute = _dylib
            .lookup<NativeFunction<Int32 Function(Pointer<Utf8>)>>('register_route')
            .asFunction(),
        _navigateTo = _dylib
            .lookup<NativeFunction<Bool Function(Pointer<Utf8>)>>('navigate_to')
            .asFunction();

  void registerAllRoutes() {
    _registerRoute(_toUtf8('product/detail'), _onProductDetail);
  }

  Pointer<Utf8> _toUtf8(String str) {
    return Utf8.toUtf8(str);
  }

  int _onProductDetail(Map<String, String> params) {
    final id = params['id'];
    print('【Flutter Router】打开商品详情,ID=$id');

    // 使用 Navigation 2.0 或普通 Navigator
    WidgetsBinding.instance.addPostFrameCallback((_) {
      // 假设你有全局 navigatorKey
      navigatorKey.currentState?.push(
        MaterialPageRoute(
          builder: (_) => ProductDetailPage(productId: id!),
        ),
      );
    });

    return 1; // 成功
  }

  bool open(String url) {
    final cStr = _toUtf8(url);
    final result = _navigateTo(cStr);
    malloc.free(cStr);
    return result;
  }
}

⚠️ 注意:实际需使用回调函数指针注册,此处简化为伪代码演示


步骤 3:OpenHarmony 端接收跳转

在 ArkTS 中调用原生路由
ets 复制代码
@Entry
@Component
struct HomePage {
  build() {
    Column({ space: 20 }) {
      Text('欢迎来到首页')
        .fontSize(20).fontWeight(FontWeight.Bold)

      Button('跳转到 Flutter 商品页')
        .onClick(() => {
          this.navigateToFlutter()
        })
    }
    .padding(30)
  }

  navigateToFlutter(): void {
    const url = 'ohrouter://product/detail?id=789&from=home'
    nativeModule.navigate(url, (err, result) => {
      if (err) {
        console.error('跳转失败:', err)
      } else {
        console.info('跳转成功:', result)
      }
    })
  }
}
NDK 桥接层 native_router.cpp
cpp 复制代码
#include <napi/native_api.h>
#include "router_registry.h"

static napi_value Navigate(napi_env env, napi_callback_info info) {
    size_t argc = 1;
    napi_value args[1];
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);

    char url[512];
    size_t len;
    napi_get_value_string_utf8(env, args[0], url, sizeof(url), &len);

    bool success = navigate_to(url);

    napi_value result;
    napi_get_boolean(env, success, &result);
    return result;
}

EXTERN_C_START
napi_value Init(napi_env env, napi_value exports) {
    napi_property_descriptor desc[] = {
        { "navigate", nullptr, Navigate, nullptr, nullptr, nullptr, napi_default, nullptr }
    };
    napi_define_properties(env, exports, 1, desc);
    return exports;
}
EXTERN_C_END

static napi_module demoModule = {
    .nm_version = 1,
    .nm_flags = 0,
    .nm_filename = nullptr,
    .nm_register_func = Init,
    .nm_modname = "router",
    .nm_priv = nullptr,
    .reserved = { 0 }
};

extern "C" __attribute__((constructor)) void RegisterModule() {
    napi_register_module(&demoModule);
}

步骤 4:配置 module.json5 并打包

确保 .so 文件和模块注册正确。


控制台日志
复制代码
INFO: 【Flutter Router】打开商品详情,ID=789
DEBUG: Push to ProductDetailPage

五、进阶功能建议

功能 实现方式
返回结果回调 类似 startActivityForResult,支持带回数据
拦截器机制 登录校验、埋点统计
分布式跳转 结合 OH 分布式能力,跳转到其他设备
动态注册 插件化页面热加载

七、结语:路由即契约

在一个复杂的混合应用中,路由就是组件之间的通信契约

当我们用统一协议替代硬编码跳转时,我们就实现了:

✅ 解耦

✅ 可维护

✅ 易扩展

这正是现代移动架构的核心理念。

💬 如果你也正在做类似的事情,欢迎关注我 @L、218,后续将推出:

  • 《跨端状态共享 SDK 设计》
  • 《Flutter on OpenHarmony 性能优化白皮书》
  • 《基于 Figma 的自动化 UI 同步方案》

一起为中国基础软件生态添砖加瓦!


参考资料


❤️ 欢迎交流

你在项目中是怎么管理多端跳转的?有没有踩过坑?

欢迎在评论区留言分享你的经验!

📌 关注我 @L、218,获取更多 Flutter × OpenHarmony 实战干货,助你成为下一代操作系统生态的先行者!


版权声明 :本文原创,转载请注明出处及作者。商业转载请联系授权。
作者主页https://blog.csdn.net/L218

点赞 + 收藏 + 转发,让更多人告别"跳转黑盒"的痛苦!


📌 标签:#Flutter #OpenHarmony #跨端路由 #页面跳转 #DeepLink #统一导航 #Scheme协议 #ArkTS #L218 #CSDN #2025工程实践

https://openharmonycrossplatform.csdn.net/content

相关推荐
laplace012310 分钟前
Part 4. LangChain 1.0 Agent 开发流程(Markdown 笔记)
前端·javascript·笔记·python·语言模型·langchain
Aliex_git10 分钟前
性能优化 - 渲染优化
前端·javascript·笔记·学习·性能优化·html
生而为虫23 分钟前
全能抓包工具-全局抓包,直接抓取下载模拟器 手机 平板 电视中的数据(文本 视频 音乐 直播)
智能手机·电脑
Heo26 分钟前
Vue3 应用实例创建及页面渲染底层原理
前端·javascript·面试
sophie旭31 分钟前
webpack异步加载原理梳理解构
前端·javascript·webpack
小小荧33 分钟前
Vue 原生渲染真要来了?Lynx引擎首次跑通Vue
前端·javascript
前端世界36 分钟前
HarmonyOS 分布式身份认证详解:设备是如何“互相信任”的?
分布式·华为·harmonyos
KLW7543 分钟前
vue中 v-cloak指令
前端·javascript·vue.js
爸爸6191 小时前
Flutter跨平台开发:Multiple Flutters 在鸿蒙系统上的使用指南
flutter·华为·harmonyos
POLITE31 小时前
Leetcode 560. 和为 K 的子数组 JavaScript (Day 5)
javascript·算法·leetcode