Commit 6c23b545fdb0dbc00b8b36f597e8bcb5ae41ffb3
1 parent
e26da9e0
fix: 修复友盟隐私合规初始化时机
Showing
6 changed files
with
203 additions
and
115 deletions
android/app/src/main/kotlin/com/kouyuxingqiu/wow_english/MainActivity.kt
| ... | ... | @@ -11,8 +11,11 @@ import com.gyf.immersionbar.ImmersionBar |
| 11 | 11 | import com.kouyuxingqiu.wow_english.methodChannels.GameMethodChannel |
| 12 | 12 | import com.kouyuxingqiu.wow_english.methodChannels.SingSoungMethodChannel |
| 13 | 13 | import com.umeng.commonsdk.UMConfigure |
| 14 | -import io.flutter.embedding.android.FlutterActivity | |
| 15 | 14 | import com.umeng.umcrash.UMCrash |
| 15 | +import io.flutter.embedding.android.FlutterActivity | |
| 16 | +import io.flutter.embedding.engine.FlutterEngine | |
| 17 | +import io.flutter.plugin.common.BinaryMessenger | |
| 18 | +import io.flutter.plugin.common.MethodChannel | |
| 16 | 19 | |
| 17 | 20 | |
| 18 | 21 | class MainActivity : FlutterActivity() { |
| ... | ... | @@ -25,7 +28,11 @@ class MainActivity : FlutterActivity() { |
| 25 | 28 | SingSoungMethodChannel(this, it) |
| 26 | 29 | GameMethodChannel(this, it) |
| 27 | 30 | } |
| 28 | - initUmeng() | |
| 31 | + } | |
| 32 | + | |
| 33 | + override fun configureFlutterEngine(flutterEngine: FlutterEngine) { | |
| 34 | + super.configureFlutterEngine(flutterEngine) | |
| 35 | + initUmengMethodChannel(flutterEngine.dartExecutor.binaryMessenger) | |
| 29 | 36 | } |
| 30 | 37 | |
| 31 | 38 | override fun onResume() { |
| ... | ... | @@ -60,11 +67,26 @@ class MainActivity : FlutterActivity() { |
| 60 | 67 | /** |
| 61 | 68 | * 友盟初始化 |
| 62 | 69 | */ |
| 63 | - private fun initUmeng() { | |
| 64 | - // 友盟集成测试阶段获取UMID | |
| 65 | -// android.util.Log.d("WQF UMConfigure", UMConfigure.getUMIDString(this)) | |
| 66 | - // 在application.onCreate内配置各模块开关并预初始化SDK | |
| 67 | - // 重点关注:如果您还想采集Native 崩溃、ANR等日志可以参考下面设置 | |
| 70 | + private var isUmengPrepared = false | |
| 71 | + | |
| 72 | + private fun initUmengMethodChannel(binaryMessenger: BinaryMessenger) { | |
| 73 | + MethodChannel(binaryMessenger, "wow_english/umeng_method_channel") | |
| 74 | + .setMethodCallHandler { call, result -> | |
| 75 | + if (call.method == "prepareAfterPrivacyConsent") { | |
| 76 | + prepareUmengAfterPrivacyConsent() | |
| 77 | + result.success(true) | |
| 78 | + } else { | |
| 79 | + result.notImplemented() | |
| 80 | + } | |
| 81 | + } | |
| 82 | + } | |
| 83 | + | |
| 84 | + private fun prepareUmengAfterPrivacyConsent() { | |
| 85 | + if (isUmengPrepared) return | |
| 86 | + | |
| 87 | + // APM 合规要求:preInit、Crash 配置和正式 init 均只能在用户同意后执行。 | |
| 88 | + UMConfigure.setLogEnabled(false) | |
| 89 | + UMConfigure.preInit(this, "663b66b0b3362515012f4ea5", "official") | |
| 68 | 90 | UMCrash.initConfig(Bundle().apply { |
| 69 | 91 | putBoolean(UMCrash.KEY_ENABLE_CRASH_JAVA, true) |
| 70 | 92 | putBoolean(UMCrash.KEY_ENABLE_CRASH_NATIVE, true) |
| ... | ... | @@ -75,8 +97,6 @@ class MainActivity : FlutterActivity() { |
| 75 | 97 | putBoolean(UMCrash.KEY_ENABLE_H5PAGE, false) |
| 76 | 98 | putBoolean(UMCrash.KEY_ENABLE_POWER, false) |
| 77 | 99 | }) |
| 78 | - //UM日志打印 | |
| 79 | - UMConfigure.setLogEnabled(false) | |
| 80 | - UMConfigure.preInit(this, "663b66b0b3362515012f4ea5", "official") | |
| 100 | + isUmengPrepared = true | |
| 81 | 101 | } |
| 82 | 102 | } | ... | ... |
lib/app/splash_page.dart
| ... | ... | @@ -23,7 +23,6 @@ import '../common/core/module_cache.dart'; |
| 23 | 23 | import '../common/widgets/webview_dialog.dart'; |
| 24 | 24 | import '../common/utils/staticstring/userregister.dart'; |
| 25 | 25 | |
| 26 | - | |
| 27 | 26 | class SplashPage extends StatelessWidget { |
| 28 | 27 | const SplashPage({super.key}); |
| 29 | 28 | |
| ... | ... | @@ -43,10 +42,14 @@ class TransitionView extends StatefulWidget { |
| 43 | 42 | } |
| 44 | 43 | |
| 45 | 44 | class _TransitionViewState extends State<TransitionView> { |
| 45 | + bool _isPrivacyDecisionInProgress = false; | |
| 46 | + bool _isInitializing = false; | |
| 47 | + | |
| 46 | 48 | Future startTime() async { |
| 47 | 49 | // 判断是否登录 |
| 48 | 50 | UserEntity? userEntity = UserUtil.getUser(); |
| 49 | - Log.d('当前模式:kDebugMode=$kDebugMode, kProfileMode=$kProfileMode, kReleaseMode=$kReleaseMode'); | |
| 51 | + Log.d( | |
| 52 | + '当前模式:kDebugMode=$kDebugMode, kProfileMode=$kProfileMode, kReleaseMode=$kReleaseMode'); | |
| 50 | 53 | Log.d('当前API地址:${RequestConfig.baseUrl}'); |
| 51 | 54 | //BuildContext context = Navigator.of(context).context; |
| 52 | 55 | //var currentPageName = ModalRoute.of(Navigator.of(AppRouter.context))?.settings.name; |
| ... | ... | @@ -63,89 +66,151 @@ class _TransitionViewState extends State<TransitionView> { |
| 63 | 66 | apartInMilliseconds = DateTime.now().difference(startTime).inMilliseconds; |
| 64 | 67 | } |
| 65 | 68 | int duration = max(1500 - apartInMilliseconds, 0); |
| 66 | - Log.d('Splash getUserInfo 耗时:${apartInMilliseconds}ms, 最终duration=$duration'); | |
| 69 | + Log.d( | |
| 70 | + 'Splash getUserInfo 耗时:${apartInMilliseconds}ms, 最终duration=$duration'); | |
| 67 | 71 | Timer(Duration(milliseconds: duration), () { |
| 68 | - /*if (userEntity != null) { | |
| 69 | - pushNamedAndRemoveUntil(AppRouteName.home, (route) => false); | |
| 70 | - } else { | |
| 71 | - pushNamedAndRemoveUntil(AppRouteName.login, (route) => false); | |
| 72 | - }*/ | |
| 73 | - bool isAggreementAccepted = AppConfigHelper.getAgreementAccepted(); | |
| 74 | - if (isAggreementAccepted) { | |
| 75 | - _initData(); | |
| 76 | - } else { | |
| 77 | - showDialog( | |
| 78 | - context: context, | |
| 79 | - barrierDismissible: false, | |
| 80 | - builder: (BuildContext context) { | |
| 81 | - return PopScope( | |
| 82 | - canPop: false, | |
| 83 | - onPopInvoked: (didPop) { | |
| 84 | - Log.d('WQF isAggreementAccepted onPopInvoked didPop=$didPop'); | |
| 85 | - }, | |
| 86 | - child: child(), | |
| 87 | - ); | |
| 72 | + pushNamedAndRemoveUntil(AppRouteName.home, (route) => false); | |
| 73 | + }); | |
| 74 | + } | |
| 75 | + | |
| 76 | + void _showPrivacyDialog() { | |
| 77 | + showDialog( | |
| 78 | + context: context, | |
| 79 | + barrierDismissible: false, | |
| 80 | + builder: (BuildContext context) { | |
| 81 | + return PopScope( | |
| 82 | + canPop: false, | |
| 83 | + onPopInvoked: (didPop) { | |
| 84 | + Log.d('WQF privacy dialog onPopInvoked didPop=$didPop'); | |
| 88 | 85 | }, |
| 86 | + child: child(), | |
| 89 | 87 | ); |
| 90 | - } | |
| 91 | - }); | |
| 88 | + }, | |
| 89 | + ); | |
| 92 | 90 | } |
| 93 | 91 | |
| 94 | 92 | Widget child() { |
| 95 | 93 | if (Platform.isIOS) { |
| 96 | 94 | return AlertDialog( |
| 97 | - title: const Center( | |
| 98 | - child: Text("服务条款及隐私政策"), | |
| 99 | - ), | |
| 100 | - content: SizedBox( | |
| 95 | + title: const Center( | |
| 96 | + child: Text("服务条款及隐私政策"), | |
| 97 | + ), | |
| 98 | + content: SizedBox( | |
| 101 | 99 | width: MediaQuery.of(context).size.height, |
| 102 | 100 | height: MediaQuery.of(context).size.height, |
| 103 | - child: SingleChildScrollView( | |
| 101 | + child: const SingleChildScrollView( | |
| 104 | 102 | child: Text(UserRegisterString.userPrivacyPolicyStr), |
| 105 | - ),), | |
| 106 | - actions: <Widget>[ | |
| 107 | - Row( | |
| 108 | - mainAxisAlignment: MainAxisAlignment.spaceBetween, | |
| 109 | - children: [ | |
| 110 | - TextButton( | |
| 111 | - child: const Text("同意并继续", | |
| 112 | - style: TextStyle(color: Color(0xFFFBB621))), | |
| 113 | - onPressed: () { | |
| 114 | - AppConfigHelper.saveAgreementAccepted(true); | |
| 115 | - _initData(); | |
| 116 | - }, | |
| 117 | - ), | |
| 118 | - TextButton( | |
| 119 | - child: const Text("不同意,退出应用"), | |
| 120 | - onPressed: () { | |
| 121 | - // 退出应用 | |
| 122 | - AppConfigHelper.exitApp(); | |
| 123 | - }, | |
| 124 | - ), | |
| 125 | - ], | |
| 126 | - ) | |
| 127 | - ],); | |
| 103 | + ), | |
| 104 | + ), | |
| 105 | + actions: <Widget>[ | |
| 106 | + Row( | |
| 107 | + mainAxisAlignment: MainAxisAlignment.spaceBetween, | |
| 108 | + children: [ | |
| 109 | + TextButton( | |
| 110 | + onPressed: _acceptPrivacyAgreement, | |
| 111 | + child: const Text("同意并继续", | |
| 112 | + style: TextStyle(color: Color(0xFFFBB621))), | |
| 113 | + ), | |
| 114 | + TextButton( | |
| 115 | + onPressed: _rejectPrivacyAgreement, | |
| 116 | + child: const Text("不同意,退出应用"), | |
| 117 | + ), | |
| 118 | + ], | |
| 119 | + ) | |
| 120 | + ], | |
| 121 | + ); | |
| 128 | 122 | } |
| 129 | 123 | return WebviewDialog( |
| 130 | - title: "服务条款及隐私政策", | |
| 131 | - webUrl: AppConsts.userPrivacyPolicyUrl, | |
| 132 | - leftButtonText: '同意并继续', | |
| 133 | - rightButtonText: '不同意,退出应用', | |
| 134 | - leftTap: () { | |
| 135 | - AppConfigHelper.saveAgreementAccepted(true); | |
| 136 | - _initData(); | |
| 137 | - }, | |
| 138 | - rightTap: () { | |
| 139 | - // 退出应用 | |
| 140 | - AppConfigHelper.exitApp(); | |
| 141 | - }, | |
| 142 | - ); | |
| 124 | + title: "服务条款及隐私政策", | |
| 125 | + webUrl: AppConsts.userPrivacyPolicyUrl, | |
| 126 | + leftButtonText: '同意并继续', | |
| 127 | + rightButtonText: '不同意,退出应用', | |
| 128 | + leftTap: _acceptPrivacyAgreement, | |
| 129 | + rightTap: _rejectPrivacyAgreement, | |
| 130 | + ); | |
| 131 | + } | |
| 132 | + | |
| 133 | + Future<void> _acceptPrivacyAgreement() async { | |
| 134 | + if (_isPrivacyDecisionInProgress) return; | |
| 135 | + _isPrivacyDecisionInProgress = true; | |
| 136 | + | |
| 137 | + await AppConfigHelper.saveAgreementAccepted(true); | |
| 138 | + if (!mounted) return; | |
| 139 | + | |
| 140 | + // 先关闭隐私政策弹窗,再进行可能耗时的 SDK 和业务初始化。 | |
| 141 | + Navigator.of(context, rootNavigator: true).pop(); | |
| 142 | + await _startInitialization(); | |
| 143 | + _isPrivacyDecisionInProgress = false; | |
| 144 | + } | |
| 145 | + | |
| 146 | + Future<void> _rejectPrivacyAgreement() async { | |
| 147 | + if (_isPrivacyDecisionInProgress) return; | |
| 148 | + _isPrivacyDecisionInProgress = true; | |
| 149 | + | |
| 150 | + // 显式撤销本地授权并等待写入完成,避免退出后残留 true。 | |
| 151 | + await AppConfigHelper.saveAgreementAccepted(false); | |
| 152 | + AppConfigHelper.exitApp(); | |
| 153 | + } | |
| 154 | + | |
| 155 | + Future<void> _startInitialization() async { | |
| 156 | + if (_isInitializing) return; | |
| 157 | + _isInitializing = true; | |
| 158 | + try { | |
| 159 | + await _initData(); | |
| 160 | + } catch (error, stackTrace) { | |
| 161 | + Log.d('Splash初始化失败: $error\n$stackTrace'); | |
| 162 | + _isInitializing = false; | |
| 163 | + if (mounted) { | |
| 164 | + _showInitializationErrorDialog(); | |
| 165 | + } | |
| 166 | + } | |
| 167 | + } | |
| 168 | + | |
| 169 | + void _showInitializationErrorDialog() { | |
| 170 | + showDialog( | |
| 171 | + context: context, | |
| 172 | + barrierDismissible: false, | |
| 173 | + builder: (dialogContext) => AlertDialog( | |
| 174 | + title: const Text('温馨提示'), | |
| 175 | + content: const Text('初始化失败,请检查网络后重试'), | |
| 176 | + actions: [ | |
| 177 | + const TextButton( | |
| 178 | + onPressed: AppConfigHelper.exitApp, | |
| 179 | + child: Text('退出'), | |
| 180 | + ), | |
| 181 | + TextButton( | |
| 182 | + onPressed: () { | |
| 183 | + Navigator.of(dialogContext).pop(); | |
| 184 | + _startInitialization(); | |
| 185 | + }, | |
| 186 | + child: const Text('重试'), | |
| 187 | + ), | |
| 188 | + ], | |
| 189 | + ), | |
| 190 | + ); | |
| 143 | 191 | } |
| 144 | 192 | |
| 145 | 193 | ///初始化数据 |
| 146 | - void _initData() { | |
| 147 | - UmengCommonSdk.initCommon("663b66b0b3362515012f4ea5", "663b66ecf32cc41105ae74b7", "official"); | |
| 148 | - pushNamedAndRemoveUntil(AppRouteName.home, (route) => false); | |
| 194 | + Future<void> _initData() async { | |
| 195 | + // 用户同意后,先准备 Native APM,再正式初始化 Common SDK。 | |
| 196 | + if (Platform.isAndroid) { | |
| 197 | + const MethodChannel umengMethodChannel = | |
| 198 | + MethodChannel('wow_english/umeng_method_channel'); | |
| 199 | + await umengMethodChannel.invokeMethod('prepareAfterPrivacyConsent'); | |
| 200 | + } | |
| 201 | + // Android 插件执行 initCommon 后不会回调 MethodChannel result,返回的 | |
| 202 | + // Future 永远不结束,因此这里只触发初始化,不能 await。 | |
| 203 | + unawaited(UmengCommonSdk.initCommon( | |
| 204 | + "663b66b0b3362515012f4ea5", "663b66ecf32cc41105ae74b7", "official") | |
| 205 | + .catchError((error, stackTrace) { | |
| 206 | + Log.d('友盟Common SDK初始化失败: $error\n$stackTrace'); | |
| 207 | + })); | |
| 208 | + await AudioPlayerUtil.getInstance() | |
| 209 | + .playAudio(AudioPlayerUtilType.welcomeToWow) | |
| 210 | + .timeout(const Duration(seconds: 10), onTimeout: () { | |
| 211 | + Log.d('欢迎音频播放超时,继续进入首页'); | |
| 212 | + }); | |
| 213 | + await startTime(); | |
| 149 | 214 | } |
| 150 | 215 | |
| 151 | 216 | Future<void> fetchNecessaryData(String userToken, |
| ... | ... | @@ -164,6 +229,12 @@ class _TransitionViewState extends State<TransitionView> { |
| 164 | 229 | completer.complete(); |
| 165 | 230 | } catch (e) { |
| 166 | 231 | debugPrint('Splash获取用户信息异常:$e'); |
| 232 | + if (!mounted) { | |
| 233 | + if (!completer.isCompleted) { | |
| 234 | + completer.complete(); | |
| 235 | + } | |
| 236 | + return; | |
| 237 | + } | |
| 167 | 238 | //异常的话弹窗提示重试 |
| 168 | 239 | showDialog( |
| 169 | 240 | context: context, |
| ... | ... | @@ -219,17 +290,26 @@ class _TransitionViewState extends State<TransitionView> { |
| 219 | 290 | changeDevice(); |
| 220 | 291 | await SpUtil.preInit(); |
| 221 | 292 | ModuleCache.instance.init(); |
| 222 | - await AudioPlayerUtil.getInstance().playAudio(AudioPlayerUtilType.welcomeToWow); | |
| 223 | - startTime(); | |
| 293 | + if (AppConfigHelper.getAgreementAccepted()) { | |
| 294 | + await _startInitialization(); | |
| 295 | + } else { | |
| 296 | + WidgetsBinding.instance.addPostFrameCallback((_) { | |
| 297 | + if (mounted) { | |
| 298 | + _showPrivacyDialog(); | |
| 299 | + } | |
| 300 | + }); | |
| 301 | + } | |
| 224 | 302 | } |
| 225 | 303 | |
| 226 | 304 | void changeDevice() async { |
| 227 | 305 | ///设置设备默认方向 |
| 228 | 306 | WidgetsFlutterBinding.ensureInitialized(); |
| 229 | 307 | if (Platform.isIOS) { |
| 230 | - await LimitingDirectionCsx.setScreenDirection(DeviceDirectionMask.Landscape); | |
| 308 | + await LimitingDirectionCsx.setScreenDirection( | |
| 309 | + DeviceDirectionMask.Landscape); | |
| 231 | 310 | } else { |
| 232 | - await SystemChrome.setPreferredOrientations([DeviceOrientation.landscapeLeft, DeviceOrientation.landscapeRight]); | |
| 311 | + await SystemChrome.setPreferredOrientations( | |
| 312 | + [DeviceOrientation.landscapeLeft, DeviceOrientation.landscapeRight]); | |
| 233 | 313 | } |
| 234 | 314 | await SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky); |
| 235 | 315 | } | ... | ... |
lib/common/core/app_config_helper.dart
| 1 | 1 | import 'dart:io'; |
| 2 | 2 | |
| 3 | -import 'package:flutter/cupertino.dart'; | |
| 4 | 3 | import 'package:flutter/foundation.dart'; |
| 5 | 4 | import 'package:flutter/services.dart'; |
| 6 | 5 | import 'package:package_info_plus/package_info_plus.dart'; |
| ... | ... | @@ -11,7 +10,6 @@ import '../../utils/sp_util.dart'; |
| 11 | 10 | import '../request/dao/system_dao.dart'; |
| 12 | 11 | |
| 13 | 12 | class AppConfigHelper { |
| 14 | - | |
| 15 | 13 | static const String _prefsKeyAgreementAccepted = "privacy_agreement_accepted"; |
| 16 | 14 | |
| 17 | 15 | static AppConfigEntity? configEntityEntity; |
| ... | ... | @@ -22,7 +20,7 @@ class AppConfigHelper { |
| 22 | 20 | static bool checkedUpdate = false; |
| 23 | 21 | |
| 24 | 22 | // 获取用户信息 |
| 25 | - static Future<AppConfigEntity?> getAppConfig({ bool forceSync = false }) async { | |
| 23 | + static Future<AppConfigEntity?> getAppConfig({bool forceSync = false}) async { | |
| 26 | 24 | if (forceSync == false && configEntityEntity != null) { |
| 27 | 25 | return configEntityEntity; |
| 28 | 26 | } |
| ... | ... | @@ -38,7 +36,8 @@ class AppConfigHelper { |
| 38 | 36 | // 是否需要隐藏... |
| 39 | 37 | static bool shouldHidePay() { |
| 40 | 38 | return isIosPlatform() && |
| 41 | - (configEntityEntity?.isAppReviewing() == true || UserUtil.getUser()?.phoneNum == "17730280759"); | |
| 39 | + (configEntityEntity?.isAppReviewing() == true || | |
| 40 | + UserUtil.getUser()?.phoneNum == "17730280759"); | |
| 42 | 41 | } |
| 43 | 42 | |
| 44 | 43 | // 获取app版本号 |
| ... | ... | @@ -51,22 +50,19 @@ class AppConfigHelper { |
| 51 | 50 | String versionCode = packageInfo.buildNumber; // 构建号 |
| 52 | 51 | _versionCode = versionCode; |
| 53 | 52 | |
| 54 | - debugPrint('versionName=$versionName versionCode=$versionCode platForm=${Platform.operatingSystem}'); | |
| 53 | + debugPrint( | |
| 54 | + 'versionName=$versionName versionCode=$versionCode platForm=${Platform.operatingSystem}'); | |
| 55 | 55 | return versionCode; |
| 56 | 56 | } |
| 57 | 57 | |
| 58 | - static void saveAgreementAccepted(bool accepted) { | |
| 59 | - SpUtil.getInstance().setData(_prefsKeyAgreementAccepted, accepted); | |
| 58 | + static Future<void> saveAgreementAccepted(bool accepted) async { | |
| 59 | + await SpUtil.getInstance().setData(_prefsKeyAgreementAccepted, accepted); | |
| 60 | 60 | } |
| 61 | 61 | |
| 62 | 62 | static bool getAgreementAccepted() { |
| 63 | 63 | return SpUtil.getInstance().get<bool>(_prefsKeyAgreementAccepted) ?? false; |
| 64 | 64 | } |
| 65 | 65 | |
| 66 | - static void _clearUserData() { | |
| 67 | - SpUtil.getInstance().remove(_prefsKeyAgreementAccepted); | |
| 68 | - } | |
| 69 | - | |
| 70 | 66 | static void exitApp() { |
| 71 | 67 | if (Platform.isIOS) { |
| 72 | 68 | exit(0); | ... | ... |
lib/main.dart
| ... | ... | @@ -8,17 +8,6 @@ import 'package:wow_english/app/app.dart'; |
| 8 | 8 | |
| 9 | 9 | import 'common/request/basic_config.dart'; |
| 10 | 10 | |
| 11 | -// void main() { | |
| 12 | -// ///设置设备默认方向 | |
| 13 | -// WidgetsFlutterBinding.ensureInitialized(); | |
| 14 | -// if (Platform.isAndroid) { | |
| 15 | -// SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle( //设置状态栏透明 | |
| 16 | -// statusBarColor: Colors.transparent, | |
| 17 | -// )); | |
| 18 | -// } | |
| 19 | -// runApp(const App()); | |
| 20 | -// } | |
| 21 | - | |
| 22 | 11 | void main() { |
| 23 | 12 | ///设置设备默认方向 |
| 24 | 13 | if (Platform.isAndroid) { |
| ... | ... | @@ -28,8 +17,8 @@ void main() { |
| 28 | 17 | } |
| 29 | 18 | |
| 30 | 19 | final UmengApmSdk umengApmSdk = UmengApmSdk( |
| 31 | - name: "", | |
| 32 | - bver: "", | |
| 20 | + name: '', | |
| 21 | + bver: '', | |
| 33 | 22 | |
| 34 | 23 | // 是否开启SDK运行时日志输出 |
| 35 | 24 | enableLog: BasicConfig.isTestDev, |
| ... | ... | @@ -56,12 +45,15 @@ void main() { |
| 56 | 45 | }, |
| 57 | 46 | |
| 58 | 47 | ); |
| 48 | + | |
| 49 | + // 此处只安装 Flutter 侧监控能力。Native APM/Common SDK 会保持未初始化状态, | |
| 50 | + // 直到用户同意隐私政策后才由 SplashPage 正式启动。 | |
| 59 | 51 | umengApmSdk.init(appRunner: (observer) async { |
| 60 | 52 | // 确保去掉原有的WidgetsFlutterBinding.ensureInitialized() ,以免出现重复初始化绑定的异常造成无法正常初始化,SDK内部已通过initFlutterBinding入参带入继承的WidgetsFlutterBinding实现初始化操作 |
| 61 | 53 | // 依赖ensureInitialized()初始化的代码可在此调用 |
| 62 | 54 | // 需要异步获取设置应用名称和版本号可在此回调中操作 |
| 63 | 55 | // SDK实例化的设置可先将name和bver 为 "",然后通过以下方式进行设置 |
| 64 | - PackageInfo packageInfo = await PackageInfo.fromPlatform(); | |
| 56 | + final PackageInfo packageInfo = await PackageInfo.fromPlatform(); | |
| 65 | 57 | String packageName = packageInfo.packageName; |
| 66 | 58 | String buildNumber = packageInfo.buildNumber; |
| 67 | 59 | String version = packageInfo.version; | ... | ... |
lib/utils/sp_util.dart
| ... | ... | @@ -28,17 +28,17 @@ class SpUtil { |
| 28 | 28 | return _instance!; |
| 29 | 29 | } |
| 30 | 30 | |
| 31 | - void setData<T>(String key, T data) { | |
| 31 | + Future<void> setData<T>(String key, T data) async { | |
| 32 | 32 | if (data is String) { |
| 33 | - _prefs?.setString(key, data); | |
| 33 | + await _prefs?.setString(key, data); | |
| 34 | 34 | } else if (data is double) { |
| 35 | - _prefs?.setDouble(key, data); | |
| 35 | + await _prefs?.setDouble(key, data); | |
| 36 | 36 | } else if (data is int) { |
| 37 | - _prefs?.setInt(key, data); | |
| 37 | + await _prefs?.setInt(key, data); | |
| 38 | 38 | } else if (data is bool) { |
| 39 | - _prefs?.setBool(key, data); | |
| 39 | + await _prefs?.setBool(key, data); | |
| 40 | 40 | } else if (data is List<String>) { |
| 41 | - _prefs?.setStringList(key, data); | |
| 41 | + await _prefs?.setStringList(key, data); | |
| 42 | 42 | } |
| 43 | 43 | } |
| 44 | 44 | ... | ... |
pubspec.yaml
| ... | ... | @@ -113,7 +113,7 @@ dependencies: |
| 113 | 113 | # 应用内更新 https://pub-web.flutter-io.cn/packages/flutter_app_update |
| 114 | 114 | flutter_app_update: ^3.0.4 |
| 115 | 115 | # 友盟统计 https://pub-web.flutter-io.cn/packages/umeng_common_sdk |
| 116 | - umeng_common_sdk: ^1.2.8 | |
| 116 | + umeng_common_sdk: ^1.3.1 | |
| 117 | 117 | # 友盟APM https://pub-web.flutter-io.cn/packages/umeng_apm_sdk |
| 118 | 118 | umeng_apm_sdk: ^2.3.2 |
| 119 | 119 | # 嵌套滚动 https://pub.dev/packages/nested_scroll_views | ... | ... |