1. 插件介绍

Flutter Fullscreen 是一个用于在原生应用中嵌入全屏 Flutter 模块的示例项目。它展示了如何将一个完整的 Flutter 应用作为原生应用的一个页面或组件进行集成,实现 Flutter 与原生代码的无缝通信和交互。

这个示例项目特别适合以下场景:

  • 需要在现有鸿蒙应用中添加完整的 Flutter 功能页面
  • 希望利用 Flutter 的跨平台能力快速开发新功能
  • 需要在 Flutter 和鸿蒙原生之间进行双向数据通信
  • 学习 Flutter 与鸿蒙系统集成的最佳实践

2. 插件功能特性

  • 支持在鸿蒙应用中嵌入全屏 Flutter 模块
  • 实现 Flutter 与鸿蒙原生之间的双向通信
  • 提供完整的计数器示例应用
  • 支持两种视图模式:全屏视图和迷你视图
  • 使用 Provider 进行状态管理
  • 演示了 MethodChannel 的使用方法
  • 提供完整的项目结构和代码示例

3. 快速开始

3.1 环境要求

  • Flutter SDK 2.19.5 或更高版本
  • HarmonyOS SDK 3.0 或更高版本
  • DevEco Studio 3.0 或更高版本
  • JDK 11 或更高版本

3.2 引入依赖

由于这是一个自定义修改版本的三方库,需要通过 Git 形式引入。在项目的 pubspec.yaml 文件中添加以下配置:

dependencies:
  flutter:
    sdk: flutter
  flutter_module_fullscreen:
    git:
      url: "https://atomgit.com/flutter/samples.git"
      path: "add_to_app/fullscreen/flutter_module"
  provider: ^6.0.2

 dev_dependencies:
  flutter_test:
    sdk: flutter
  flutter_driver:
    sdk: flutter

然后运行以下命令获取依赖:

flutter pub get

4. 使用方法

4.1 鸿蒙应用中嵌入 Flutter 全屏模块

  1. 在鸿蒙应用中创建一个新的 Ability 来承载 Flutter 视图:
import com.huawei.flutter.hmos.adapter.FlutterView;
import ohos.aafwk.ability.Ability;
import ohos.aafwk.content.Intent;
import ohos.agp.components.ComponentContainer;
import ohos.agp.window.dialog.ToastDialog;
import java.util.HashMap;
import java.util.Map;

public class FlutterFullscreenAbility extends Ability {
    private FlutterView flutterView;
    private int counter = 0;
    
    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        super.setUIContent(ResourceTable.Layout_ability_flutter_fullscreen);
        
        // 初始化 FlutterView
        ComponentContainer container = (ComponentContainer) findComponentById(ResourceTable.Id_flutter_container);
        flutterView = new FlutterView(this);
        flutterView.setBundleName("dev.flutter.example.flutter_module");
        flutterView.setEntrypoint("main");
        container.addComponent(flutterView);
        
        // 初始化 Flutter 引擎
        flutterView.initialize();
        
        // 设置 MethodChannel 处理器
        setupMethodChannel();
    }
    
    private void setupMethodChannel() {
        // 创建并设置 MethodChannel
        new MethodChannel(flutterView.getFlutterEngine().getDartExecutor().getBinaryMessenger(), "dev.flutter.example/counter")
            .setMethodCallHandler((call, result) -> {
                switch (call.method) {
                    case "requestCounter":
                        // 返回当前计数器值
                        result.success(counter);
                        break;
                    case "incrementCounter":
                        // 增加计数器值并返回
                        counter++;
                        result.success(counter);
                        // 通知 Flutter 更新计数器值
                        new MethodChannel(flutterView.getFlutterEngine().getDartExecutor().getBinaryMessenger(), "dev.flutter.example/counter")
                            .invokeMethod("reportCounter", counter);
                        break;
                    default:
                        result.notImplemented();
                        break;
                }
            });
    }
    
    @Override
    protected void onForeground(Intent intent) {
        super.onForeground(intent);
        if (flutterView != null) {
            flutterView.onForeground();
        }
    }
    
    @Override
    protected void onBackground() {
        super.onBackground();
        if (flutterView != null) {
            flutterView.onBackground();
        }
    }
    
    @Override
    protected void onStop() {
        super.onStop();
        if (flutterView != null) {
            flutterView.onStop();
        }
    }
}
  1. 在鸿蒙应用的布局文件中添加 Flutter 视图容器:
<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    ohos:height="match_parent"
    ohos:width="match_parent"
    ohos:orientation="vertical">
    
    <!-- Flutter 视图容器 -->
    <ComponentContainer
        ohos:id="$+id:flutter_container"
        ohos:height="match_parent"
        ohos:width="match_parent"/>
</DirectionalLayout>
  1. 在主应用中添加跳转到 Flutter 页面的入口:
import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
import ohos.agp.components.Button;
import ohos.agp.components.DirectionalLayout;

public class MainAbilitySlice extends AbilitySlice {
    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        
        // 创建布局
        DirectionalLayout layout = new DirectionalLayout(this);
        layout.setHeight(DirectionalLayout.LayoutConfig.MATCH_PARENT);
        layout.setWidth(DirectionalLayout.LayoutConfig.MATCH_PARENT);
        layout.setOrientation(Component.VERTICAL);
        
        // 创建按钮
        Button openFlutterButton = new Button(this);
        openFlutterButton.setText("打开 Flutter 全屏页面");
        openFlutterButton.setHeight(Button.LayoutConfig.MATCH_CONTENT);
        openFlutterButton.setWidth(Button.LayoutConfig.MATCH_CONTENT);
        openFlutterButton.setMargins(0, 100, 0, 0);
        
        // 设置按钮点击事件
        openFlutterButton.setClickedListener(component -> {
            // 创建跳转到 Flutter 页面的意图
            Intent flutterIntent = new Intent();
            flutterIntent.setElementName(
                "dev.flutter.example.harmonyos_fullscreen",
                "FlutterFullscreenAbility"
            );
            startAbility(flutterIntent);
        });
        
        // 添加按钮到布局
        layout.addComponent(openFlutterButton);
        
        // 设置布局
        super.setUIContent(layout);
    }
}

4.2 Flutter 模块开发

Flutter 模块提供了一个完整的计数器应用,包含以下主要组件:

  1. CounterModel:使用 MethodChannel 与原生应用通信的状态管理类
class CounterModel extends ChangeNotifier {
  CounterModel() {
    _channel.setMethodCallHandler(_handleMessage);
    _channel.invokeMethod<void>('requestCounter');
  }

  final _channel = const MethodChannel('dev.flutter.example/counter');

  int _count = 0;

  int get count => _count;

  void increment() {
    _channel.invokeMethod<void>('incrementCounter');
  }

  Future<dynamic> _handleMessage(MethodCall call) async {
    if (call.method == 'reportCounter') {
      _count = call.arguments as int;
      notifyListeners();
    }
  }
}
  1. MyApp:Flutter 应用的入口组件,定义了两个路由
class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Module Title',
      theme: ThemeData.light(useMaterial3: true),
      routes: {
        '/': (context) => const FullScreenView(),
        '/mini': (context) => const Contents(),
      },
    );
  }
}
  1. FullScreenView:全屏视图组件,包含一个应用栏
class FullScreenView extends StatelessWidget {
  const FullScreenView({super.key});

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Full-screen Flutter'),
      ),
      body: const Contents(showExit: true),
    );
  }
}
  1. Contents:实际内容组件,显示计数器和窗口信息
class Contents extends StatelessWidget {
  final bool showExit;

  const Contents({this.showExit = false, super.key});

  
  Widget build(BuildContext context) {
    final mediaInfo = MediaQuery.of(context);

    return SizedBox.expand(
      child: Stack(
        children: [
          Positioned.fill(
            child: DecoratedBox(
              decoration: BoxDecoration(
                color: Theme.of(context).scaffoldBackgroundColor,
              ),
            ),
          ),
          const Positioned.fill(
            child: Opacity(
              opacity: .25,
              child: FittedBox(
                fit: BoxFit.cover,
                child: FlutterLogo(),
              ),
            ),
          ),
          Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Text(
                  'Window is ${mediaInfo.size.width.toStringAsFixed(1)} x '\n                  '${mediaInfo.size.height.toStringAsFixed(1)}',
                  style: Theme.of(context).textTheme.headlineSmall,
                ),
                const SizedBox(height: 16),
                Consumer<CounterModel>(
                  builder: (context, model, child) {
                    return Text(
                      'Taps: ${model.count}',
                      style: Theme.of(context).textTheme.headlineSmall,
                    );
                  },
                ),
                const SizedBox(height: 16),
                Consumer<CounterModel>(
                  builder: (context, model, child) {
                    return ElevatedButton(
                      onPressed: () => model.increment(),
                      child: const Text('Tap me!'),
                    );
                  },
                ),
                if (showExit) ...[
                  const SizedBox(height: 16),
                  ElevatedButton(
                    onPressed: () => SystemNavigator.pop(animated: true),
                    child: const Text('Exit this screen'),
                  ),
                ],
              ],
            ),
          ),
        ],
      ),
    );
  }
}

4.3 API 调用说明

Flutter 模块通过 MethodChannel 与鸿蒙原生应用进行通信,主要 API 包括:

  1. requestCounter:从原生应用获取当前计数器值
  2. incrementCounter:通知原生应用增加计数器值
  3. reportCounter:原生应用通知 Flutter 更新计数器值

5. 构建与运行

5.1 构建 Flutter 模块

在 Flutter 模块目录下运行以下命令构建 Flutter AAR:

flutter build aar --no-debug --no-profile

5.2 构建鸿蒙应用

在 DevEco Studio 中打开鸿蒙应用项目,然后点击 “Build” -> “Build HAP(s)/APP(s)” -> “Build APP(s)” 构建完整的鸿蒙应用。

5.3 运行应用

将鸿蒙设备连接到开发机,然后在 DevEco Studio 中点击 “Run” 按钮或使用以下命令运行应用:

hap build install

6. 常见问题与解决方案

6.1 Flutter 视图无法加载

问题:鸿蒙应用中 Flutter 视图显示为空白或无法加载。

解决方案

  1. 检查 Flutter SDK 版本是否符合要求(2.19.5 或更高)
  2. 确保 Flutter 模块已正确构建(运行 flutter build aar
  3. 检查鸿蒙应用的 config.json 文件中是否已配置 Flutter 相关权限
  4. 查看日志获取详细错误信息:hdc shell logcat -s Flutter

6.2 MethodChannel 通信失败

问题:Flutter 与鸿蒙原生之间的 MethodChannel 通信失败。

解决方案

  1. 确保两边使用的 Channel 名称完全一致
  2. 检查参数类型是否匹配
  3. 确保已在两侧正确设置 MethodCallHandler
  4. 查看日志获取详细错误信息

6.3 性能问题

问题:嵌入 Flutter 视图后,鸿蒙应用的性能下降。

解决方案

  1. 考虑在应用启动时预热 Flutter 引擎
  2. 优化 Flutter 代码,减少不必要的重建和重绘
  3. 合理使用 Flutter 的异步加载和缓存机制
  4. 使用 Flutter 的 release 模式构建应用(flutter build aar --release

7. 总结

Flutter Fullscreen 示例项目展示了如何在鸿蒙系统上实现完整的 Flutter 模块嵌入,特别是通过 MethodChannel 实现高效的数据通信。

通过本文的指南,您已经了解了如何:

  • 在鸿蒙应用中嵌入全屏 Flutter 模块
  • 使用 MethodChannel 实现 Flutter 与鸿蒙原生之间的通信
  • 开发包含状态管理的 Flutter 应用
  • 构建和运行混合应用

这种集成方式允许开发者在保持现有应用架构的同时,利用 Flutter 的跨平台能力快速开发新功能,为鸿蒙应用开发提供了更大的灵活性和效率。

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

Logo

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

更多推荐