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,8 +11,11 @@ import com.gyf.immersionbar.ImmersionBar | ||
| 11 | import com.kouyuxingqiu.wow_english.methodChannels.GameMethodChannel | 11 | import com.kouyuxingqiu.wow_english.methodChannels.GameMethodChannel |
| 12 | import com.kouyuxingqiu.wow_english.methodChannels.SingSoungMethodChannel | 12 | import com.kouyuxingqiu.wow_english.methodChannels.SingSoungMethodChannel |
| 13 | import com.umeng.commonsdk.UMConfigure | 13 | import com.umeng.commonsdk.UMConfigure |
| 14 | -import io.flutter.embedding.android.FlutterActivity | ||
| 15 | import com.umeng.umcrash.UMCrash | 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 | class MainActivity : FlutterActivity() { | 21 | class MainActivity : FlutterActivity() { |
| @@ -25,7 +28,11 @@ class MainActivity : FlutterActivity() { | @@ -25,7 +28,11 @@ class MainActivity : FlutterActivity() { | ||
| 25 | SingSoungMethodChannel(this, it) | 28 | SingSoungMethodChannel(this, it) |
| 26 | GameMethodChannel(this, it) | 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 | override fun onResume() { | 38 | override fun onResume() { |
| @@ -60,11 +67,26 @@ class MainActivity : FlutterActivity() { | @@ -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 | UMCrash.initConfig(Bundle().apply { | 90 | UMCrash.initConfig(Bundle().apply { |
| 69 | putBoolean(UMCrash.KEY_ENABLE_CRASH_JAVA, true) | 91 | putBoolean(UMCrash.KEY_ENABLE_CRASH_JAVA, true) |
| 70 | putBoolean(UMCrash.KEY_ENABLE_CRASH_NATIVE, true) | 92 | putBoolean(UMCrash.KEY_ENABLE_CRASH_NATIVE, true) |
| @@ -75,8 +97,6 @@ class MainActivity : FlutterActivity() { | @@ -75,8 +97,6 @@ class MainActivity : FlutterActivity() { | ||
| 75 | putBoolean(UMCrash.KEY_ENABLE_H5PAGE, false) | 97 | putBoolean(UMCrash.KEY_ENABLE_H5PAGE, false) |
| 76 | putBoolean(UMCrash.KEY_ENABLE_POWER, false) | 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,7 +23,6 @@ import '../common/core/module_cache.dart'; | ||
| 23 | import '../common/widgets/webview_dialog.dart'; | 23 | import '../common/widgets/webview_dialog.dart'; |
| 24 | import '../common/utils/staticstring/userregister.dart'; | 24 | import '../common/utils/staticstring/userregister.dart'; |
| 25 | 25 | ||
| 26 | - | ||
| 27 | class SplashPage extends StatelessWidget { | 26 | class SplashPage extends StatelessWidget { |
| 28 | const SplashPage({super.key}); | 27 | const SplashPage({super.key}); |
| 29 | 28 | ||
| @@ -43,10 +42,14 @@ class TransitionView extends StatefulWidget { | @@ -43,10 +42,14 @@ class TransitionView extends StatefulWidget { | ||
| 43 | } | 42 | } |
| 44 | 43 | ||
| 45 | class _TransitionViewState extends State<TransitionView> { | 44 | class _TransitionViewState extends State<TransitionView> { |
| 45 | + bool _isPrivacyDecisionInProgress = false; | ||
| 46 | + bool _isInitializing = false; | ||
| 47 | + | ||
| 46 | Future startTime() async { | 48 | Future startTime() async { |
| 47 | // 判断是否登录 | 49 | // 判断是否登录 |
| 48 | UserEntity? userEntity = UserUtil.getUser(); | 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 | Log.d('当前API地址:${RequestConfig.baseUrl}'); | 53 | Log.d('当前API地址:${RequestConfig.baseUrl}'); |
| 51 | //BuildContext context = Navigator.of(context).context; | 54 | //BuildContext context = Navigator.of(context).context; |
| 52 | //var currentPageName = ModalRoute.of(Navigator.of(AppRouter.context))?.settings.name; | 55 | //var currentPageName = ModalRoute.of(Navigator.of(AppRouter.context))?.settings.name; |
| @@ -63,89 +66,151 @@ class _TransitionViewState extends State<TransitionView> { | @@ -63,89 +66,151 @@ class _TransitionViewState extends State<TransitionView> { | ||
| 63 | apartInMilliseconds = DateTime.now().difference(startTime).inMilliseconds; | 66 | apartInMilliseconds = DateTime.now().difference(startTime).inMilliseconds; |
| 64 | } | 67 | } |
| 65 | int duration = max(1500 - apartInMilliseconds, 0); | 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 | Timer(Duration(milliseconds: duration), () { | 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 | Widget child() { | 92 | Widget child() { |
| 95 | if (Platform.isIOS) { | 93 | if (Platform.isIOS) { |
| 96 | return AlertDialog( | 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 | width: MediaQuery.of(context).size.height, | 99 | width: MediaQuery.of(context).size.height, |
| 102 | height: MediaQuery.of(context).size.height, | 100 | height: MediaQuery.of(context).size.height, |
| 103 | - child: SingleChildScrollView( | 101 | + child: const SingleChildScrollView( |
| 104 | child: Text(UserRegisterString.userPrivacyPolicyStr), | 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 | return WebviewDialog( | 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 | Future<void> fetchNecessaryData(String userToken, | 216 | Future<void> fetchNecessaryData(String userToken, |
| @@ -164,6 +229,12 @@ class _TransitionViewState extends State<TransitionView> { | @@ -164,6 +229,12 @@ class _TransitionViewState extends State<TransitionView> { | ||
| 164 | completer.complete(); | 229 | completer.complete(); |
| 165 | } catch (e) { | 230 | } catch (e) { |
| 166 | debugPrint('Splash获取用户信息异常:$e'); | 231 | debugPrint('Splash获取用户信息异常:$e'); |
| 232 | + if (!mounted) { | ||
| 233 | + if (!completer.isCompleted) { | ||
| 234 | + completer.complete(); | ||
| 235 | + } | ||
| 236 | + return; | ||
| 237 | + } | ||
| 167 | //异常的话弹窗提示重试 | 238 | //异常的话弹窗提示重试 |
| 168 | showDialog( | 239 | showDialog( |
| 169 | context: context, | 240 | context: context, |
| @@ -219,17 +290,26 @@ class _TransitionViewState extends State<TransitionView> { | @@ -219,17 +290,26 @@ class _TransitionViewState extends State<TransitionView> { | ||
| 219 | changeDevice(); | 290 | changeDevice(); |
| 220 | await SpUtil.preInit(); | 291 | await SpUtil.preInit(); |
| 221 | ModuleCache.instance.init(); | 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 | void changeDevice() async { | 304 | void changeDevice() async { |
| 227 | ///设置设备默认方向 | 305 | ///设置设备默认方向 |
| 228 | WidgetsFlutterBinding.ensureInitialized(); | 306 | WidgetsFlutterBinding.ensureInitialized(); |
| 229 | if (Platform.isIOS) { | 307 | if (Platform.isIOS) { |
| 230 | - await LimitingDirectionCsx.setScreenDirection(DeviceDirectionMask.Landscape); | 308 | + await LimitingDirectionCsx.setScreenDirection( |
| 309 | + DeviceDirectionMask.Landscape); | ||
| 231 | } else { | 310 | } else { |
| 232 | - await SystemChrome.setPreferredOrientations([DeviceOrientation.landscapeLeft, DeviceOrientation.landscapeRight]); | 311 | + await SystemChrome.setPreferredOrientations( |
| 312 | + [DeviceOrientation.landscapeLeft, DeviceOrientation.landscapeRight]); | ||
| 233 | } | 313 | } |
| 234 | await SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky); | 314 | await SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky); |
| 235 | } | 315 | } |
lib/common/core/app_config_helper.dart
| 1 | import 'dart:io'; | 1 | import 'dart:io'; |
| 2 | 2 | ||
| 3 | -import 'package:flutter/cupertino.dart'; | ||
| 4 | import 'package:flutter/foundation.dart'; | 3 | import 'package:flutter/foundation.dart'; |
| 5 | import 'package:flutter/services.dart'; | 4 | import 'package:flutter/services.dart'; |
| 6 | import 'package:package_info_plus/package_info_plus.dart'; | 5 | import 'package:package_info_plus/package_info_plus.dart'; |
| @@ -11,7 +10,6 @@ import '../../utils/sp_util.dart'; | @@ -11,7 +10,6 @@ import '../../utils/sp_util.dart'; | ||
| 11 | import '../request/dao/system_dao.dart'; | 10 | import '../request/dao/system_dao.dart'; |
| 12 | 11 | ||
| 13 | class AppConfigHelper { | 12 | class AppConfigHelper { |
| 14 | - | ||
| 15 | static const String _prefsKeyAgreementAccepted = "privacy_agreement_accepted"; | 13 | static const String _prefsKeyAgreementAccepted = "privacy_agreement_accepted"; |
| 16 | 14 | ||
| 17 | static AppConfigEntity? configEntityEntity; | 15 | static AppConfigEntity? configEntityEntity; |
| @@ -22,7 +20,7 @@ class AppConfigHelper { | @@ -22,7 +20,7 @@ class AppConfigHelper { | ||
| 22 | static bool checkedUpdate = false; | 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 | if (forceSync == false && configEntityEntity != null) { | 24 | if (forceSync == false && configEntityEntity != null) { |
| 27 | return configEntityEntity; | 25 | return configEntityEntity; |
| 28 | } | 26 | } |
| @@ -38,7 +36,8 @@ class AppConfigHelper { | @@ -38,7 +36,8 @@ class AppConfigHelper { | ||
| 38 | // 是否需要隐藏... | 36 | // 是否需要隐藏... |
| 39 | static bool shouldHidePay() { | 37 | static bool shouldHidePay() { |
| 40 | return isIosPlatform() && | 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 | // 获取app版本号 | 43 | // 获取app版本号 |
| @@ -51,22 +50,19 @@ class AppConfigHelper { | @@ -51,22 +50,19 @@ class AppConfigHelper { | ||
| 51 | String versionCode = packageInfo.buildNumber; // 构建号 | 50 | String versionCode = packageInfo.buildNumber; // 构建号 |
| 52 | _versionCode = versionCode; | 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 | return versionCode; | 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 | static bool getAgreementAccepted() { | 62 | static bool getAgreementAccepted() { |
| 63 | return SpUtil.getInstance().get<bool>(_prefsKeyAgreementAccepted) ?? false; | 63 | return SpUtil.getInstance().get<bool>(_prefsKeyAgreementAccepted) ?? false; |
| 64 | } | 64 | } |
| 65 | 65 | ||
| 66 | - static void _clearUserData() { | ||
| 67 | - SpUtil.getInstance().remove(_prefsKeyAgreementAccepted); | ||
| 68 | - } | ||
| 69 | - | ||
| 70 | static void exitApp() { | 66 | static void exitApp() { |
| 71 | if (Platform.isIOS) { | 67 | if (Platform.isIOS) { |
| 72 | exit(0); | 68 | exit(0); |
lib/main.dart
| @@ -8,17 +8,6 @@ import 'package:wow_english/app/app.dart'; | @@ -8,17 +8,6 @@ import 'package:wow_english/app/app.dart'; | ||
| 8 | 8 | ||
| 9 | import 'common/request/basic_config.dart'; | 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 | void main() { | 11 | void main() { |
| 23 | ///设置设备默认方向 | 12 | ///设置设备默认方向 |
| 24 | if (Platform.isAndroid) { | 13 | if (Platform.isAndroid) { |
| @@ -28,8 +17,8 @@ void main() { | @@ -28,8 +17,8 @@ void main() { | ||
| 28 | } | 17 | } |
| 29 | 18 | ||
| 30 | final UmengApmSdk umengApmSdk = UmengApmSdk( | 19 | final UmengApmSdk umengApmSdk = UmengApmSdk( |
| 31 | - name: "", | ||
| 32 | - bver: "", | 20 | + name: '', |
| 21 | + bver: '', | ||
| 33 | 22 | ||
| 34 | // 是否开启SDK运行时日志输出 | 23 | // 是否开启SDK运行时日志输出 |
| 35 | enableLog: BasicConfig.isTestDev, | 24 | enableLog: BasicConfig.isTestDev, |
| @@ -56,12 +45,15 @@ void main() { | @@ -56,12 +45,15 @@ void main() { | ||
| 56 | }, | 45 | }, |
| 57 | 46 | ||
| 58 | ); | 47 | ); |
| 48 | + | ||
| 49 | + // 此处只安装 Flutter 侧监控能力。Native APM/Common SDK 会保持未初始化状态, | ||
| 50 | + // 直到用户同意隐私政策后才由 SplashPage 正式启动。 | ||
| 59 | umengApmSdk.init(appRunner: (observer) async { | 51 | umengApmSdk.init(appRunner: (observer) async { |
| 60 | // 确保去掉原有的WidgetsFlutterBinding.ensureInitialized() ,以免出现重复初始化绑定的异常造成无法正常初始化,SDK内部已通过initFlutterBinding入参带入继承的WidgetsFlutterBinding实现初始化操作 | 52 | // 确保去掉原有的WidgetsFlutterBinding.ensureInitialized() ,以免出现重复初始化绑定的异常造成无法正常初始化,SDK内部已通过initFlutterBinding入参带入继承的WidgetsFlutterBinding实现初始化操作 |
| 61 | // 依赖ensureInitialized()初始化的代码可在此调用 | 53 | // 依赖ensureInitialized()初始化的代码可在此调用 |
| 62 | // 需要异步获取设置应用名称和版本号可在此回调中操作 | 54 | // 需要异步获取设置应用名称和版本号可在此回调中操作 |
| 63 | // SDK实例化的设置可先将name和bver 为 "",然后通过以下方式进行设置 | 55 | // SDK实例化的设置可先将name和bver 为 "",然后通过以下方式进行设置 |
| 64 | - PackageInfo packageInfo = await PackageInfo.fromPlatform(); | 56 | + final PackageInfo packageInfo = await PackageInfo.fromPlatform(); |
| 65 | String packageName = packageInfo.packageName; | 57 | String packageName = packageInfo.packageName; |
| 66 | String buildNumber = packageInfo.buildNumber; | 58 | String buildNumber = packageInfo.buildNumber; |
| 67 | String version = packageInfo.version; | 59 | String version = packageInfo.version; |
lib/utils/sp_util.dart
| @@ -28,17 +28,17 @@ class SpUtil { | @@ -28,17 +28,17 @@ class SpUtil { | ||
| 28 | return _instance!; | 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 | if (data is String) { | 32 | if (data is String) { |
| 33 | - _prefs?.setString(key, data); | 33 | + await _prefs?.setString(key, data); |
| 34 | } else if (data is double) { | 34 | } else if (data is double) { |
| 35 | - _prefs?.setDouble(key, data); | 35 | + await _prefs?.setDouble(key, data); |
| 36 | } else if (data is int) { | 36 | } else if (data is int) { |
| 37 | - _prefs?.setInt(key, data); | 37 | + await _prefs?.setInt(key, data); |
| 38 | } else if (data is bool) { | 38 | } else if (data is bool) { |
| 39 | - _prefs?.setBool(key, data); | 39 | + await _prefs?.setBool(key, data); |
| 40 | } else if (data is List<String>) { | 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,7 +113,7 @@ dependencies: | ||
| 113 | # 应用内更新 https://pub-web.flutter-io.cn/packages/flutter_app_update | 113 | # 应用内更新 https://pub-web.flutter-io.cn/packages/flutter_app_update |
| 114 | flutter_app_update: ^3.0.4 | 114 | flutter_app_update: ^3.0.4 |
| 115 | # 友盟统计 https://pub-web.flutter-io.cn/packages/umeng_common_sdk | 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 | # 友盟APM https://pub-web.flutter-io.cn/packages/umeng_apm_sdk | 117 | # 友盟APM https://pub-web.flutter-io.cn/packages/umeng_apm_sdk |
| 118 | umeng_apm_sdk: ^2.3.2 | 118 | umeng_apm_sdk: ^2.3.2 |
| 119 | # 嵌套滚动 https://pub.dev/packages/nested_scroll_views | 119 | # 嵌套滚动 https://pub.dev/packages/nested_scroll_views |