Flutter无需重启应用修改MyApp内Khalti公钥的方案咨询
问题描述
应用首次启动展示学校列表,选择学校后跳转至登录页面。当前痛点:选择学校后获取的密钥需要传入main.dart引用的my_app.dart中,且不能重启整个应用。目前能修改密钥值,但应用会持续重启,求技术解决方案。
相关代码
MyApp 组件代码
class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Obx( () => KhaltiScope( publicKey: globalCtrl.khaltiPubKey.value, builder: (context, navKey) { return GetMaterialApp( translations: LanguageTranslate(), locale: Get.deviceLocale, smartManagement: SmartManagement.full, initialBinding: Binder(), debugShowCheckedModeBanner: false, title: 'Merovidya Student', navigatorKey: navKey, fallbackLocale: const Locale("en", "US"), theme: ThemeData( primaryColor: primaryColor1, visualDensity: VisualDensity.adaptivePlatformDensity, scaffoldBackgroundColor: scaffoldBackgroundColor, brightness: Brightness.light, ), getPages: MeroRoutes.routes, supportedLocales: const [ Locale('en', 'US'), Locale('ne', 'NP'), ], localizationsDelegates: const [ KhaltiLocalizations.delegate, ], home: const SplashScreen(), ); }, ), ); } }
GlobalController 密钥更新函数
changePublicKey() { logger.i("This is public key", khaltiPubKey.value); khaltiPubKey.value = Keys.khalthiPublicKey; logger.i("This is public key1", khaltiPubKey.value); }
main.dart 初始化代码
void main() async { WidgetsFlutterBinding.ensureInitialized(); SystemChrome.setPreferredOrientations([ DeviceOrientation.portraitUp, //DeviceOrientation.portraitDown, // DeviceOrientation.landscapeLeft, // DeviceOrientation.landscapeRight ]); Binder(); await Preferences().init(); await Firebase.initializeApp(); FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler); Get.put(GlobalController(), permanent: true); runApp(const MyApp()); }
解决方案
核心问题分析
当前代码中,Obx监听khaltiPubKey变化时会重建整个GetMaterialApp——而GetMaterialApp是应用的根组件,重建它等同于触发应用重启,这就是问题的根源。
修复步骤
调整组件层级,避免重建根App
把KhaltiScope从MyApp的根层级移到需要使用Khalti功能的子页面(比如支付页面、登录后的主页面),这样只有目标页面会随密钥变化重建,不会影响整个应用。修改后的
MyApp代码:class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return GetMaterialApp( translations: LanguageTranslate(), locale: Get.deviceLocale, smartManagement: SmartManagement.full, initialBinding: Binder(), debugShowCheckedModeBanner: false, title: 'Merovidya Student', fallbackLocale: const Locale("en", "US"), theme: ThemeData( primaryColor: primaryColor1, visualDensity: VisualDensity.adaptivePlatformDensity, scaffoldBackgroundColor: scaffoldBackgroundColor, brightness: Brightness.light, ), getPages: MeroRoutes.routes, supportedLocales: const [ Locale('en', 'US'), Locale('ne', 'NP'), ], localizationsDelegates: const [ KhaltiLocalizations.delegate, ], home: const SplashScreen(), ); } }在目标页面中包裹 KhaltiScope
以登录后的主页面为例:class HomePage extends StatelessWidget { final GlobalController globalCtrl = Get.find(); HomePage({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Obx( () => KhaltiScope( publicKey: globalCtrl.khaltiPubKey.value, builder: (context, navKey) { return Scaffold( // 页面内容 ); }, ), ); } }优化密钥更新逻辑
保留GetX的响应式更新即可,无需额外操作:class GlobalController extends GetxController { final RxString khaltiPubKey = "初始默认密钥".obs; void changePublicKey(String newKey) { khaltiPubKey.value = newKey; } }检查 SmartManagement 设置
若不需要自动销毁控制器,可将SmartManagement.full改为SmartManagement.keepFactory,避免因控制器销毁重建导致的意外问题;若业务依赖full模式,只要确保GlobalController设置了permanent: true即可(当前代码已满足)。
额外注意事项
- 确保在选择学校并设置密钥完成后,再跳转至需要使用Khalti的页面,此时密钥已准备就绪。
- 不要在
GetMaterialApp的初始化逻辑中依赖动态变化的参数,否则参数变动会触发根App重建。
内容的提问来源于stack exchange,提问作者Saurav
相关产品推荐
相关产品推荐

