AtomGit Flutter鸿蒙客户端:鸿蒙平台集成

双端架构

Flutter 与 HarmonyOS 原生层的通信通过 BasicMessageChannel 实现,分为 Dart 端和 ArkTS 端。

复制代码
Flutter (Dart)  ←→  BasicMessageChannel  ←→  HarmonyOS (ArkTS)
     ↑                      ↑                        ↑
OhosPlatform          "com.atomgit/auth"        EntryAbility

Dart 端:OhosPlatform

单例模式

dart 复制代码
class OhosPlatform {
  static final OhosPlatform _instance = OhosPlatform._();
  static OhosPlatform get instance => _instance;
  OhosPlatform._();

  static const _channelName = 'com.atomgit/auth';
  BasicMessageChannel<String?>? _channel;
  bool _isListening = false;
  final _authCodeController = StreamController<String>.broadcast();
  Stream<String> get onAuthCode => _authCodeController.stream;
}

_isListening 守卫防止重复初始化 MessageChannel 的监听器。StreamController.broadcast() 支持多个监听者同时订阅 auth code 事件。

初始化

dart 复制代码
void init() {
  if (_isListening) return;
  _channel = const BasicMessageChannel<String?>(
    _channelName,
    StringCodec(),
  );

  _channel!.setMessageHandler((String? message) async {
    if (message != null) {
      try {
        final decoded = jsonDecode(message) as Map<String, dynamic>;
        if (decoded['type'] == 'authCode') {
          _authCodeController.add(decoded['code'] as String);
        }
      } catch (_) {}
    }
    return null;
  });

  _isListening = true;
}

BasicMessageChannel 使用 StringCodec 编解码器,消息以 JSON 字符串传递。Handler 解析 JSON,识别 type: "authCode" 后通过 Stream 广播。

打开浏览器

dart 复制代码
Future<bool> openBrowser(String url) async {
  if (_channel == null) return false;
  try {
    final message = jsonEncode({
      'method': 'openBrowser',
      'url': url,
    });
    final reply = await _channel!.send(message);
    if (reply != null) {
      final result = jsonDecode(reply) as Map<String, dynamic>;
      return result['success'] == true;
    }
  } catch (_) {}
  return false;
}

send() 是异步的 ------ Dart 发送消息后等待 ArkTS 处理完成并返回结果。

ArkTS 端:EntryAbility

基础结构

typescript 复制代码
import { FlutterAbility, FlutterEngine } from '@ohos/flutter_ohos';
import { GeneratedPluginRegistrant } from '../plugins/GeneratedPluginRegistrant';
import { BasicMessageChannel, StringCodec } from '@ohos/flutter_ohos';

export default class EntryAbility extends FlutterAbility {
  private authChannel?: BasicMessageChannel<string>;
  private flutterEngine?: FlutterEngine;

  configureFlutterEngine(engine: FlutterEngine): void {
    this.flutterEngine = engine;
    GeneratedPluginRegistrant.registerWith(engine);

    this.authChannel = new BasicMessageChannel(
      engine.getBinaryMessenger(),
      'com.atomgit/auth',
      StringCodec.instance
    );

    this.authChannel.setMessageHandler((message: string | null) => {
      return this.handleMessage(message);
    });

    super.configureFlutterEngine(engine);
  }
}

EntryAbility 继承自 FlutterAbility(HarmonyOS Flutter 引擎提供的基类)。在 configureFlutterEngine 中注册插件和创建 MessageChannel。

消息处理

typescript 复制代码
private handleMessage(message: string | null): string | null {
  if (!message) return null;
  try {
    const data = JSON.parse(message) as Record<string, string>;
    if (data.method === 'openBrowser') {
      this.openBrowser(data.url as string);
      return JSON.stringify({ success: true });
    }
  } catch (_) {}
  return null;
}

private openBrowser(url: string): void {
  const want: Want = {
    action: 'ohos.want.action.viewData',
    uri: url
  };
  this.context.startAbility(want);
}

解析 Dart 发来的 JSON → 匹配 method → 调用 startAbility 启动系统浏览器。ohos.want.action.viewData 是 HarmonyOS 的系统动作,用于打开 URL。

OAuth 回调处理

typescript 复制代码
onNewWant(want: Want): void {
  super.onNewWant(want);
  const uri = want.uri;
  if (uri && uri.startsWith('atomgit://oauth/callback')) {
    const code = this.extractQueryParam(uri, 'code');
    if (code && this.authChannel) {
      const message = JSON.stringify({
        type: 'authCode',
        code: code
      });
      this.authChannel.send(message);
    }
  }
}

private extractQueryParam(uri: string, param: string): string | null {
  const queryIndex = uri.indexOf('?');
  if (queryIndex === -1) return null;
  const query = uri.substring(queryIndex + 1);
  const pairs = query.split('&');
  for (const pair of pairs) {
    const [key, value] = pair.split('=');
    if (key === param && value) {
      return decodeURIComponent(value);
    }
  }
  return null;
}

onNewWant 在系统浏览器回调时被调用。EntryAbility 检查是否是 OAuth 回调(atomgit://oauth/callback),提取 code 参数,通过 MessageChannel 发回 Dart 端。

extractQueryParam 手动解析 URL 参数(不依赖 URLSearchParams),用 decodeURIComponent 解码。

module.json5 配置

json5 复制代码
{
  "module": {
    "name": "entry",
    "abilities": [
      {
        "name": "EntryAbility",
        "skills": [
          {
            "actions": ["ohos.want.action.viewData"],
            "uris": [
              {
                "scheme": "atomgit",
                "host": "oauth",
                "path": "/callback"
              }
            ]
          }
        ]
      }
    ],
    "requestPermissions": [
      { "name": "ohos.permission.INTERNET" }
    ]
  }
}

skills 配置声明了 EntryAbility 能处理 atomgit://oauth/callback 的自定义 URI scheme。当系统浏览器访问该 URI 时,系统会将 Want 路由回应用。

Index.ets --- Flutter 页面容器

typescript 复制代码
import { FlutterPage } from '@ohos/flutter_ohos';

@Entry
@Component
struct Index {
  @StorageLink('viewId') viewId: string = '';

  build() {
    Column() {
      FlutterPage({ viewId: this.viewId })
    }
  }

  onBackPress(): boolean | void {
    getContext(this)
      .eventHub
      .emit('EVENT_BACK_PRESS');
  }
}

Index 是 ArkUI 的入口组件,内部只承载一个 FlutterPage 组件。viewId 通过 localStorage 传递,用于 Flutter 的视图管理。

OAuth 完整流程

复制代码
1. 用户点击登录
2. Dart: OhosPlatform.openBrowser(authUrl)
3. ArkTS: startAbility({action: viewData, uri: authUrl})
4. 系统浏览器打开 AtomGit 授权页
5. 用户授权
6. AtomGit 重定向到 atomgit://oauth/callback?code=xxx
7. 系统路由回 EntryAbility.onNewWant()
8. ArkTS: authChannel.send({type: "authCode", code: "xxx"})
9. Dart: _authCodeController.add("xxx")
10. LoginScreen 收到 code → exchangeCode() → 获取 token

Broadcast Stream 的使用

LoginScreen 中订阅 auth code:

dart 复制代码
StreamSubscription<String>? _authCodeSub;

@override
void initState() {
  super.initState();
  _authCodeSub = OhosPlatform.instance.onAuthCode.listen((code) {
    _handleAuthCode(code);
  });
}

@override
void dispose() {
  _authCodeSub?.cancel();
  super.dispose();
}

设计要点

  1. 单向业务流:Dart 发起请求(打开浏览器),ArkTS 执行操作并异步返回结果(auth code)
  2. JSON 协议 :所有消息以 JSON 编码,method 字段区分请求类型
  3. 守卫模式_isListening 防重复初始化,try-catch 包裹所有 JSON 解析
  4. 手动 URL 解析:HarmonyOS 的 API 限制要求手动实现参数提取,而非使用 URL 对象
相关推荐
weixin_604236672 小时前
华三 二层交换机 企业完整正式版配置
运维·网络·华为·华为交换机命令
●VON2 小时前
AtomGit Flutter鸿蒙客户端:共享组件
java·flutter·华为·harmonyos·鸿蒙
川石课堂软件测试2 小时前
UI自动化测试|XPath元素定位实践
功能测试·测试工具·jmeter·microsoft·ui·postman·harmonyos
●VON3 小时前
AtomGit Flutter鸿蒙客户端:本地存储
flutter·华为·跨平台·harmonyos·鸿蒙
伶俜663 小时前
# ✨ 零基础学 ArkUI 动画(专题一):从 animateTo 到 Lottie,一篇吃透全部
学习·华为·harmonyos
李二。3 小时前
HarmonyOS NEXT 屏幕取色器设计与实现详解
华为·harmonyos
●VON3 小时前
AtomGit Flutter鸿蒙客户端:Provider状态管理
flutter·华为·跨平台·harmonyos·鸿蒙
伶俜663 小时前
# [特殊字符] 零基础学 ArkUI 数据持久化(专题三):5 种存储方案深度对比
学习·华为·wpf·harmonyos