Files
tongxunruanjian/mobile-next/openim_common/lib/src/utils/api_service.dart
T
编码工程师andmultica-agent 8046ec7483 feat(mobile-next): 导入官方 openim-flutter-demo 固定基线 3.8.3-patch.3 并完成双构建
- 上游: github.com/OpenIMSDK/openim-flutter-demo tag 3.8.3-patch.3
  commit b3dfdb1e8aaeaaf6f0793e10cadd20d5c184a31f
- 并行目录 mobile-next/ 原样导入(含 LICENSE),不覆盖现网 mobile/
- 锁定 Flutter 3.24.5 / Dart 3.5.4 / JDK 17 / Gradle 7.6.3 / AGP 7.3.1
- 实测 Android debug 与 release 构建均成功(见 docs/mobile-next-baseline-import.md)
- 本提交可单独回退:git revert 1db1229(重写前)

Co-authored-by: multica-agent <github@multica.ai>
2026-08-19 15:24:33 +08:00

162 lines
4.0 KiB
Dart

import 'dart:convert';
import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:openim_common/openim_common.dart';
import 'package:talker_dio_logger/talker_dio_logger.dart';
class ApiService {
static final _instance = ApiService._internal();
factory ApiService() {
return _instance;
}
final Dio dio = Dio();
ApiService._internal() {
final talkerDioLogger = TalkerDioLogger(
settings: const TalkerDioLoggerSettings(
printRequestHeaders: kDebugMode,
printRequestData: kDebugMode,
printResponseMessage: kDebugMode,
printResponseData: kDebugMode,
printResponseHeaders: false,
),
);
dio.options
..connectTimeout = const Duration(seconds: 30)
..receiveTimeout = const Duration(seconds: 30);
dio.interceptors
..add(talkerDioLogger)
..add(
InterceptorsWrapper(
onRequest: (options, handler) {
return handler.next(options); //continue
},
onResponse: (response, handler) {
return handler.next(response); // continue
},
onError: (DioException e, handler) {
return handler.next(e); //continue
},
),
);
dio.options.connectTimeout = const Duration(seconds: 30);
dio.options.receiveTimeout = const Duration(seconds: 30);
}
void setBaseUrl(String baseUrl) {
dio.options.baseUrl = baseUrl;
}
void setToken(String token) {
dio.options.headers['token'] = token;
}
Future get(String path, {Map<String, dynamic>? queryParams}) async {
try {
dio.options.headers['operationID'] = DateTime.now().millisecondsSinceEpoch.toString();
final response = await dio.get(path, queryParameters: queryParams);
if (response.statusCode == 200) {
final result = ApiResponse.fromJson(response.data as Map<String, dynamic>);
if (result.errCode == 0) {
return result.data;
} else {
return Future.error(result.errMsg);
}
}
return Future.error(response.data);
} on DioException catch (e) {
_handleError(e);
rethrow;
}
}
Future post(String path, {Map<String, dynamic>? data, String? token}) async {
try {
final operationID = DateTime.now().millisecondsSinceEpoch.toString();
dio.options.headers['operationID'] = operationID;
final response = await dio.post(path, data: data);
if (response.statusCode == 200) {
final result = ApiResponse.fromJson(response.data as Map<String, dynamic>);
if (result.errCode == 0) {
return result.data;
} else {
final exception = ApiException(code: result.errCode, message: result.errMsg, operationID: operationID);
return Future.error(exception);
}
}
return Future.error(response.data);
} on DioException catch (e) {
_handleError(e);
rethrow;
}
}
Future download(
String url, {
required String cachePath,
CancelToken? cancelToken,
Function(int count, int total)? onProgress,
}) {
return dio.download(
url,
cachePath,
cancelToken: cancelToken,
onReceiveProgress: onProgress,
);
}
void _handleError(DioException error) {
Logger.print('DioError: ${error.message}', isError: true);
}
}
class ApiResponse {
int errCode;
String errMsg;
String errDlt;
dynamic data;
ApiResponse.fromJson(Map<String, dynamic> map)
: errCode = map["errCode"] ?? -1,
errMsg = map["errMsg"] ?? '',
errDlt = map["errDlt"] ?? '',
data = map["data"];
Map<String, dynamic> toJson() {
final data = <String, dynamic>{};
data['errCode'] = errCode;
data['errMsg'] = errMsg;
data['errDlt'] = errDlt;
data['data'] = data;
return data;
}
@override
String toString() {
return jsonEncode(this);
}
}
class ApiException implements Exception {
final int code;
final String? message;
final String? operationID;
ApiException({required this.code, this.message, this.operationID});
}