02. 高性能网络层架构与鸿蒙权限管理
1. 鸿蒙网络通信机制解析
在 Flutter 鸿蒙应用中,网络请求本质上是通过 Dart 的 dart:io 库发起的。Flutter 引擎会将这些 Dart IO 请求桥接到鸿蒙底层的网络栈。
1.1 鸿蒙特有的网络约束
- 权限强制声明:必须在
module.json5中声明ohos.permission.INTERNET,否则请求会直接抛出 SocketException。 - 明文流量限制:默认情况下,鸿蒙系统(类似于 Android 9+)禁止 HTTP 明文请求。虽然 GitCode API 使用 HTTPS,但我们在调试阶段(连接本地 Mock Server)可能需要 HTTP 支持。
- 解决方案:在
module.json5的module节点配置"network": { "cleartextTraffic": true }(需 API 11+ 支持)。
- 解决方案:在
2. 基于 Dio 的网络层封装
我们使用 Dio 作为网络库,它在鸿蒙上运行良好。
2.1 ApiClient 设计
单例模式管理 Dio 实例,确保连接池复用。
// lib/core/network/api_client.dart
import 'package:dio/dio.dart';
import 'package:dio/io.dart'; // 用于配置证书忽略等
class ApiClient {
static final ApiClient _instance = ApiClient._internal();
factory ApiClient() => _instance;
late final Dio dio;
ApiClient._internal() {
dio = Dio(BaseOptions(
baseUrl: 'https://api.gitcode.com/api/v5',
connectTimeout: const Duration(seconds: 15),
receiveTimeout: const Duration(seconds: 15),
headers: {
'User-Agent': 'GitCodePocket-Harmony/1.0.0',
'Accept': 'application/json',
},
));
_setupInterceptors();
_setupCertificatePinning();
}
}
2.2 抓包调试配置
在鸿蒙真机上调试时,我们经常需要使用 Charles/Fiddler 抓包。这需要配置代理和忽略证书错误。
void _setupCertificatePinning() {
// 仅在调试模式下开启代理
if (kDebugMode) {
dio.httpClientAdapter = IOHttpClientAdapter(
createHttpClient: () {
final client = HttpClient();
// 设置代理地址 (Charles 运行的主机 IP)
client.findProxy = (uri) => 'PROXY 192.168.1.5:8888';
// 忽略自签名证书错误
client.badCertificateCallback =
(X509Certificate cert, String host, int port) => true;
return client;
},
);
}
}
3. 拦截器链 (Interceptor Chain)
拦截器是网络层逻辑解耦的关键。
3.1 统一鉴权拦截器
GitCode API 支持 OAuth 2.0,我们需要在每次请求头中动态注入 Access Token。
class AuthInterceptor extends Interceptor {
final TokenRepository _tokenRepo;
AuthInterceptor(this._tokenRepo);
void onRequest(RequestOptions options, RequestInterceptorHandler handler) async {
final token = await _tokenRepo.getAccessToken();
if (token != null) {
options.headers['Authorization'] = 'Bearer $token';
}
super.onRequest(options, handler);
}
}
3.2 响应数据转换器
为了让业务层直接拿到干净的数据,我们可以在拦截器中统一处理 API 响应结构。
// 假设 API 返回结构: { "code": 200, "message": "ok", "data": ... }
class ResponseInterceptor extends Interceptor {
void onResponse(Response response, ResponseInterceptorHandler handler) {
if (response.statusCode == 200) {
// 这里可以直接解包,或者透传
handler.next(response);
} else {
handler.reject(
DioException(
requestOptions: response.requestOptions,
error: 'Server Error: ${response.statusCode}',
),
);
}
}
}
4. 业务接口定义 (RemoteService)
我们不直接在 UI 层使用 Dio,而是定义具体的 Service 类。
4.1 用户相关接口
class GitcodeRemoteService {
final Dio _dio;
GitcodeRemoteService(this._dio);
// 获取当前登录用户信息
Future<User> fetchCurrentUser() async {
try {
final response = await _dio.get('/user');
return User.fromJson(response.data);
} on DioException catch (e) {
throw ServerException.fromDio(e);
}
}
// 获取用户组织
Future<List<Organization>> fetchOrganizations() async {
final response = await _dio.get('/user/orgs');
return (response.data as List)
.map((e) => Organization.fromJson(e))
.toList();
}
}
5. 错误处理模型
鸿蒙应用的网络错误可能来自于底层(如 SocketException 对应鸿蒙的断网状态)。我们需要将这些底层错误转换为 UI 层可读的 Failure 对象。
abstract class Failure {
final String message;
Failure(this.message);
}
class NetworkFailure extends Failure {
NetworkFailure() : super("网络连接异常,请检查鸿蒙设备的网络设置");
}
class ServerFailure extends Failure {
ServerFailure(String msg) : super(msg);
}
// 异常转换工厂
Failure handleException(dynamic e) {
if (e is DioException) {
if (e.type == DioExceptionType.connectionTimeout) {
return NetworkFailure();
}
// 处理 401, 403, 404 等
}
return ServerFailure("未知错误");
}
6. 鸿蒙网络状态监听
为了在断网时给出及时反馈,我们需要监听鸿蒙系统的网络状态。
可以使用 connectivity_plus(需确认鸿蒙适配版本)或者通过 MethodChannel 调用鸿蒙原生的 connection 模块。
ArkTS 侧实现 (EntryAbility.ets):
import connection from '@ohos.net.connection';
// 监听网络连接
let netCon = connection.createNetConnection();
netCon.on('netAvailable', (data) => {
flutterChannel.invokeMethod('onNetworkAvailable');
});
netCon.on('netLost', (data) => {
flutterChannel.invokeMethod('onNetworkLost');
});
7. 总结
本章我们构建了一个健壮的网络层。虽然 Dio 在鸿蒙上运行流畅,但我们必须注意权限配置、抓包调试的特殊设置以及底层网络状态的监听。
下一章,我们将深入 认证与安全存储,利用鸿蒙系统的加密能力保护用户的 Token。

被折叠的 条评论
为什么被折叠?



