callExperimentalAPI method
Implementation
Future<V2TimValueCallback<Object>> callExperimentalAPI({
required String api,
Object? param,
}) async {
Map<String, dynamic> cJsonParam = {};
if (param is Map<String, dynamic>) {
cJsonParam = Map<String, dynamic>.from(param);
}
cJsonParam['request_internal_operation'] = api;
// C 层直接通过返回值传递数据,不走回调
if (api == 'internal_operation_get_login_account_type') {
Pointer<Char> pCJsonParam = Tools.string2PointerChar(json.encode(cJsonParam));
Pointer<Void> pUserData = Tools.string2PointerVoid('');
int accountType = NativeLibraryManager.bindings.DartCallExperimentalAPI(pCJsonParam, pUserData);
Tools.freePointers([pCJsonParam, pUserData]);
return V2TimValueCallback<Object>(code: 0, desc: '', data: accountType);
}
// C 层同步操作,不会触发回调,直接返回结果
if (_syncExperimentalAPIs.contains(api)) {
Pointer<Char> pCJsonParam = Tools.string2PointerChar(json.encode(cJsonParam));
Pointer<Void> pUserData = Tools.string2PointerVoid('');
int result = NativeLibraryManager.bindings.DartCallExperimentalAPI(pCJsonParam, pUserData);
Tools.freePointers([pCJsonParam, pUserData]);
if (result != TIMResult.TIM_SUCC.value) {
return V2TimValueCallback<Object>(code: TIMErrCode.ERR_INVALID_PARAMETERS.value, desc: "invalid parameter");
}
return V2TimValueCallback<Object>(code: 0, desc: '');
}
// C 层异步操作,通过回调返回结果
String userData = Tools.generateUserData('callExperimentalAPI');
Completer<V2TimValueCallback<Object>> completer = Completer();
NativeLibraryManager.addTimValueCallback2Map<Object>(userData, completer);
completer.future.whenComplete(() => NativeLibraryManager.removeTimCallbackFromMap(userData));
Pointer<Char> pCJsonParam = Tools.string2PointerChar(json.encode(cJsonParam));
Pointer<Void> pUserData = Tools.string2PointerVoid(userData);
int result = NativeLibraryManager.bindings.DartCallExperimentalAPI(pCJsonParam, pUserData);
if (result != TIMResult.TIM_SUCC.value) {
completer.complete(V2TimValueCallback<Object>(
code: TIMErrCode.ERR_INVALID_PARAMETERS.value, desc: "invalid parameter"));
}
// 用 Timer + completer.complete 替代 Future.timeout:
// - 原 Future.timeout 创建的是新 future,原 completer.future 在超时后依然 pending,
// 会导致上方手挂的 whenComplete 不触发 → map 中 closure 泄漏,且若 native 5s
// 后真回调还会触发 .then 的 freePointers 二次释放(与 onTimeout 已 free 的指针冲突)。
// - 改成 Timer 主动 complete 后,所有路径都汇聚到同一个 completer.future:
// whenComplete 必触发一次清理,freePointers 也只会执行一次。
final Timer timeoutTimer = Timer(const Duration(seconds: 5), () {
if (!completer.isCompleted) {
completer.complete(V2TimValueCallback<Object>(
code: TIMErrCode.ERR_INVALID_PARAMETERS.value,
desc: "callExperimentalAPI timeout, api: $api"));
}
});
return completer.future.then((value) {
timeoutTimer.cancel();
Tools.freePointers([pCJsonParam, pUserData]);
return value;
});
}