Flutter 与 OpenHarmony 网络请求协同优化:统一拦截、安全校验与离线策略


引言
在混合开发场景中,Flutter 应用常需调用 OpenHarmony 原生能力以满足国产化合规要求,其中网络通信尤为关键。OpenHarmony 对网络权限、HTTPS 校验、代理配置等有严格管控,而 Flutter 默认使用 Dart 的 http 或 dio 库,其底层基于 POSIX socket,在 OpenHarmony 上可能面临:
- 权限拒绝:未声明
ohos.permission.INTERNET; - 证书校验失败:系统强制启用 TLS 安全策略;
- 无法复用系统网络栈:如企业代理、国密算法支持;
- 离线场景处理缺失:未与 OpenHarmony 的网络状态监听联动。
若直接在 Flutter 中发起网络请求,轻则功能异常,重则违反安全规范。本文提出一种 “原生代理 + 统一拦截” 的网络协同架构,并通过代码案例展示如何让 Flutter 安全、高效、合规地访问网络。
一、OpenHarmony 网络安全机制要点
1. 权限声明(必须)
在 module.json5 中显式申请:
{
"requestPermissions": [
{ "name": "ohos.permission.INTERNET" },
{ "name": "ohos.permission.GET_NETWORK_INFO" }
]
}
2. HTTPS 强制校验
- 默认禁止 HTTP 明文请求(可配置
network_security_config.xml临时允许); - 证书需由受信任 CA 签发,或通过 自定义 TrustManager 注入。
3. 网络状态监听
可通过 @ohos.net.connection 监听网络类型(Wi-Fi/蜂窝)、是否在线等。
二、为什么不应让 Flutter 直连网络?
| 风险点 | 说明 |
|---|---|
| 绕过系统安全策略 | Dart 的 HttpClient 不走 OpenHarmony 的网络安全框架,可能被拦截 |
| 无法适配国产加密标准 | 如 SM2/SM4 国密算法,需依赖系统级支持 |
| 企业网络环境不兼容 | 代理、证书透明度(CT)等需系统级配置 |
| 电量与流量监控失效 | 系统无法统计 Flutter 进程的网络消耗 |
✅ 最佳实践:
所有网络请求应由 OpenHarmony 原生层代理执行,Flutter 仅负责业务逻辑与 UI。
三、协同架构设计
+------------------+ MethodChannel +-----------------------+
| Flutter (Dart) | -------------------------> | OpenHarmony (ArkTS) |
| - 发起 API 请求 | <------------------------- | - 使用 @ohos.net.http |
| - 处理 JSON 响应 | | - 统一拦截/重试/缓存 |
+------------------+ +-----------------------+
↑
网络状态监听 & 安全校验
核心优势:
- 复用 OpenHarmony 安全网络栈;
- 统一处理 Token 刷新、错误码拦截;
- 支持离线缓存、请求队列;
- 符合等保与国产化审计要求。
四、代码实践
步骤 1:Flutter 端定义网络服务接口
// lib/services/oh_http_client.dart
import 'package:flutter/services.dart';
class OHHttpClient {
static const _channel = MethodChannel('com.example.network');
static Future<Map<String, dynamic>> get(String url,
{Map<String, String>? headers}) async {
final args = <String, dynamic>{
'method': 'GET',
'url': url,
'headers': headers ?? {},
};
final result = await _channel.invokeMethod('request', args);
return result as Map<String, dynamic>;
}
static Future<Map<String, dynamic>> post(String url,
{Map<String, dynamic>? body, Map<String, String>? headers}) async {
final args = <String, dynamic>{
'method': 'POST',
'url': url,
'body': body,
'headers': headers ?? {},
};
final result = await _channel.invokeMethod('request', args);
return result as Map<String, dynamic>;
}
}
返回格式约定:
{ "code": 200, "data": {...}, "message": "" }
步骤 2:OpenHarmony 端实现网络代理
// model/NetworkBridge.ts
import http from '@ohos.net.http';
import connection from '@ohos.net.connection';
export class NetworkBridge {
private netCap: connection.NetCap | null = null;
constructor() {
this.initNetworkListener();
}
private initNetworkListener() {
// 监听网络状态变化(用于离线提示)
connection.getDefaultNet().then(net => {
this.netCap = net.getNetCap();
net.on('netAvailable', () => console.log('Network available'));
net.on('netUnavailable', () => console.log('Network lost'));
});
}
async request(options: {
method: string;
url: string;
headers?: Record<string, string>;
body?: Record<string, any>;
}): Promise<Record<string, any>> {
// 检查网络是否可用
if (!this.netCap?.isAvailable()) {
return { code: -1, message: '网络不可用', data: null };
}
const httpRequest = http.createHttp();
let extraData: http.HttpRequestOptions = {
method: options.method as http.RequestMethod,
header: options.headers || {},
expectDataType: http.HttpDataType.STRING
};
if (options.method === 'POST' && options.body) {
extraData = {
...extraData,
extraData: JSON.stringify(options.body)
};
}
try {
const response = await httpRequest.request(options.url, extraData);
// 统一处理响应
if (response.responseCode >= 200 && response.responseCode < 300) {
const data = JSON.parse(response.result as string);
return { code: 0, data, message: 'success' };
} else {
return { code: response.responseCode, message: '请求失败', data: null };
}
} catch (err) {
console.error('Network error:', err);
return { code: -2, message: '网络异常', data: null };
} finally {
httpRequest.destroy();
}
}
}
步骤 3:在 EntryAbility 中注册通道
// EntryAbility.ts
import UIAbility from '@ohos/app.ability.UIAbility';
import { MethodChannel } from '@ohos/flutter';
import { NetworkBridge } from './model/NetworkBridge';
export default class EntryAbility extends UIAbility {
private networkBridge: NetworkBridge;
onCreate() {
this.networkBridge = new NetworkBridge();
const channel = new MethodChannel('com.example.network');
channel.setMethodCallHandler(async (call) => {
if (call.method === 'request') {
return await this.networkBridge.request(call.arguments as any);
}
throw new Error('Unknown method');
});
}
}
步骤 4:Flutter 页面调用示例
// lib/pages/user_profile.dart
import 'package:flutter/material.dart';
import '../services/oh_http_client.dart';
class UserProfilePage extends StatefulWidget {
_UserProfilePageState createState() => _UserProfilePageState();
}
class _UserProfilePageState extends State<UserProfilePage> {
String _status = '点击加载';
Map<String, dynamic>? _user;
Future<void> _loadUser() async {
setState(() => _status = '加载中...');
try {
final response = await OHHttpClient.get(
'https://api.example.com/user/123',
headers: {'Authorization': 'Bearer xxx'}
);
if (response['code'] == 0) {
setState(() {
_user = response['data'];
_status = '加载成功';
});
} else {
_status = '错误: ${response['message']}';
}
} catch (e) {
_status = '异常: $e';
}
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('用户信息')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(_status),
if (_user != null) Text('姓名: ${_user!['name']}'),
ElevatedButton(onPressed: _loadUser, child: Text('获取用户信息')),
],
),
),
);
}
}
五、高级能力扩展
1. 统一 Token 刷新
在 NetworkBridge.request() 中拦截 401,自动调用登录接口刷新 Token。
2. 离线缓存
- 网络不可用时,从 OpenHarmony 的
Preferences或KV Store读取缓存; - 请求成功后自动更新缓存。
3. 国密支持
通过 @ohos.security.cryptoFramework 注入 SM2 公钥,对请求体签名。
4. 请求日志审计
记录所有请求 URL、时间、耗时,满足等保日志留存要求。
六、注意事项
1. 避免阻塞主线程
OpenHarmony 的 http.request 采用异步设计,开发者必须确保网络请求不会阻塞 UI 线程。建议采用以下方式:
- 使用
Promise或async/await语法处理异步请求 - 在回调函数中更新 UI 时,务必通过
TaskDispatcher切换到主线程 - 示例代码:
http.request({
// 请求配置
}, (err, data) => {
// 回调处理
context.resourceManager.getTaskDispatcher('main').asyncDispatch(() => {
// 更新UI操作
});
});
2. 超时设置
合理的超时设置对应用稳定性至关重要:
readTimeout默认值为 60 秒- 可根据网络环境动态调整:
const options = {
readTimeout: 10000, // 10秒超时
// 其他配置...
}
http.request(url, options, callback);
- 建议值:
- WiFi环境:5-10秒
- 移动网络:10-15秒
- 大文件下载:适当延长
3. 敏感信息保护
安全开发规范要求:
- 所有认证信息(Token、API Key等)必须加密存储
- 禁止在日志中输出完整敏感信息,如需调试可显示部分字符(如"token: abc…xyz")
- 推荐使用系统提供的安全存储接口:
import security from '@ohos.security';
// 存储敏感数据
security.cryptoFramework.createCipher().then(...);
4. HTTPS 证书管理
安全连接配置要点:
- 生产环境必须使用正规CA颁发的证书
- 开发阶段如需使用自签名证书:
- 准备证书文件(.crt/.pem)
- 在
resources/base/profile/network_security_config.xml中添加配置:
<domain-config cleartextTrafficPermitted="false">
<domain includeSubdomains="true">yourdomain.com</domain>
<trust-anchors>
<certificates src="@raw/your_certificate"/>
</trust-anchors>
</domain-config>
- 证书文件需放在
resources/rawfile目录 - 正式发布前务必移除测试证书配置
七、总结
通过将网络请求委托给 OpenHarmony 原生层,我们不仅规避了安全合规风险,还获得了系统级网络能力的支持。这种“Flutter 负责 UI 与逻辑,OpenHarmony 负责系统交互”的分工模式,是构建高质量国产混合应用的最佳实践。
未来,随着 OpenHarmony 对 WebAssembly 和更高效 IPC 的支持,网络桥接性能将进一步提升。但现阶段,MethodChannel + 原生代理仍是稳定可靠的选择。
!**
更多推荐

所有评论(0)