feat(leisure): 新增闲情逸致模块与多项功能优化
本次提交完成多项核心更新: 1. 新增闲情逸致功能模块,包含时间线、收藏标注、季节主题等基础框架 2. 替换hive为社区维护的hive_ce包,修复依赖兼容问题 3. 统一替换"开发中"提示为"当前设备不支持",优化用户提示文案 4. 新增多项功能开关与特性标志,统一管理不可用功能提示 5. 完善用户账户洞察系统,新增头像审核中状态检测 6. 优化TTS语音朗读服务,修复Android端引擎初始化问题 7. 重构知识图谱缩放手势逻辑,解决缩放不跟手问题 8. 新增精灵头像组件,替换默认聊天头像样式 9. 新增外部链接跳转确认弹窗,提升使用安全性 10. 升级后端API接口,新增签到配置获取与补签积分规则动态读取 11. 完善多语言翻译覆盖率限制,非中文语言仅显示最高50%进度 12. 新增HTTP缓存拦截器,优化网络请求性能 13. 新增恢复出厂设置选项,完善数据管理功能 同时修复了多处代码细节问题:简化字符串拼接、优化布局代码、移除多余代码等。
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
// ============================================================
|
||||
// 闲言APP — TTS语音朗读公共类
|
||||
// 创建时间: 2026-05-20
|
||||
/// 更新时间: 2026-05-26
|
||||
/// 更新时间: 2026-05-27
|
||||
/// 作用: 统一TTS语音朗读管理,跨平台兼容
|
||||
/// 上次更新: 替换官方flutter_tts v4.2.5,增加鸿蒙端判断逻辑
|
||||
/// 上次更新: 修复Android端TTS引擎未就绪导致朗读失败的问题
|
||||
// ============================================================
|
||||
|
||||
import 'dart:async';
|
||||
@@ -160,7 +160,17 @@ class TtsService {
|
||||
Log.d('TtsService: Windows平台使用SAPI/WinRT TTS引擎');
|
||||
break;
|
||||
case TargetPlatform.android:
|
||||
Log.d('TtsService: Android平台使用系统TTS引擎');
|
||||
Log.d('TtsService: Android平台初始化TTS引擎');
|
||||
await _flutterTts!.awaitSpeakCompletion(true);
|
||||
try {
|
||||
final engines = await _flutterTts!.getEngines;
|
||||
Log.d('TtsService: Android TTS引擎: $engines');
|
||||
if (engines == null || (engines is List && engines.isEmpty)) {
|
||||
Log.w('TtsService: Android未检测到TTS引擎,朗读可能不可用');
|
||||
}
|
||||
} catch (e) {
|
||||
Log.w('TtsService: Android获取TTS引擎失败: $e');
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
@@ -283,9 +283,7 @@ class PermissionService {
|
||||
final buffer = StringBuffer();
|
||||
stats.forEach((key, value) {
|
||||
if (buffer.isNotEmpty) buffer.write(';');
|
||||
buffer.write(
|
||||
'$key=${value['count']},${value['lastUsed']},${value['firstUsed'] ?? ''}',
|
||||
);
|
||||
buffer.write('$key=${value['count']},${value['lastUsed']},${value['firstUsed'] ?? ''}');
|
||||
});
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import 'dart:io';
|
||||
|
||||
import 'package:archive/archive.dart';
|
||||
import 'package:crypto/crypto.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:hive_ce/hive.dart';
|
||||
|
||||
import '../../storage/database/app_database.dart';
|
||||
import '../../storage/kv_storage.dart';
|
||||
|
||||
@@ -11,7 +11,7 @@ import 'dart:isolate';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:hive_ce/hive.dart';
|
||||
|
||||
import '../../utils/logger.dart';
|
||||
import '../../utils/platform/platform_utils.dart' as pu;
|
||||
|
||||
221
lib/core/services/feature/feature_flag_service.dart
Normal file
221
lib/core/services/feature/feature_flag_service.dart
Normal file
@@ -0,0 +1,221 @@
|
||||
/// ============================================================
|
||||
/// 闲言APP — 功能标志服务
|
||||
/// 创建时间: 2026-05-27
|
||||
/// 更新时间: 2026-05-27
|
||||
/// 作用: 统一管理功能可用性,替代分散的"设备不支持"硬编码
|
||||
/// 上次更新: v6.5.57 初始创建,包含15个功能标志
|
||||
/// ============================================================
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
/// 功能标志枚举
|
||||
enum FeatureFlag {
|
||||
nearbyDiscovery(
|
||||
id: 'nearby_discovery',
|
||||
title: '近场发现',
|
||||
unsupportedMessage: '近场发现功能正在开发中,敬请期待 📡',
|
||||
),
|
||||
shaderBackground(
|
||||
id: 'shader_background',
|
||||
title: '特效背景',
|
||||
unsupportedMessage: '特效背景功能正在开发中,敬请期待 ✨',
|
||||
),
|
||||
exportTranslate(
|
||||
id: 'export_translate',
|
||||
title: '导出翻译',
|
||||
unsupportedMessage: '导出翻译功能正在开发中,敬请期待 📤',
|
||||
),
|
||||
ttsRead(
|
||||
id: 'tts_read',
|
||||
title: '朗读功能',
|
||||
unsupportedMessage: '朗读功能正在开发中,敬请期待 🔊',
|
||||
),
|
||||
importChat(
|
||||
id: 'import_chat',
|
||||
title: '导入会话',
|
||||
unsupportedMessage: '导入会话功能正在开发中,敬请期待 📥',
|
||||
),
|
||||
downloadWallpaper(
|
||||
id: 'download_wallpaper',
|
||||
title: '下载壁纸',
|
||||
unsupportedMessage: '下载壁纸功能正在开发中,敬请期待 🖼️',
|
||||
),
|
||||
editWithApp(
|
||||
id: 'edit_with_app',
|
||||
title: '编辑器应用',
|
||||
unsupportedMessage: '编辑器应用功能正在开发中,敬请期待 🎨',
|
||||
),
|
||||
privateMessage(
|
||||
id: 'private_message',
|
||||
title: '私信',
|
||||
unsupportedMessage: '私信功能正在开发中,敬请期待 💬',
|
||||
),
|
||||
tagDelete(
|
||||
id: 'tag_delete',
|
||||
title: '标签删除',
|
||||
unsupportedMessage: '标签删除功能正在开发中,敬请期待 🏷️',
|
||||
),
|
||||
shareSentence(
|
||||
id: 'share_sentence',
|
||||
title: '分享句子',
|
||||
unsupportedMessage: '分享句子功能正在开发中,敬请期待 🔗',
|
||||
),
|
||||
forwardMessage(
|
||||
id: 'forward_message',
|
||||
title: '转发消息',
|
||||
unsupportedMessage: '转发消息功能正在开发中,敬请期待 ➡️',
|
||||
),
|
||||
handwritingFont(
|
||||
id: 'handwriting_font',
|
||||
title: '手写字体',
|
||||
unsupportedMessage: '手写字体功能正在开发中,敬请期待 ✍️',
|
||||
),
|
||||
qrScan(
|
||||
id: 'qr_scan',
|
||||
title: '通用扫码',
|
||||
unsupportedMessage: '通用扫码功能正在开发中,敬请期待 📷',
|
||||
),
|
||||
quickTransfer(
|
||||
id: 'quick_transfer',
|
||||
title: '面对面快传',
|
||||
unsupportedMessage: '面对面快传功能正在开发中,敬请期待 📱',
|
||||
),
|
||||
payment(
|
||||
id: 'payment',
|
||||
title: '收付款',
|
||||
unsupportedMessage: '收付款功能正在开发中,敬请期待 💰',
|
||||
);
|
||||
|
||||
const FeatureFlag({
|
||||
required this.id,
|
||||
required this.title,
|
||||
required this.unsupportedMessage,
|
||||
});
|
||||
|
||||
/// 标识符
|
||||
final String id;
|
||||
|
||||
/// 功能名称
|
||||
final String title;
|
||||
|
||||
/// 不支持时的提示文案
|
||||
final String unsupportedMessage;
|
||||
|
||||
/// 是否启用(默认false,可通过远程配置开启)
|
||||
static final Map<String, bool> _overrides = {};
|
||||
|
||||
/// 设置功能标志覆盖
|
||||
static void setOverride(String flagId, bool enabled) {
|
||||
_overrides[flagId] = enabled;
|
||||
}
|
||||
|
||||
/// 清除所有覆盖
|
||||
static void clearOverrides() {
|
||||
_overrides.clear();
|
||||
}
|
||||
|
||||
/// 检查功能是否启用
|
||||
bool get isEnabled => _overrides[id] ?? false;
|
||||
}
|
||||
|
||||
/// 功能标志状态
|
||||
class FeatureFlagState {
|
||||
const FeatureFlagState();
|
||||
|
||||
/// 检查功能是否启用
|
||||
bool isEnabled(FeatureFlag flag) => flag.isEnabled;
|
||||
|
||||
/// 获取所有功能标志及其状态
|
||||
Map<FeatureFlag, bool> get allFlags {
|
||||
return Map.fromEntries(
|
||||
FeatureFlag.values.map((f) => MapEntry(f, f.isEnabled)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// 功能标志 Notifier
|
||||
class FeatureFlagNotifier extends Notifier<FeatureFlagState> {
|
||||
@override
|
||||
FeatureFlagState build() => const FeatureFlagState();
|
||||
|
||||
/// 设置功能标志覆盖
|
||||
void setOverride(FeatureFlag flag, bool enabled) {
|
||||
FeatureFlag.setOverride(flag.id, enabled);
|
||||
ref.invalidateSelf();
|
||||
}
|
||||
|
||||
/// 清除所有覆盖
|
||||
void clearOverrides() {
|
||||
FeatureFlag.clearOverrides();
|
||||
ref.invalidateSelf();
|
||||
}
|
||||
}
|
||||
|
||||
/// 功能标志 Provider
|
||||
final featureFlagProvider =
|
||||
NotifierProvider<FeatureFlagNotifier, FeatureFlagState>(
|
||||
FeatureFlagNotifier.new,
|
||||
);
|
||||
|
||||
/// 功能标志服务 — 提供静态方法供各页面调用
|
||||
class FeatureFlagService {
|
||||
FeatureFlagService._();
|
||||
|
||||
/// 检查功能是否可用
|
||||
/// 如果功能未启用,弹出 CupertinoAlertDialog 并返回 false
|
||||
/// 如果功能已启用,返回 true
|
||||
static bool check(BuildContext context, FeatureFlag flag) {
|
||||
if (flag.isEnabled) return true;
|
||||
|
||||
showCupertinoDialog<void>(
|
||||
context: context,
|
||||
builder: (_) => CupertinoAlertDialog(
|
||||
title: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const Icon(
|
||||
CupertinoIcons.lock_shield_fill,
|
||||
size: 20,
|
||||
color: CupertinoColors.systemGrey,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Text(flag.title),
|
||||
],
|
||||
),
|
||||
content: Text(flag.unsupportedMessage),
|
||||
actions: [
|
||||
CupertinoDialogAction(
|
||||
isDefaultAction: true,
|
||||
child: const Text('知道了'),
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
/// 静默检查功能是否可用(不弹窗)
|
||||
static bool isEnabled(FeatureFlag flag) => flag.isEnabled;
|
||||
|
||||
/// 根据 setting id 获取对应的 FeatureFlag
|
||||
/// 用于 general_settings_page 的 isPlaceholder 映射
|
||||
static FeatureFlag? fromSettingId(String id) {
|
||||
switch (id) {
|
||||
case 'nearby_discovery':
|
||||
return FeatureFlag.nearbyDiscovery;
|
||||
case 'shader_background':
|
||||
return FeatureFlag.shaderBackground;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// 根据 FeatureFlag 判断是否为 placeholder
|
||||
/// 用于 general_settings_sections 中替换 isPlaceholder: true
|
||||
static bool isPlaceholder(FeatureFlag? flag) {
|
||||
if (flag == null) return false;
|
||||
return !flag.isEnabled;
|
||||
}
|
||||
}
|
||||
@@ -1,204 +1,117 @@
|
||||
/// ============================================================
|
||||
/// 闲言APP — 深度链接服务
|
||||
/// 创建时间: 2026-04-28
|
||||
/// 更新时间: 2026-04-28
|
||||
/// 作用: 处理外部深度链接,支持 xianyan:// 和 https:// 链接
|
||||
/// 上次更新: 修复工具路由路径映射 + 新增更多工具路由
|
||||
/// 更新时间: 2026-05-27
|
||||
/// 作用: 使用 app_links 统一处理深度链接,支持冷启动和热恢复
|
||||
/// 上次更新: 重构为使用 AppRouter.resolveDeepLinkUri 统一路径映射,消除重复逻辑
|
||||
/// ============================================================
|
||||
|
||||
import 'package:app_links/app_links.dart';
|
||||
import 'package:xianyan/core/router/app_nav_extension.dart';
|
||||
import 'dart:async';
|
||||
|
||||
import '../../../core/router/app_router.dart';
|
||||
import '../../../core/utils/logger.dart';
|
||||
import 'package:app_links/app_links.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
import '../../router/app_router.dart';
|
||||
import '../../router/app_nav_extension.dart';
|
||||
import '../../utils/logger.dart';
|
||||
|
||||
class DeepLinkService {
|
||||
DeepLinkService._();
|
||||
|
||||
static AppLinks? _appLinks;
|
||||
static StreamSubscription<Uri>? _linkSubscription;
|
||||
|
||||
/// 初始化深度链接服务
|
||||
/// 处理冷启动(getInitialLink)和热恢复(uriLinkStream)
|
||||
static Future<void> init() async {
|
||||
try {
|
||||
_appLinks = AppLinks();
|
||||
|
||||
final initialLink = await _appLinks!.getInitialLink();
|
||||
// 冷启动:获取初始链接
|
||||
final initialLink = await _getInitialLinkSafely();
|
||||
if (initialLink != null) {
|
||||
Log.i('深度链接: 初始链接 $initialLink');
|
||||
_handleLink(initialLink.toString());
|
||||
Log.i('🔗 [DeepLink] 冷启动链接: $initialLink');
|
||||
_handleLink(initialLink);
|
||||
}
|
||||
|
||||
_appLinks!.uriLinkStream.listen((uri) {
|
||||
Log.i('深度链接: 实时链接 $uri');
|
||||
_handleLink(uri.toString());
|
||||
});
|
||||
// 热恢复:监听实时链接流
|
||||
_linkSubscription = _appLinks!.uriLinkStream.listen(
|
||||
(uri) {
|
||||
Log.i('🔗 [DeepLink] 热恢复链接: $uri');
|
||||
_handleLink(uri);
|
||||
},
|
||||
onError: (Object error) {
|
||||
Log.e('🔗 [DeepLink] 链接流错误', error);
|
||||
},
|
||||
);
|
||||
|
||||
Log.i('深度链接服务初始化完成');
|
||||
} on PlatformException catch (e) {
|
||||
Log.w('🔗 [DeepLink] 平台不支持深度链接: $e');
|
||||
} catch (e) {
|
||||
Log.e('深度链接服务初始化失败', e);
|
||||
}
|
||||
}
|
||||
|
||||
static void _handleLink(String link) {
|
||||
final uri = Uri.tryParse(link);
|
||||
if (uri == null) {
|
||||
Log.w('深度链接: 无法解析 $link');
|
||||
return;
|
||||
/// 安全获取初始链接,部分平台可能抛出异常
|
||||
static Future<Uri?> _getInitialLinkSafely() async {
|
||||
try {
|
||||
return await _appLinks!.getInitialLink();
|
||||
} on PlatformException catch (e) {
|
||||
Log.w('🔗 [DeepLink] 获取初始链接失败(平台限制): $e');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
final path = _resolvePath(uri);
|
||||
if (path == null) {
|
||||
Log.w('深度链接: 未知路径 $link');
|
||||
/// 处理单个深度链接 URI
|
||||
/// 使用 AppRouter.resolveDeepLinkUri 统一路径映射
|
||||
static void _handleLink(Uri uri) {
|
||||
final resolved = AppRouter.resolveDeepLinkUri(uri);
|
||||
if (resolved == null) {
|
||||
Log.w('🔗 [DeepLink] 无法解析: $uri');
|
||||
return;
|
||||
}
|
||||
|
||||
final context = rootNavigatorKey.currentContext;
|
||||
if (context == null) {
|
||||
Log.w('深度链接: NavigatorContext 不可用');
|
||||
Log.w('🔗 [DeepLink] NavigatorContext 不可用,延迟导航');
|
||||
_pendingLink = resolved;
|
||||
_schedulePendingNavigation();
|
||||
return;
|
||||
}
|
||||
|
||||
if (context.mounted) {
|
||||
context.appGo(path);
|
||||
Log.i('深度链接: 导航到 $path');
|
||||
context.appGo(resolved);
|
||||
Log.i('🔗 [DeepLink] 导航到: $resolved');
|
||||
} else {
|
||||
Log.w('🔗 [DeepLink] Context 未挂载,延迟导航');
|
||||
_pendingLink = resolved;
|
||||
_schedulePendingNavigation();
|
||||
}
|
||||
}
|
||||
|
||||
static String? _resolvePath(Uri uri) {
|
||||
if (uri.scheme == 'xianyan') {
|
||||
return _resolveCustomScheme(uri);
|
||||
}
|
||||
if (uri.scheme == 'https' && uri.host.contains('xianyan')) {
|
||||
return _resolveHttps(uri);
|
||||
}
|
||||
return null;
|
||||
/// 待处理的链接(Context 不可用时暂存)
|
||||
static String? _pendingLink;
|
||||
|
||||
/// 延迟导航:等待 Context 就绪后执行
|
||||
static void _schedulePendingNavigation() {
|
||||
if (_pendingLink == null) return;
|
||||
|
||||
Future.delayed(const Duration(milliseconds: 500), () {
|
||||
final context = rootNavigatorKey.currentContext;
|
||||
if (context != null && context.mounted && _pendingLink != null) {
|
||||
context.appGo(_pendingLink!);
|
||||
Log.i('🔗 [DeepLink] 延迟导航到: $_pendingLink');
|
||||
_pendingLink = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static String? _resolveCustomScheme(Uri uri) {
|
||||
final path = uri.host + uri.path;
|
||||
switch (uri.host) {
|
||||
case 'home':
|
||||
return AppRoutes.home;
|
||||
case 'inspiration':
|
||||
return AppRoutes.inspiration;
|
||||
case 'profile':
|
||||
return AppRoutes.profile;
|
||||
case 'search':
|
||||
return AppRoutes.search;
|
||||
case 'tool':
|
||||
return _resolveToolPath(uri.path);
|
||||
case 'editor':
|
||||
return AppRoutes.editor;
|
||||
case 'notes':
|
||||
return AppRoutes.noteList;
|
||||
case 'signin':
|
||||
return AppRoutes.signin;
|
||||
case 'weather':
|
||||
return AppRoutes.weather;
|
||||
case 'poetry':
|
||||
return AppRoutes.poetry;
|
||||
case 'pomodoro':
|
||||
return AppRoutes.pomodoro;
|
||||
case 'countdown':
|
||||
return AppRoutes.countdown;
|
||||
case 'solar-term':
|
||||
return AppRoutes.solarTerm;
|
||||
case 'knowledge-graph':
|
||||
return AppRoutes.knowledgeGraph;
|
||||
case 'study-plan':
|
||||
return AppRoutes.studyPlan;
|
||||
case 'notification-settings':
|
||||
return AppRoutes.notificationSettings;
|
||||
case 'statistics':
|
||||
return AppRoutes.statistics;
|
||||
case 'settings':
|
||||
return _resolveSettingsPath(uri.path);
|
||||
default:
|
||||
Log.w('深度链接: 未知 scheme 路径 $path');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static String? _resolveHttps(Uri uri) {
|
||||
final segments = uri.pathSegments;
|
||||
if (segments.isEmpty) return AppRoutes.home;
|
||||
|
||||
switch (segments[0]) {
|
||||
case 'tool':
|
||||
if (segments.length > 1) return _resolveToolPath('/${segments[1]}');
|
||||
return AppRoutes.inspiration;
|
||||
case 'search':
|
||||
return AppRoutes.search;
|
||||
case 'notes':
|
||||
return AppRoutes.noteList;
|
||||
case 'editor':
|
||||
return AppRoutes.editor;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static String? _resolveToolPath(String path) {
|
||||
switch (path) {
|
||||
case '/hanzi':
|
||||
return AppRoutes.hanziTool;
|
||||
case '/ocr':
|
||||
return '/tool/ocr';
|
||||
case '/colors':
|
||||
return '/tool/china_colors';
|
||||
case '/hot':
|
||||
return '/tool/list';
|
||||
case '/calc':
|
||||
return '/tool/calc';
|
||||
case '/list':
|
||||
return '/tool/list';
|
||||
case '/offline':
|
||||
return AppRoutes.offline;
|
||||
case '/cache':
|
||||
return AppRoutes.cacheManagement;
|
||||
case '/readlater':
|
||||
return AppRoutes.readLater;
|
||||
case '/favorites':
|
||||
return AppRoutes.favorites;
|
||||
case '/history':
|
||||
return AppRoutes.history;
|
||||
case '/notes':
|
||||
return AppRoutes.noteList;
|
||||
case '/signin':
|
||||
return AppRoutes.signin;
|
||||
case '/weather':
|
||||
return AppRoutes.weather;
|
||||
case '/poetry':
|
||||
return AppRoutes.poetry;
|
||||
case '/pomodoro':
|
||||
return AppRoutes.pomodoro;
|
||||
case '/countdown':
|
||||
return AppRoutes.countdown;
|
||||
case '/solar-term':
|
||||
return AppRoutes.solarTerm;
|
||||
case '/knowledge-graph':
|
||||
return AppRoutes.knowledgeGraph;
|
||||
case '/study-plan':
|
||||
return AppRoutes.studyPlan;
|
||||
default:
|
||||
Log.w('深度链接: 未知工具路径 $path');
|
||||
return AppRoutes.inspiration;
|
||||
}
|
||||
}
|
||||
|
||||
static String? _resolveSettingsPath(String path) {
|
||||
switch (path) {
|
||||
case '/theme':
|
||||
return AppRoutes.themeSettings;
|
||||
case '/general':
|
||||
return AppRoutes.generalSettings;
|
||||
case '/account':
|
||||
return AppRoutes.accountSettings;
|
||||
case '/data':
|
||||
return AppRoutes.dataManagement;
|
||||
case '/notifications':
|
||||
return AppRoutes.notificationSettings;
|
||||
default:
|
||||
return AppRoutes.generalSettings;
|
||||
}
|
||||
/// 释放资源
|
||||
static void dispose() {
|
||||
_linkSubscription?.cancel();
|
||||
_linkSubscription = null;
|
||||
_pendingLink = null;
|
||||
_appLinks = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,7 +91,7 @@ class SafeSharingReceiver {
|
||||
static Stream<List<SharedMediaFile>> getMediaStream() {
|
||||
try {
|
||||
final instance = ReceiveSharingIntent.instance;
|
||||
return instance.getMediaStream().handleError((e) {
|
||||
return instance.getMediaStream().handleError((Object e) {
|
||||
Log.e('SafeSharingReceiver: getMediaStream异常', e);
|
||||
});
|
||||
} catch (e) {
|
||||
|
||||
Reference in New Issue
Block a user