You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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是应用的根组件,重建它等同于触发应用重启,这就是问题的根源。

修复步骤

  1. 调整组件层级,避免重建根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(),
        );
      }
    }
    
  2. 在目标页面中包裹 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(
                // 页面内容
              );
            },
          ),
        );
      }
    }
    
  3. 优化密钥更新逻辑
    保留GetX的响应式更新即可,无需额外操作:

    class GlobalController extends GetxController {
      final RxString khaltiPubKey = "初始默认密钥".obs;
    
      void changePublicKey(String newKey) {
        khaltiPubKey.value = newKey;
      }
    }
    
  4. 检查 SmartManagement 设置
    若不需要自动销毁控制器,可将SmartManagement.full改为SmartManagement.keepFactory,避免因控制器销毁重建导致的意外问题;若业务依赖full模式,只要确保GlobalController设置了permanent: true即可(当前代码已满足)。

额外注意事项

  • 确保在选择学校并设置密钥完成后,再跳转至需要使用Khalti的页面,此时密钥已准备就绪。
  • 不要在GetMaterialApp的初始化逻辑中依赖动态变化的参数,否则参数变动会触发根App重建。

内容的提问来源于stack exchange,提问作者Saurav

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 09:37:49