对于完成基础环境搭建和入门 Demo 开发的鸿蒙 + Flutter 初学者而言,进阶阶段的核心需求集中在三大场景:跨端路由无缝跳转、数据安全持久化存储、多设备 UI 自适应适配。本文将通过完整代码案例,从实战角度拆解每个技术点的实现逻辑、避坑要点和优化方案,帮助开发者快速掌握可直接落地的进阶技能,适配中小型混合应用开发需求。

一、跨端路由深度整合:Flutter 与鸿蒙页面自由跳转

入门阶段的页面跳转多局限于单一技术栈内,混合开发中需解决 “Flutter 跳鸿蒙原生页”“鸿蒙跳 Flutter 页”“带参数跳转”“路由返回传值” 四大核心场景。本节将基于鸿蒙原生路由和 Flutter Navigator,实现跨端路由的统一管理。

1. 路由协议定义(统一跨端跳转标准)

首先通过 Pigeon 定义跨端路由通信协议,确保跳转参数的强类型约束,避免参数传递错误。在之前创建的pigeon/device_api.dart中新增路由相关模型和接口:

// 路由请求模型(包含目标页面和参数)
class RouterRequest {
  // 目标页面标识(flutter_xxx:Flutter页面;harmony_xxx:鸿蒙页面)
  late String targetPage;
  // 跳转参数(键值对形式)
  late Map<String, dynamic> params;
  // 跳转类型(push:压栈;pushReplace:替换)
  late String jumpType;
}

// 路由返回结果模型
class RouterResult {
  // 是否跳转成功
  late bool success;
  // 返回数据(回传场景用)
  late Map<String, dynamic> resultData;
  // 错误信息(跳转失败时)
  late String errorMsg;
}

// 新增路由相关接口(Flutter调用鸿蒙路由)
@HostApi()
abstract class HarmonyRouterApi {
  // Flutter跳鸿蒙页面
  Future<RouterResult> navigateToHarmonyPage(RouterRequest request);
  // 鸿蒙页面返回数据给Flutter
  Future<void> sendResultToFlutter(RouterResult result);
}

// 鸿蒙调用Flutter路由(GuestApi:原生调用Flutter)
@GuestApi()
abstract class FlutterRouterApi {
  // 鸿蒙跳Flutter页面
  Future<RouterResult> navigateToFlutterPage(RouterRequest request);
}

执行代码生成命令,更新两端通信代码:

flutter pub run pigeon --input lib/pigeon/device_api.dart

2. 鸿蒙侧路由实现(原生页面管理)

在鸿蒙entry/src/main/ets/router目录下新建router_manager.ets,封装原生路由管理工具:

import { AbilityContext } from '@ohos.application';
import Intent from '@ohos.intent.Intent';
import { RouterRequest, RouterResult, HarmonyRouterApi } from '../pigeon/generated';
import { LogUtil } from '../utils/log_util';

// 鸿蒙页面路由映射表(统一管理页面路径)
const PAGE_ROUTER_MAP = {
  "harmony_user_info": "com.example.harmonyflutterdemo.UserInfoAbility",
  "harmony_settings": "com.example.harmonyflutterdemo.SettingsAbility"
};

export class HarmonyRouterApiImpl implements HarmonyRouterApi {
  private context: AbilityContext;
  // 存储路由回调(用于返回数据)
  private resultCallback?: (result: RouterResult) => void;

  constructor(context: AbilityContext) {
    this.context = context;
  }

  // Flutter跳鸿蒙页面实现
  async navigateToHarmonyPage(request: RouterRequest): Promise<RouterResult> {
    const result = new RouterResult();
    try {
      // 校验目标页面是否存在
      const targetAbility = PAGE_ROUTER_MAP[request.targetPage];
      if (!targetAbility) {
        result.success = false;
        result.errorMsg = `目标页面${request.targetPage}未注册`;
        LogUtil.error(result.errorMsg);
        return result;
      }

      // 构建跳转Intent
      const intent = new Intent();
      intent.setAction('android.intent.action.VIEW');
      intent.setComponent({
        package: "com.example.harmonyflutterdemo",
        abilityName: targetAbility
      });

      // 传递参数
      for (const key in request.params) {
        intent.setParam(key, request.params[key]);
      }

      // 根据跳转类型执行对应操作
      if (request.jumpType === "push") {
        // 压栈跳转(可返回)
        await this.context.startAbilityForResult(intent, (abilityResult) => {
          // 接收鸿蒙页面返回数据
          if (this.resultCallback) {
            const callbackResult = new RouterResult();
            callbackResult.success = true;
            callbackResult.resultData = abilityResult.result as Map<string, dynamic>;
            this.resultCallback(callbackResult);
          }
        });
      } else if (request.jumpType === "pushReplace") {
        // 替换跳转(不可返回)
        await this.context.startAbility(intent);
      }

      result.success = true;
      result.errorMsg = "";
      return result;
    } catch (e) {
      result.success = false;
      result.errorMsg = `跳转失败:${JSON.stringify(e)}`;
      LogUtil.error(result.errorMsg);
      return result;
    }
  }

  // 接收鸿蒙页面返回数据并回调给Flutter
  async sendResultToFlutter(result: RouterResult): Promise<void> {
    if (this.resultCallback) {
      this.resultCallback(result);
    }
  }

  // 注册路由回调
  setResultCallback(callback: (result: RouterResult) => void) {
    this.resultCallback = callback;
  }
}

3. Flutter 侧路由管理(统一跳转入口)

在 Flutter 模块lib/router目录下新建router_manager.dart,封装跨端路由工具类,提供统一跳转接口:

import 'package:flutter/material.dart';
import 'package:harmony_flutter_demo/pigeon/generated.dart';

// 路由管理单例
class RouterManager {
  static final RouterManager _instance = RouterManager._internal();
  factory RouterManager() => _instance;
  RouterManager._internal();

  // 初始化Pigeon接口实例
  final HarmonyRouterApi _harmonyRouterApi = HarmonyRouterApi();
  final FlutterRouterApi _flutterRouterApi = FlutterRouterApi();

  // 存储路由返回回调
  Function(Map<String, dynamic>)? _resultCallback;

  // 统一跳转方法(支持Flutter和鸿蒙页面)
  Future<bool> navigateTo({
    required String targetPage,
    Map<String, dynamic> params = const {},
    String jumpType = "push",
    Function(Map<String, dynamic>)? onResult,
  }) async {
    _resultCallback = onResult;

    if (targetPage.startsWith("flutter_")) {
      // 跳Flutter内部页面
      return _navigateToFlutterPage(
        targetPage: targetPage.replaceFirst("flutter_", ""),
        params: params,
        jumpType: jumpType,
      );
    } else if (targetPage.startsWith("harmony_")) {
      // 跳鸿蒙原生页面
      return _navigateToHarmonyPage(
        targetPage: targetPage,
        params: params,
        jumpType: jumpType,
      );
    } else {
      debugPrint("未知页面类型:$targetPage");
      return false;
    }
  }

  // 跳Flutter内部页面
  Future<bool> _navigateToFlutterPage({
    required String targetPage,
    required Map<String, dynamic> params,
    required String jumpType,
  }) async {
    final context = navigatorKey.currentContext;
    if (context == null) return false;

    Widget targetWidget = _getFlutterPage(targetPage, params);

    if (jumpType == "push") {
      final result = await Navigator.push(
        context,
        MaterialPageRoute(builder: (ctx) => targetWidget),
      );
      if (result != null && _resultCallback != null) {
        _resultCallback!(result as Map<String, dynamic>);
      }
    } else if (jumpType == "pushReplace") {
      Navigator.pushReplacement(
        context,
        MaterialPageRoute(builder: (ctx) => targetWidget),
      );
    }
    return true;
  }

  // 跳鸿蒙原生页面
  Future<bool> _navigateToHarmonyPage({
    required String targetPage,
    required Map<String, dynamic> params,
    required String jumpType,
  }) async {
    final request = RouterRequest()
      ..targetPage = targetPage
      ..params = params
      ..jumpType = jumpType;

    final result = await _harmonyRouterApi.navigateToHarmonyPage(request);
    if (result.success && _resultCallback != null) {
      // 注册鸿蒙页面返回数据回调
      _harmonyRouterApi.setResultCallback((routerResult) {
        if (routerResult.success) {
          _resultCallback!(routerResult.resultData);
        }
      });
    }
    return result.success;
  }

  // 根据页面标识获取Flutter页面
  Widget _getFlutterPage(String pageName, Map<String, dynamic> params) {
    switch (pageName) {
      case "detail":
        return DetailPage(params: params);
      case "mine":
        return const MinePage();
      default:
        return Scaffold(
          body: Center(child: Text("未找到页面:$pageName")),
        );
    }
  }
}

// 全局导航键(用于无上下文跳转)
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();

// Flutter示例页面:详情页
class DetailPage extends StatelessWidget {
  final Map<String, dynamic> params;

  const DetailPage({super.key, required this.params});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("Flutter详情页")),
      body: Padding(
        padding: const EdgeInsets.all(20.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text("页面参数:"),
            const SizedBox(height: 10),
            Text(params.toString()),
            const SizedBox(height: 30),
            ElevatedButton(
              onPressed: () {
                // 返回并携带数据
                Navigator.pop(context, {"code": 200, "message": "详情页返回数据"});
              },
              child: const Text("返回并传值"),
            ),
          ],
        ),
      ),
    );
  }
}

// Flutter示例页面:我的页面
class MinePage extends StatelessWidget {
  const MinePage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("我的页面")),
      body: const Center(child: Text("Flutter我的页面")),
    );
  }
}

4. 跨端跳转实战示例

(1)Flutter 侧调用跳转

修改main.dart,添加跳转按钮演示不同场景:

class _DevicePageState extends State<DevicePage> {
  // 初始化路由管理器
  final RouterManager _routerManager = RouterManager();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("跨端路由实战")),
      body: Padding(
        padding: const EdgeInsets.all(20.0),
        child: Column(
          children: [
            // 跳Flutter详情页(带参数)
            ElevatedButton(
              onPressed: () {
                _routerManager.navigateTo(
                  targetPage: "flutter_detail",
                  params: {"id": 1001, "title": "鸿蒙混合开发教程"},
                  onResult: (result) {
                    ScaffoldMessenger.of(context).showSnackBar(
                      SnackBar(content: Text("接收返回数据:${result.toString()}")),
                    );
                  },
                );
              },
              child: const Text("跳Flutter详情页(带参数)"),
            ),
            const SizedBox(height: 20),
            // 跳鸿蒙原生页面
            ElevatedButton(
              onPressed: () {
                _routerManager.navigateTo(
                  targetPage: "harmony_user_info",
                  params: {"userId": "user_123", "userName": "Flutter用户"},
                  jumpType: "push",
                  onResult: (result) {
                    ScaffoldMessenger.of(context).showSnackBar(
                      SnackBar(content: Text("鸿蒙页面返回:${result.toString()}")),
                    );
                  },
                );
              },
              child: const Text("跳鸿蒙用户信息页"),
            ),
          ],
        ),
      ),
    );
  }
}
(2)鸿蒙侧原生页面实现

新建鸿蒙用户信息页面UserInfoAbility.ets,接收参数并支持返回数据:

import Ability from '@ohos.application.Ability';
import { AbilityContext } from '@ohos.application';
import { RouterResult } from '../pigeon/generated';
import { HarmonyRouterApiImpl } from '../router/router_manager';

export default class UserInfoAbility extends Ability {
  private context: AbilityContext;
  private routerApiImpl: HarmonyRouterApiImpl;

  onCreate(want: Want) {
    super.onCreate(want);
    this.context = this.context;
    this.routerApiImpl = new HarmonyRouterApiImpl(this.context);
    // 接收Flutter传递的参数
    const userId = want.parameters["userId"];
    const userName = want.parameters["userName"];
    console.log(`接收参数:userId=${userId}, userName=${userName}`);
    // 加载页面(此处简化,实际需关联UI)
    this.setMainRoute("pages/user_info/user_info");
  }

  // 返回数据给Flutter
  onBackPressed() {
    const result = new RouterResult();
    result.success = true;
    result.resultData = {"code": 200, "message": "用户信息页已确认", "data": {"age": 25, "gender": "male"}};
    this.routerApiImpl.sendResultToFlutter(result);
    this.terminateAbility();
  }
}

5. 路由跳转避坑要点

  • 页面标识必须统一前缀(如flutter_/harmony_),避免路由冲突;
  • 鸿蒙侧页面需在module.json5中注册 Ability,否则跳转失败;
  • 传递参数需使用基础数据类型(String、int、bool 等),复杂对象需提前序列化;
  • Flutter 侧需通过navigatorKey管理全局导航上下文,避免无上下文跳转报错。

二、数据持久化:跨端统一存储方案

混合开发中需解决 “Flutter 侧存储”“鸿蒙侧存储”“两端数据同步” 三大问题,本节采用 “原生存储 + 跨端同步” 方案,确保数据一致性和安全性。

1. 存储类型选择与分工

存储类型 适用场景 技术选型
轻量键值对 配置信息、用户登录态、临时缓存 鸿蒙 Preferences + Flutter SharedPreferences
大量结构化数据 本地数据库、业务数据 鸿蒙 RelationalStore + Flutter Hive
文件存储 图片、音频、大文件 鸿蒙文件管理 API + Flutter path_provider

2. 键值对存储实现(跨端同步)

(1)Pigeon 协议扩展

device_api.dart中新增存储相关接口:

// 存储操作请求模型
class StorageRequest {
  // 存储键
  late String key;
  // 存储值
  late dynamic value;
  // 存储类型(string/int/bool/double)
  late String valueType;
}

// 存储操作结果模型
class StorageResult {
  late bool success;
  late dynamic data; // 查询操作返回数据
  late String errorMsg;
}

// 存储相关接口
@HostApi()
abstract class HarmonyStorageApi {
  // 写入键值对
  Future<StorageResult> setStorage(StorageRequest request);
  // 获取键值对
  Future<StorageResult> getStorage(String key);
  // 删除键值对
  Future<StorageResult> removeStorage(String key);
  // 清空所有存储
  Future<StorageResult> clearStorage();
}

重新执行代码生成命令更新接口。

(2)鸿蒙侧存储实现

entry/src/main/ets/storage目录下新建storage_manager.ets

import { AbilityContext } from '@ohos.application';
import preferences from '@ohos.data.preferences';
import { HarmonyStorageApi, StorageRequest, StorageResult } from '../pigeon/generated';
import { LogUtil } from '../utils/log_util';

export class HarmonyStorageApiImpl implements HarmonyStorageApi {
  private context: AbilityContext;
  private preferences: preferences.Preferences | null = null;
  private static const STORE_NAME = "harmony_flutter_store";

  constructor(context: AbilityContext) {
    this.context = context;
    // 初始化Preferences
    this.initPreferences();
  }

  // 初始化存储
  private async initPreferences() {
    try {
      this.preferences = await preferences.getPreferences(this.context, STORE_NAME);
      LogUtil.info("Preferences初始化成功");
    } catch (e) {
      LogUtil.error("Preferences初始化失败:${JSON.stringify(e)}");
    }
  }

  // 写入存储
  async setStorage(request: StorageRequest): Promise<StorageResult> {
    const result = new StorageResult();
    if (!this.preferences) {
      result.success = false;
      result.errorMsg = "存储初始化未完成";
      return result;
    }

    try {
      switch (request.valueType) {
        case "string":
          await this.preferences.putString(request.key, request.value as string);
          break;
        case "int":
          await this.preferences.putInt(request.key, request.value as number);
          break;
        case "bool":
          await this.preferences.putBool(request.key, request.value as boolean);
          break;
        case "double":
          await this.preferences.putDouble(request.key, request.value as number);
          break;
        default:
          result.success = false;
          result.errorMsg = "不支持的存储类型";
          return result;
      }
      // 提交变更
      await this.preferences.flush();
      result.success = true;
      result.errorMsg = "";
      return result;
    } catch (e) {
      result.success = false;
      result.errorMsg = `写入失败:${JSON.stringify(e)}`;
      LogUtil.error(result.errorMsg);
      return result;
    }
  }

  // 读取存储
  async getStorage(key: string): Promise<StorageResult> {
    const result = new StorageResult();
    if (!this.preferences) {
      result.success = false;
      result.errorMsg = "存储初始化未完成";
      return result;
    }

    try {
      // 先判断键是否存在
      const exists = await this.preferences.hasKey(key);
      if (!exists) {
        result.success = true;
        result.data = null;
        return result;
      }

      // 依次尝试不同类型读取(实际项目可优化存储类型记录)
      let value = await this.preferences.getString(key);
      if (value !== null) {
        result.data = value;
      } else {
        value = await this.preferences.getInt(key);
        if (value !== null) {
          result.data = value;
        } else {
          value = await this.preferences.getBool(key);
          if (value !== null) {
            result.data = value;
          } else {
            value = await this.preferences.getDouble(key);
            result.data = value;
          }
        }
      }

      result.success = true;
      result.errorMsg = "";
      return result;
    } catch (e) {
      result.success = false;
      result.errorMsg = `读取失败:${JSON.stringify(e)}`;
      LogUtil.error(result.errorMsg);
      return result;
    }
  }

  // 删除存储
  async removeStorage(key: string): Promise<StorageResult> {
    const result = new StorageResult();
    if (!this.preferences) {
      result.success = false;
      result.errorMsg = "存储初始化未完成";
      return result;
    }

    try {
      await this.preferences.delete(key);
      await this.preferences.flush();
      result.success = true;
      result.errorMsg = "";
      return result;
    } catch (e) {
      result.success = false;
      result.errorMsg = `删除失败:${JSON.stringify(e)}`;
      LogUtil.error(result.errorMsg);
      return result;
    }
  }

  // 清空存储
  async clearStorage(): Promise<StorageResult> {
    const result = new StorageResult();
    if (!this.preferences) {
      result.success = false;
      result.errorMsg = "存储初始化未完成";
      return result;
    }

    try {
      await this.preferences.clear();
      await this.preferences.flush();
      result.success = true;
      result.errorMsg = "";
      return result;
    } catch (e) {
      result.success = false;
      result.errorMsg = `清空失败:${JSON.stringify(e)}`;
      LogUtil.error(result.errorMsg);
      return result;
    }
  }
}
(3)Flutter 侧存储工具封装

lib/storage目录下新建storage_manager.dart,统一调用原生存储:

import 'package:flutter/foundation.dart';
import 'package:harmony_flutter_demo/pigeon/generated.dart';

class StorageManager {
  static final StorageManager _instance = StorageManager._internal();
  factory StorageManager() => _instance;
  StorageManager._internal();

  final HarmonyStorageApi _storageApi = HarmonyStorageApi();

  // 写入字符串
  Future<bool> setString(String key, String value) async {
    return _setStorage(key, value, "string");
  }

  // 写入整数
  Future<bool> setInt(String key, int value) async {
    return _setStorage(key, value, "int");
  }

  // 写入布尔值
  Future<bool> setBool(String key, bool value) async {
    return _setStorage(key, value, "bool");
  }

  // 写入浮点数
  Future<bool> setDouble(String key, double value) async {
    return _setStorage(key, value, "double");
  }

  // 通用写入方法
  Future<bool> _setStorage(String key, dynamic value, String valueType) async {
    try {
      final request = StorageRequest()
        ..key = key
        ..value = value
        ..valueType = valueType;
      final result = await _storageApi.setStorage(request);
      return result.success;
    } catch (e) {
      if (kDebugMode) print("存储失败:$e");
      return false;
    }
  }

  // 读取字符串
  Future<String?> getString(String key) async {
    final result = await _getStorage(key);
    return result.success ? result.data as String? : null;
  }

  // 读取整数
  Future<int?> getInt(String key) async {
    final result = await _getStorage(key);
    return result.success ? result.data as int? : null;
  }

  // 读取布尔值
  Future<bool?> getBool(String key) async {
    final result = await _getStorage(key);
    return result.success ? result.data as bool? : null;
  }

  // 读取浮点数
  Future<double?> getDouble(String key) async {
    final result = await _getStorage(key);
    return result.success ? result.data as double? : null;
  }

  // 通用读取方法
  Future<StorageResult> _getStorage(String key) async {
    try {
      return await _storageApi.getStorage(key);
    } catch (e) {
      if (kDebugMode) print("读取失败:$e");
      return StorageResult()
        ..success = false
        ..errorMsg = e.toString();
    }
  }

  // 删除存储
  Future<bool> remove(String key) async {
    try {
      final result = await _storageApi.removeStorage(key);
      return result.success;
    } catch (e) {
      if (kDebugMode) print("删除失败:$e");
      return false;
    }
  }

  // 清空存储
  Future<bool> clear() async {
    try {
      final result = await _storageApi.clearStorage();
      return result.success;
    } catch (e) {
      if (kDebugMode) print("清空失败:$e");
      return false;
    }
  }
}
(4)存储使用示例
// 写入用户登录态
await StorageManager().setString("token", "user_token_123456");
await StorageManager().setBool("isLogin", true);

// 读取用户登录态
final token = await StorageManager().getString("token");
final isLogin = await StorageManager().getBool("isLogin") ?? false;

// 删除存储
await StorageManager().remove("token");

// 清空存储
await StorageManager().clear();

3. 数据持久化避坑要点

  • 敏感数据(如 token、密码)需加密存储,鸿蒙侧可使用crypto模块,Flutter 侧可使用encrypt插件;
  • 存储键名需统一前缀(如app_),避免与其他应用冲突;
  • 大量数据存储优先使用数据库,避免键值对存储性能瓶颈;
  • 跨端读取时需处理数据类型转换,避免类型不匹配报错。

三、UI 自适应:多设备适配方案

鸿蒙系统支持手机、平板、手表等多设备,Flutter 侧需配合实现 “屏幕适配”“字体适配”“布局适配”,确保在不同设备上显示正常。

1. 屏幕适配基础(基于设备像素密度)

在 Flutter 模块lib/utils目录下新建screen_adapter.dart,封装适配工具:

import 'package:flutter/material.dart';

class ScreenAdapter {
  // 设计稿尺寸(以360x690为例)
  static const double designWidth = 360.0;
  static const double designHeight = 690.0;

  // 初始化屏幕参数
  static void init(BuildContext context) {
    final mediaQuery = MediaQuery.of(context);
    _screenWidth = mediaQuery.size.width;
    _screenHeight = mediaQuery.size.height;
    _pixelRatio = mediaQuery.devicePixelRatio;
    _statusBarHeight = mediaQuery.padding.top;
    _bottomInset = mediaQuery.padding.bottom;
  }

  static late double _screenWidth;
  static late double _screenHeight;
  static late double _pixelRatio;
  static late double _statusBarHeight;
  static late double _bottomInset;

  // 获取屏幕宽度
  static double get screenWidth => _screenWidth;

  // 获取屏幕高度
  static double get screenHeight => _screenHeight;

  // 获取状态栏高度
  static double get statusBarHeight => _statusBarHeight;

  // 获取底部安全区高度
  static double get bottomInset => _bottomInset;

  // 宽度适配(根据设计稿宽度比例缩放)
  static double width(double value) {
    return value * (_screenWidth / designWidth);
  }

  // 高度适配(根据设计稿高度比例缩放)
  static double height(double value) {
    return value * (_screenHeight / designHeight);
  }

  // 字体适配(基于宽度比例,避免高度拉伸导致字体变形)
  static double font(double value) {
    return width(value);
  }

  // 适配最小边长(用于正方形组件)
  static double minLength(double value) {
    final ratio = _screenWidth < _screenHeight
        ? _screenWidth / designWidth
        : _screenHeight / designHeight;
    return value * ratio;
  }
}

2. 适配实战示例

class AdaptedPage extends StatelessWidget {
  const AdaptedPage({super.key});

  @override
  Widget build(BuildContext context) {
    // 初始化适配工具
    ScreenAdapter.init(context);

    return Scaffold(
      appBar: AppBar(
        title: const Text("UI适配示例"),
        // 状态栏高度适配
        toolbarHeight: ScreenAdapter.height(50),
      ),
      body: Padding(
        // 内边距适配
        padding: EdgeInsets.symmetric(
          horizontal: ScreenAdapter.width(20),
          vertical: ScreenAdapter.height(15),
        ),
        child: Column(
          children: [
            // 容器尺寸适配
            Container(
              width: ScreenAdapter.width(320),
              height: ScreenAdapter.height(150),
              color: Colors.blue,
              child: Center(
                // 字体大小适配
                child: Text(
                  "适配不同屏幕尺寸",
                  style: TextStyle(
                    fontSize: ScreenAdapter.font(18),
                    color: Colors.white,
                  ),
                ),
              ),
            ),
            const SizedBox(height: 20),
            // 列表项适配
            ListView.builder(
              shrinkWrap: true,
              itemCount: 3,
              itemBuilder: (ctx, index) {
                return Container(
                  margin: EdgeInsets.only(bottom: ScreenAdapter.height(10)),
                  padding: EdgeInsets.all(ScreenAdapter.width(15)),
                  decoration: BoxDecoration(
                    border: Border.all(color: Colors.grey),
                    borderRadius: BorderRadius.circular(ScreenAdapter.width(8)),
                  ),
                  child: Row(
                    children: [
                      // 圆形头像适配
                      CircleAvatar(
                        radius: ScreenAdapter.minLength(30),
                        backgroundImage: const NetworkImage("https://example.com/avatar.jpg"),
                      ),
                      const SizedBox(width: 10),
                      Column(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: [
                          Text(
                            "列表项 ${index + 1}",
                            style: TextStyle(fontSize: ScreenAdapter.font(16)),
                          ),
                          Text(
                            "适配后的列表描述文本",
                            style: TextStyle(
                              fontSize: ScreenAdapter.font(14),
                              color: Colors.grey,
                            ),
                          ),
                        ],
                      ),
                    ],
                  ),
                );
              },
            ),
          ],
        ),
      ),
    );
  }
}

3. 鸿蒙侧原生 UI 适配配合

鸿蒙侧需确保 Flutter 容器尺寸自适应,修改MainAbility.ets中 Flutter 页面启动逻辑:

private startFlutterPage() {
  final engine = FlutterEngineManager().getGlobalEngine();
  if (engine == null) return;
  const intent = Intent();
  intent.setAction('android.intent.action.VIEW');
  intent.setParam('flutter_route', '/');
  intent.setParam('flutter_engine', engine);
  // 设置Flutter页面自适应尺寸
  intent.setParam('flutter_fullscreen', true);
  this.startAbility(intent);
}

4. UI 适配避坑要点

  • 所有尺寸相关数值必须通过适配工具计算,禁止硬编码固定值;
  • 字体适配优先基于宽度比例,避免在平板等宽屏设备上字体过大;
  • 图片资源建议使用 SVG 格式,或提供多分辨率图片(hdpi/xhdpi/xxhdpi);
  • 复杂布局使用FlexWrap等自适应组件,避免使用固定宽高的绝对布局。

四、调试与优化技巧

1. 跨端调试工具组合

  • 网络请求调试:使用 Charles 抓包,统一配置代理查看 Flutter 和鸿蒙侧的网络请求;
  • 存储调试:鸿蒙侧通过Preferences工具查看存储数据,Flutter 侧使用shared_preferences_dev_tools插件;
  • UI 调试:Flutter 侧打开 DevTools 的 Layout Inspector,鸿蒙侧使用 DevEco Studio 的 UI 预览功能;
  • 日志调试:统一日志标签(如HarmonyFlutter),通过 Logcat 过滤查看跨端通信日志。

2. 性能优化要点

  • 路由优化:使用 “预加载” 机制,提前初始化常用页面,减少跳转延迟;
  • 存储优化:频繁读取的数据缓存到内存,避免重复 IO 操作;
  • UI 优化:Flutter 侧使用const构造函数、ListView.builder懒加载,减少 Widget 重建;
  • 引擎优化:坚持全局引擎复用,避免频繁创建销毁引擎(之前章节已实现)。

总结

本文围绕鸿蒙 + Flutter 混合开发的三大核心进阶场景,提供了可直接落地的完整解决方案:通过 Pigeon 强类型接口实现跨端路由统一管理,解决了页面跳转和参数传递的稳定性问题;通过原生存储 + 跨端同步方案,确保了数据持久化的安全性和一致性;通过屏幕适配工具和自适应布局,实现了多设备兼容。

Logo

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

更多推荐