feat: 多端邀请接入
This commit is contained in:
@@ -25,11 +25,15 @@ import 'package:kaer_with_panels/app/widgets/dialogs/hi_dialog.dart';
|
||||
import 'package:kaer_with_panels/app/services/api_service/kr_auth_api.dart';
|
||||
import 'package:kaer_with_panels/app/services/kr_subscribe_service.dart';
|
||||
import 'package:kaer_with_panels/app/utils/kr_common_util.dart';
|
||||
import 'package:kaer_with_panels/app/utils/kr_device_util.dart';
|
||||
import 'package:openinstall_flutter_plugin/openinstall_flutter_plugin.dart';
|
||||
import 'dart:io' show Platform;
|
||||
|
||||
class KRAppRunData {
|
||||
static final KRAppRunData _instance = KRAppRunData._internal();
|
||||
|
||||
static const String _keyUserInfo = 'USER_INFO';
|
||||
static const bool inviteDebugMode = true;
|
||||
|
||||
/// 登录token
|
||||
String? kr_token;
|
||||
@@ -61,6 +65,9 @@ class KRAppRunData {
|
||||
// 需要被监听的属性,用 obs 包装
|
||||
final kr_isLogin = false.obs;
|
||||
|
||||
// 存储临时待绑定的邀请码(处理唤醒数据比登录完成早的情况)
|
||||
String? _kr_pendingInviteCode;
|
||||
|
||||
KRAppRunData._internal();
|
||||
|
||||
factory KRAppRunData() => _instance;
|
||||
@@ -447,6 +454,16 @@ class KRAppRunData {
|
||||
|
||||
kr_isLogin.value = true;
|
||||
print('✅ 已标记为登录状态');
|
||||
|
||||
// 静默邀请绑定
|
||||
if (inviteDebugMode) {
|
||||
// Debug 模式下等待调试弹窗完成,避免页面跳转
|
||||
await _kr_handleSilentInvitation();
|
||||
} else {
|
||||
// 正式环境异步执行,不阻塞主流程
|
||||
_kr_handleSilentInvitation();
|
||||
}
|
||||
|
||||
_logStepTiming('设备登录完成');
|
||||
return true;
|
||||
},
|
||||
@@ -496,6 +513,9 @@ class KRAppRunData {
|
||||
KRLogUtil.kr_i('✅ Token和账号验证通过,设置登录状态为true', tag: 'AppRunData');
|
||||
KRLogUtil.kr_i('📊 恢复账号: ${kr_account.value}', tag: 'AppRunData');
|
||||
kr_isLogin.value = true;
|
||||
|
||||
// 🔧 新增:恢复登录状态后也尝试检测一次静默邀请(重要:针对已安装后启动的情况)
|
||||
_kr_handleSilentInvitation();
|
||||
} else {
|
||||
// 账号信息为空,清理旧数据
|
||||
KRLogUtil.kr_w('⚠️ 账号信息为空,清理该条用户数据', tag: 'AppRunData');
|
||||
@@ -633,4 +653,125 @@ class KRAppRunData {
|
||||
KRLogUtil.kr_e('📚 [AppRunData] 错误堆栈: $stackTrace', tag: 'AppRunData');
|
||||
}
|
||||
}
|
||||
/// 处理静默邀请
|
||||
Future<void> _kr_handleSilentInvitation() async {
|
||||
KRLogUtil.kr_i('🚀 开始处理静默邀请...', tag: 'AppRunData');
|
||||
String? inviteCode;
|
||||
|
||||
// 1. 先检查是否有之前通过唤醒/安装暂存的邀请码
|
||||
if (_kr_pendingInviteCode != null && _kr_pendingInviteCode!.isNotEmpty) {
|
||||
inviteCode = _kr_pendingInviteCode;
|
||||
KRLogUtil.kr_i('📎 使用暂存的待绑定邀请码: $inviteCode', tag: 'AppRunData');
|
||||
}
|
||||
|
||||
// 2. 如果没有暂存码,尝试从平台环境获取
|
||||
if (inviteCode == null || inviteCode!.isEmpty) {
|
||||
try {
|
||||
if (Platform.isMacOS || Platform.isWindows) {
|
||||
inviteCode = await KRDeviceUtil().kr_getDesktopInviteCode();
|
||||
} else if (Platform.isAndroid || Platform.isIOS) {
|
||||
final Completer<String?> completer = Completer<String?>();
|
||||
OpeninstallFlutterPlugin().install((data) async {
|
||||
final code = kr_parseInviteCodeFromData(data);
|
||||
KRLogUtil.kr_i('收到 OpenInstall 安装数据: $data, 解析出邀请码: $code', tag: 'AppRunData');
|
||||
if (!completer.isCompleted) completer.complete(code);
|
||||
});
|
||||
inviteCode = await completer.future
|
||||
.timeout(const Duration(seconds: 8), onTimeout: () => null);
|
||||
}
|
||||
} catch (e) {
|
||||
KRLogUtil.kr_e('获取静默邀请码异常: $e', tag: 'AppRunData');
|
||||
}
|
||||
}
|
||||
|
||||
if (inviteCode != null && inviteCode!.isNotEmpty) {
|
||||
KRLogUtil.kr_i('🔍 最终识别到邀请码: $inviteCode', tag: 'AppRunData');
|
||||
|
||||
if (inviteDebugMode) {
|
||||
// Debug 模式下弹出对话框确认
|
||||
final bool isDesktop = Platform.isMacOS || Platform.isWindows;
|
||||
await HIDialog.show(
|
||||
title: isDesktop ? '调试:唤醒识别到邀请码' : '调试:邀请码绑定确认',
|
||||
message: isDesktop
|
||||
? '桌面端识别到邀请码:$inviteCode\n是否进行绑定?'
|
||||
: '识别到邀请码:$inviteCode\n是否进行绑定?',
|
||||
confirmText: isDesktop ? '绑定' : '确认绑定',
|
||||
cancelText: isDesktop ? '跳过' : '取消',
|
||||
onConfirm: () async {
|
||||
await _kr_performInviteBinding(inviteCode!);
|
||||
_kr_pendingInviteCode = null; // 绑定后清除
|
||||
},
|
||||
onCancel: () {
|
||||
_kr_pendingInviteCode = null; // 取消也清除,避免重复弹窗
|
||||
},
|
||||
);
|
||||
} else {
|
||||
// 正式环境静默绑定
|
||||
await _kr_performInviteBinding(inviteCode!);
|
||||
_kr_pendingInviteCode = null; // 绑定后清除
|
||||
}
|
||||
} else {
|
||||
KRLogUtil.kr_i('⚠️ 未识别到有效的邀请码,跳外静默绑定', tag: 'AppRunData');
|
||||
}
|
||||
}
|
||||
|
||||
/// 执行邀请码绑定请求
|
||||
Future<void> _kr_performInviteBinding(String inviteCode) async {
|
||||
KRLogUtil.kr_i('🚀 准备执行邀请码绑定: $inviteCode', tag: 'AppRunData');
|
||||
final result =
|
||||
await KRUserApi().hi_inviteCode(inviteCode, isSilentInvite: true);
|
||||
result.fold(
|
||||
(error) => KRLogUtil.kr_w('❌ 邀请绑定失败: ${error.msg}', tag: 'AppRunData'),
|
||||
(_) => KRLogUtil.kr_i('✅ 邀请绑定成功', tag: 'AppRunData'),
|
||||
);
|
||||
}
|
||||
|
||||
/// 公开方法:直接处理 OpenInstall 返回的原始数据(用于唤醒等场景)
|
||||
Future<void> kr_handleOpenInstallData(Map<dynamic, dynamic> data) async {
|
||||
final code = kr_parseInviteCodeFromData(data);
|
||||
if (code != null && code.isNotEmpty) {
|
||||
KRLogUtil.kr_i('🔗 收到 OpenInstall 原始参数并触发解析: $code', tag: 'AppRunData');
|
||||
|
||||
// 暂存该邀请码
|
||||
_kr_pendingInviteCode = code;
|
||||
|
||||
// 如果当前已经是登录状态,则由于是唤醒(Hot Start)触发,直接按业务逻辑处理
|
||||
if (kr_isLogin.value) {
|
||||
KRLogUtil.kr_i('✅ 用户已登录,立即处理唤醒绑定', tag: 'AppRunData');
|
||||
if (inviteDebugMode) {
|
||||
await HIDialog.show(
|
||||
title: '调试:唤醒识别到邀请码',
|
||||
message: '唤醒数据解析到邀请码:$code\n是否进行绑定?',
|
||||
confirmText: '绑定',
|
||||
cancelText: '跳过',
|
||||
onConfirm: () async {
|
||||
await _kr_performInviteBinding(code);
|
||||
_kr_pendingInviteCode = null;
|
||||
},
|
||||
onCancel: () => _kr_pendingInviteCode = null,
|
||||
);
|
||||
} else {
|
||||
_kr_performInviteBinding(code).then((_) => _kr_pendingInviteCode = null);
|
||||
}
|
||||
} else {
|
||||
KRLogUtil.kr_i('⏳ 用户未登录,已暂存邀请码,等待登录完成后自动绑定', tag: 'AppRunData');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 从 OpenInstall 数据中解析邀请码
|
||||
String? kr_parseInviteCodeFromData(Map<dynamic, dynamic> data) {
|
||||
try {
|
||||
if (data.containsKey('bindData')) {
|
||||
final bindDataStr = data['bindData'] as String?;
|
||||
if (bindDataStr != null && bindDataStr.isNotEmpty) {
|
||||
final Map<String, dynamic> bindData = jsonDecode(bindDataStr);
|
||||
return bindData['inviteCode']?.toString();
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
KRLogUtil.kr_e('解析 OpenInstall 数据中邀请码失败: $e', tag: 'AppRunData');
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user