鸿蒙 + Flutter 混合开发进阶实战:路由跳转、数据持久化与 UI 适配全攻略
本文围绕鸿蒙 + Flutter 混合开发的三大核心进阶场景,提供了可直接落地的完整解决方案:通过 Pigeon 强类型接口实现跨端路由统一管理,解决了页面跳转和参数传递的稳定性问题;通过原生存储 + 跨端同步方案,确保了数据持久化的安全性和一致性;通过屏幕适配工具和自适应布局,实现了多设备兼容。
对于完成基础环境搭建和入门 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);
- 复杂布局使用
Flex、Wrap等自适应组件,避免使用固定宽高的绝对布局。
四、调试与优化技巧
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 强类型接口实现跨端路由统一管理,解决了页面跳转和参数传递的稳定性问题;通过原生存储 + 跨端同步方案,确保了数据持久化的安全性和一致性;通过屏幕适配工具和自适应布局,实现了多设备兼容。
更多推荐



所有评论(0)