fix: 1.优化上报逻辑,防止一样的token重复上报

2.请求头添加deviceId,为后续设备管理业务预留数据
This commit is contained in:
Liuyf 2025-02-26 19:08:46 +08:00
parent a77cb10caf
commit 50257a7ffe
5 changed files with 99 additions and 51 deletions

View File

@ -28,5 +28,10 @@ FutureOr<Request> requestInterceptor(Request request) async {
xToken = LoginData.fromJson(jsonDecode(data)).accessToken;
}
request.headers['Authorization'] = "Bearer ${xToken ?? ''}";
final String? deviceID = await Storage.getString(appDeviceID);
if (deviceID != null && deviceID.isNotEmpty) {
request.headers['deviceID'] = deviceID;
}
return request;
}

View File

@ -1,12 +1,20 @@
import 'package:get/get.dart';
import '../../network/api_provider.dart';
import '../../network/api_repository.dart';
import 'package:star_lock/tools/storage.dart';
import 'package:uuid/uuid.dart';
class AppBindings extends Bindings {
@override
void dependencies() {
initDeviceId();
}
}
Future<void> initDeviceId() async {
final String? deviceID = await Storage.getString(appDeviceID);
final bool isNullOrBlank = GetUtils.isNullOrBlank(deviceID) ?? true;
if (isNullOrBlank) {
final String uuidV4 = const Uuid().v4();
print('initDeviceId UUID:v4: $uuidV4');
await Storage.setString(appDeviceID, uuidV4);
}
}
}

View File

@ -0,0 +1,23 @@
import 'dart:async';
import 'package:flutter/widgets.dart';
class DebounceThrottleTool<T> {
DebounceThrottleTool(this._debounceTime, this._callback);
Timer? _timer;
final Duration _debounceTime;
final void Function(T param) _callback;
void trigger(T param) {
_timer?.cancel();
_timer = Timer(_debounceTime, () {
_callback(param);
_timer = null;
});
}
void cancel() {
_timer?.cancel();
}
}

View File

@ -1,5 +1,6 @@
import 'dart:async';
import 'dart:convert';
import 'dart:ffi';
import 'dart:io';
import 'package:flutter/foundation.dart';
@ -9,6 +10,7 @@ import 'package:star_lock/flavors.dart';
import 'package:star_lock/mine/minePersonInfo/minePersonInfoEditAccount/minePersonInfoEditAccount/mineUnbindPhoneOrEmail_entity.dart';
import 'package:star_lock/network/api_repository.dart';
import 'package:star_lock/tools/baseGetXController.dart';
import 'package:star_lock/tools/debounce_throttle_tool.dart';
import 'package:star_lock/tools/push/message_management.dart';
import 'package:star_lock/tools/push/notification_service.dart';
import 'package:star_lock/tools/storage.dart';
@ -28,31 +30,32 @@ class XSJPushProvider {
9: 'jiguang'
};
final JPush jpush = JPush();
Completer<Map<String, dynamic>>? _jpushRegistrationIdCompleter;
Completer<Map<String, dynamic>>? _vendorTokenCompleter;
DebounceThrottleTool? _debounceThrottleTool;
Future<void> resetJPushService() async {
debugPrint("resetJPushService start");
jpush.setup(
appKey: '',
channel: 'flutter_channel',
production: F.isProductionEnv,
debug: !F.isProductionEnv,
);
for (final MapEntry<int, String> entry in channelTypeMapping.entries) {
await Storage.removeData('old_${entry.value}');
}
debugPrint("resetJPushService end");
}
// appKey: 251fc8074820d122b6de58d2--AppKey
// appKey: 7ff37d174c1a568a89e98dad--sky
Future<void> initJPushService() async {
debugPrint("initJPushService start");
_jpushRegistrationIdCompleter = Completer<Map<String, dynamic>>();
_vendorTokenCompleter = Completer<Map<String, dynamic>>();
final String? data = await Storage.getString(saveUserLoginData);
if (data == null || data.isEmpty) {
AppLog.log('No user data found.');
return;
}
_debounceThrottleTool = DebounceThrottleTool(
const Duration(milliseconds: 1500),
(dynamic param) {
bindPushChannels();
},
);
AppLog.log('jPushKey ${F.jPushKey}');
// final String? bundleIdentifier =
// await NativeInteractionTool().getBundleIdentifier();
@ -86,35 +89,20 @@ class XSJPushProvider {
case CMD_GET_REGISTRATION_ID:
final bool isNullOrBlank =
GetUtils.isNullOrBlank(data['message']) ?? true;
if (!(_jpushRegistrationIdCompleter?.isCompleted ?? true) &&
!isNullOrBlank) {
await Storage.setString(pushDeviceID, data['message']);
AppLog.log('flutter get registration id : ${data['message']}');
_jpushRegistrationIdCompleter?.complete(<String, dynamic>{
'channel': 'jiguang',
'channelToken': data['message']
});
final String? channel2TokenStr =
await Storage.getString(vendorPushChannelInfo);
if (Platform.isAndroid &&
!(_vendorTokenCompleter?.isCompleted ?? true) &&
channel2TokenStr != null) {
_vendorTokenCompleter?.complete(jsonDecode(channel2TokenStr));
}
if (!isNullOrBlank) {
AppLog.log(
'flutter get jiguang registration id : ${data['message']}');
await Storage.setString('jiguang', data['message']);
_debounceThrottleTool?.trigger(data['message']);
}
break;
case CMD_GET_TOKEN:
final bool isNullOrBlank =
GetUtils.isNullOrBlank(data['token']) ?? true;
if (!(_vendorTokenCompleter?.isCompleted ?? true) &&
!isNullOrBlank) {
final Map<String, dynamic> channel2Token = <String, dynamic>{
'channel': channelTypeMapping[data['platform']],
'channelToken': data['token']
};
if (!isNullOrBlank) {
await Storage.setString(
vendorPushChannelInfo, jsonEncode(channel2Token));
_vendorTokenCompleter?.complete(channel2Token);
channelTypeMapping[data['platform']] ?? '', data['token']);
_debounceThrottleTool?.trigger(data['token']);
}
break;
}
@ -147,31 +135,54 @@ class XSJPushProvider {
return Future.value();
},
);
bindPushChannels();
}
// jpush
Future<void> bindPushChannels() async {
try {
if (_jpushRegistrationIdCompleter == null ||
_vendorTokenCompleter == null) {
debugPrint("BindPushChannels start");
bool needReBindPushToken = false;
final Map<String, String> newVendorsPushToken = <String, String>{};
final Map<String, String> oldVendorsPushToken = <String, String>{};
for (final String channel in channelTypeMapping.values) {
debugPrint("BindPushChannels channel $channel");
final String? newVendorToken = await Storage.getString(channel);
debugPrint("BindPushChannels newVendorToken $newVendorToken");
newVendorsPushToken[channel] = newVendorToken ?? '';
final String? oldVendorToken = await Storage.getString('old_$channel');
debugPrint("BindPushChannels oldVendorToken $oldVendorToken");
oldVendorsPushToken['old_$channel'] = oldVendorToken ?? '';
if (newVendorToken != oldVendorToken) {
needReBindPushToken = true;
}
}
if (!needReBindPushToken) {
AppLog.log('vendorToken 未变动,无需重新绑定');
return;
}
debugPrint("await PushChannels start");
final List<Map<String, dynamic>> channels = await Future.wait([
_jpushRegistrationIdCompleter!.future,
_vendorTokenCompleter!.future
]);
final String? registrationId = await Storage.getString(pushDeviceID);
debugPrint("await PushChannels end");
final List<Map<String, dynamic>> channels = newVendorsPushToken.entries
.where((entry) => !(GetUtils.isNullOrBlank(entry.value) ?? true))
.map((entry) => <String, dynamic>{
'channel': entry.key,
'channelToken': entry.value
})
.toList();
debugPrint("BindPushChannels ${channels}");
final String? deviceID = await Storage.getString(appDeviceID);
final MineUnbindPhoneOrEmailEntity entity =
await ApiRepository.to.pushBindChannels(registrationId!, channels);
await ApiRepository.to.pushBindChannels(deviceID!, channels);
if (entity.errorCode!.codeIsSuccessful) {
AppLog.log('绑定成功');
AppLog.log('vendorToken绑定成功准备更新本地缓存');
await Future.wait(channels.map((Map<String, dynamic> entry) =>
Storage.setString(
'old_${entry['channel']}', entry['channelToken'])));
AppLog.log('vendorToken绑定成功更新本地缓存完成');
} else {
AppLog.log('绑定失败');
}
} catch (e) {
AppLog.log('vendorToken绑定失败下次重启应用重新绑定');
AppLog.log('Error binding device ID: $e');
}
}

View File

@ -24,7 +24,8 @@ const String isAgreeCamera = 'isAgreeCamera'; //是否同意获取相机/相册
const String isShowUpdateVersion = 'isShowUpdateVersion'; //
const String saveLockAlias = 'saveLockAlias'; //
const String pushDeviceID = 'pushDeviceID'; //ID
const String appDeviceID = 'appDeviceID'; //ID
const String pushDeviceID = 'pushDeviceID'; //Jpush推送设备ID
const String vendorPushChannelInfo = 'pushChannelInfo'; //ID
const String saveIsVip = 'saveIsVip'; //VIP