一、FlutterChannel介绍

FlutterChannel是Flutter与OpenHarmony原生层之间进行通信的核心机制,它提供了三种不同类型的通信通道,满足各种跨平台通信需求。通过FlutterChannel,开发者可以在Flutter代码中调用OpenHarmony原生API,也可以在原生代码中触发Flutter端的回调。

三种通信通道

  1. MethodChannel:用于方法调用,支持Flutter和原生之间的双向方法调用
  2. BasicMessageChannel:用于基本消息传递,支持字符串、二进制等数据的双向传递
  3. EventChannel:用于事件流通信,支持原生向Flutter发送事件通知

二、环境准备

在开始使用FlutterChannel前,请确保已完成以下环境配置:

1. 基础开发环境

  • DevEco Studio:4.0及以上版本
  • JDK:17.0及以上版本
  • Flutter SDK:OpenHarmony适配版本
  • Node.js:16.0及以上版本

2. 环境变量配置

# 设置Flutter包管理镜像
export PUB_HOSTED_URL=https://mirrors.huaweicloud.com/repository/flutter/
export FLUTTER_STORAGE_BASE_URL=https://mirrors.huaweicloud.com/repository/flutter/

# 添加Flutter和OpenHarmony工具到PATH
export PATH=/path/to/flutter_flutter/bin:$PATH
export PATH=/path/to/ohos/tools:$PATH

3. 验证环境

# 验证Flutter版本
flutter --version

# 验证OpenHarmony环境
hdc version

三、MethodChannel使用方法

MethodChannel用于Flutter与OpenHarmony之间的方法调用,支持双向通信。

1. Flutter端实现

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

class BatteryLevelPage extends StatefulWidget {
  const BatteryLevelPage({Key? key}) : super(key: key);

  
  State<BatteryLevelPage> createState() => _BatteryLevelPageState();
}

class _BatteryLevelPageState extends State<BatteryLevelPage> {
  // 创建MethodChannel实例,指定通道名称
  final _methodChannel = const MethodChannel('samples.flutter.dev/battery');
  int? _batteryLevel;
  String _error = '';

  // 调用原生方法获取电池电量
  Future<void> _getBatteryLevel() async {
    try {
      final int result = await _methodChannel.invokeMethod<int>('getBatteryLevel') ?? 0;
      setState(() {
        _batteryLevel = result;
        _error = '';
      });
    } on PlatformException catch (e) {
      setState(() {
        _error = 'Failed to get battery level: ${e.message}';
      });
    }
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Battery Level'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            ElevatedButton(
              onPressed: _getBatteryLevel,
              child: const Text('Get Battery Level'),
            ),
            const SizedBox(height: 20),
            if (_batteryLevel != null)
              Text('Battery Level: $_batteryLevel%'),
            if (_error.isNotEmpty)
              Text('Error: $_error', style: const TextStyle(color: Colors.red)),
          ],
        ),
      ),
    );
  }
}

2. OpenHarmony端实现

import { FlutterPlugin, FlutterPluginBinding, MethodChannel, MethodCall, MethodResult } from '@ohos/flutter_ohos';
import batteryInfo from '@ohos.batteryInfo';

export default class BatteryPlugin extends FlutterPlugin {
  private channel: MethodChannel | null = null;

  onAttachedToEngine(binding: FlutterPluginBinding): void {
    // 创建MethodChannel实例,通道名称必须与Flutter端一致
    this.channel = new MethodChannel(binding.getBinaryMessenger(), "samples.flutter.dev/battery");

    // 设置方法调用处理器
    this.channel.setMethodCallHandler({
      onMethodCall: (call: MethodCall, result: MethodResult) => {
        switch (call.method) {
          case 'getBatteryLevel':
            this.getBatteryLevel(result);
            break;
          default:
            result.notImplemented();
            break;
        }
      }
    });
  }

  private getBatteryLevel(result: MethodResult): void {
    try {
      // 获取电池电量
      const batteryLevel = batteryInfo.batterySOC;
      result.success(batteryLevel);
    } catch (error) {
      result.error('UNAVAILABLE', 'Battery level not available', null);
    }
  }

  onDetachedFromEngine(binding: FlutterPluginBinding): void {
    // 清理资源
    this.channel?.dispose();
    this.channel = null;
  }
}

四、BasicMessageChannel使用方法

BasicMessageChannel用于Flutter与OpenHarmony之间的基本消息传递,支持字符串、二进制等数据类型。

1. Flutter端实现

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

class MessageChannelPage extends StatefulWidget {
  const MessageChannelPage({Key? key}) : super(key: key);

  
  State<MessageChannelPage> createState() => _MessageChannelPageState();
}

class _MessageChannelPageState extends State<MessageChannelPage> {
  // 创建BasicMessageChannel实例,指定通道名称和消息编解码器
  final _basicChannel = BasicMessageChannel<String>(
    'samples.flutter.dev/message',
    StringCodec(),
  );

  String _message = 'No message received';
  int _count = 0;

  
  void initState() {
    super.initState();
    // 设置消息接收器
    _basicChannel.setMessageHandler((String? message) async {
      setState(() {
        _message = 'Received: $message';
      });
      return 'Message received';
    });
  }

  // 发送消息到原生端
  Future<void> _sendMessage() async {
    _count++;
    final String response = await _basicChannel.send('Hello from Flutter: $_count');
    setState(() {
      _message = 'Response: $response';
    });
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Message Channel'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            ElevatedButton(
              onPressed: _sendMessage,
              child: const Text('Send Message'),
            ),
            const SizedBox(height: 20),
            Text(_message),
          ],
        ),
      ),
    );
  }
}

2. OpenHarmony端实现

import { FlutterPlugin, FlutterPluginBinding, BasicMessageChannel, Any, Reply, StringCodec } from '@ohos/flutter_ohos';
import { Log } from '@kit.PerformanceAnalysisKit';

const TAG = 'BasicMessageChannelPlugin';

export default class BasicMessageChannelPlugin extends FlutterPlugin {
  private basicChannel: BasicMessageChannel | null = null;

  onAttachedToEngine(binding: FlutterPluginBinding): void {
    // 创建BasicMessageChannel实例
    this.basicChannel = new BasicMessageChannel(
      binding.getBinaryMessenger(),
      "samples.flutter.dev/message",
      new StringCodec()
    );

    // 设置消息处理器
    this.basicChannel.setMessageHandler({
      onMessage: (message: Any, reply: Reply<Any>) => {
        Log.i(TAG, "Received message: " + message);

        // 根据消息内容处理
        const msgStr = message as string;
        if (msgStr.contains('Hello')) {
          reply.reply('Hello from OpenHarmony! You said: ' + msgStr);
        } else {
          reply.reply('Received: ' + msgStr);
        }
      }
    });
  }

  // 发送消息到Flutter端
  sendMessage(message: string): void {
    if (this.basicChannel) {
      this.basicChannel.send(message, {
        onReply: (reply: Any) => {
          Log.i(TAG, "Reply received: " + reply);
        }
      });
    }
  }

  onDetachedFromEngine(binding: FlutterPluginBinding): void {
    // 清理资源
    this.basicChannel = null;
  }
}

五、EventChannel使用方法

EventChannel用于OpenHarmony向Flutter发送事件通知,实现单向的事件流通信。

1. Flutter端实现

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

class EventChannelPage extends StatefulWidget {
  const EventChannelPage({Key? key}) : super(key: key);

  
  State<EventChannelPage> createState() => _EventChannelPageState();
}

class _EventChannelPageState extends State<EventChannelPage> {
  // 创建EventChannel实例
  final _eventChannel = const EventChannel('samples.flutter.dev/event_channel');

  String _eventMessage = 'No event received';
  StreamSubscription? _eventSubscription;

  
  void initState() {
    super.initState();
    // 订阅事件流
    _eventSubscription = _eventChannel.receiveBroadcastStream().listen(
      (event) {
        setState(() {
          _eventMessage = 'Event received: $event';
        });
      },
      onError: (error) {
        setState(() {
          _eventMessage = 'Error: $error';
        });
      },
    );
  }

  
  void dispose() {
    // 取消订阅
    _eventSubscription?.cancel();
    super.dispose();
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Event Channel'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text('Listening for events...'),
            const SizedBox(height: 20),
            Text(_eventMessage),
          ],
        ),
      ),
    );
  }
}

2. OpenHarmony端实现

import { FlutterPlugin, FlutterPluginBinding, EventChannel, Any, EventSink } from '@ohos/flutter_ohos';
import { Log } from '@kit.PerformanceAnalysisKit';

const TAG = 'EventChannelPlugin';

export default class EventChannelPlugin extends FlutterPlugin {
  private eventChannel: EventChannel | null = null;
  private eventSink: EventSink | undefined = undefined;
  private timerId: number | undefined = undefined;

  onAttachedToEngine(binding: FlutterPluginBinding): void {
    // 创建EventChannel实例
    this.eventChannel = new EventChannel(
      binding.getBinaryMessenger(),
      "samples.flutter.dev/event_channel"
    );

    // 设置流处理器
    this.eventChannel.setStreamHandler({
      onListen: (args: Any, events: EventSink): void => {
        Log.i(TAG, "EventChannel onListen: " + args);
        this.eventSink = events;

        // 每秒发送一次事件
        this.timerId = setInterval(() => {
          if (this.eventSink) {
            // 发送成功事件
            this.eventSink.success("Current time: " + new Date().toISOString());
          }
        }, 1000);
      },

      onCancel: (args: Any): void => {
        Log.i(TAG, "EventChannel onCancel: " + args);
        this.eventSink = undefined;

        // 清理定时器
        if (this.timerId) {
          clearInterval(this.timerId);
          this.timerId = undefined;
        }
      }
    });
  }

  // 手动发送事件
  sendEvent(data: Any): void {
    if (this.eventSink) {
      this.eventSink.success(data);
    }
  }

  // 发送错误事件
  sendError(code: string, message: string, details: Any): void {
    if (this.eventSink) {
      this.eventSink.error(code, message, details);
    }
  }

  onDetachedFromEngine(binding: FlutterPluginBinding): void {
    // 清理资源
    this.eventSink = undefined;
    if (this.timerId) {
      clearInterval(this.timerId);
      this.timerId = undefined;
    }
    this.eventChannel = null;
  }
}

六、通过AtomGit引入依赖

在Flutter工程中,可以通过AtomGit引入FlutterChannel相关依赖:

1. 在pubspec.yaml中添加依赖

dependencies:
  flutter:
    sdk: flutter

  # 通过AtomGit引入flutter_ohos包
  flutter_ohos:
    git:
      url: "https://atomgit.com/flutter-openharmony/flutter_ohos"
      path: "packages/flutter_ohos/flutter_ohos"

  # 通过AtomGit引入其他Flutter插件
  battery_plugin:
    git:
      url: "https://atomgit.com/flutter-openharmony/plugins"
      path: "packages/battery_plugin/battery_plugin"

2. 更新依赖

执行以下命令更新依赖:

flutter pub get

七、完整应用集成示例

1. Flutter应用主入口

import 'package:flutter/material.dart';
import 'battery_level_page.dart';
import 'message_channel_page.dart';
import 'event_channel_page.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Channel Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const HomePage(),
    );
  }
}

class HomePage extends StatelessWidget {
  const HomePage({Key? key}) : super(key: key);

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Flutter Channel Demo'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            ElevatedButton(
              onPressed: () {
                Navigator.push(
                  context,
                  MaterialPageRoute(builder: (context) => const BatteryLevelPage()),
                );
              },
              child: const Text('MethodChannel Demo'),
            ),
            const SizedBox(height: 20),
            ElevatedButton(
              onPressed: () {
                Navigator.push(
                  context,
                  MaterialPageRoute(builder: (context) => const MessageChannelPage()),
                );
              },
              child: const Text('BasicMessageChannel Demo'),
            ),
            const SizedBox(height: 20),
            ElevatedButton(
              onPressed: () {
                Navigator.push(
                  context,
                  MaterialPageRoute(builder: (context) => const EventChannelPage()),
                );
              },
              child: const Text('EventChannel Demo'),
            ),
          ],
        ),
      ),
    );
  }
}

2. OpenHarmony插件注册

import { GeneratedPluginRegistrant } from '@ohos/flutter_ohos/src/main/ets/plugins/GeneratedPluginRegistrant';
import BatteryPlugin from './BatteryPlugin';
import BasicMessageChannelPlugin from './BasicMessageChannelPlugin';
import EventChannelPlugin from './EventChannelPlugin';

// 注册所有插件
export function registerPlugins() {
  GeneratedPluginRegistrant.registerWith();

  // 注册自定义插件
  const binding = getFlutterPluginBinding();
  if (binding) {
    binding.addPlugin(new BatteryPlugin());
    binding.addPlugin(new BasicMessageChannelPlugin());
    binding.addPlugin(new EventChannelPlugin());
  }
}

八、总结

FlutterChannel提供了强大的跨平台通信能力,通过三种不同类型的通道满足各种通信需求:

  1. MethodChannel:适用于需要双向方法调用的场景,如获取设备信息、调用原生API等
  2. BasicMessageChannel:适用于需要频繁传递数据的场景,如字符串、二进制数据等
  3. EventChannel:适用于需要原生向Flutter发送事件通知的场景,如传感器数据、状态变化等

使用FlutterChannel的基本步骤:

  1. 在Flutter和OpenHarmony两端创建相同名称的Channel实例
  2. 在两端分别设置消息/方法处理器
  3. 通过Channel发送消息或调用方法
  4. 处理接收到的消息或方法调用

通过AtomGit引入依赖,可以方便地使用自定义修改版本的Flutter包,避免使用GitCode品牌名称。

欢迎加入开源鸿蒙跨平台社区: https://openharmonycrossplatform.csdn.net

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐