如何在Flutter的Modal Bottom Sheet内嵌入支付网页,避免打开外部页面?
解决Flutter Modal Bottom Sheet内显示支付WebView的问题
问题根源
你当前使用的launchUrl方法,本质就是调用系统默认浏览器/应用打开外部链接,所以必然会跳转到外部页面,这就是核心问题所在。
解决方案
要在Bottom Sheet内嵌入支付页面,需要使用Flutter官方的webview_flutter插件,直接将网页嵌入模态框中,替换掉launchUrl的跳转逻辑。
步骤1:添加依赖
在项目的pubspec.yaml中添加webview_flutter依赖:
dependencies: flutter: sdk: flutter webview_flutter: ^4.4.0 # 可替换为最新版本
执行flutter pub get完成依赖安装。
步骤2:修改代码替换跳转逻辑
把原代码中的FutureBuilder和launchUrl替换为WebView组件,调整布局让网页占满模态框的剩余空间,同时保留加载状态控制:
await showModalBottomSheet( elevation: 10, backgroundColor: Colors.transparent, isScrollControlled: true, context: context, builder: (context) { // 用StatefulBuilder管理加载状态 return StatefulBuilder( builder: (context, setState) { bool isLoading = true; return Container( decoration: const BoxDecoration( color: Colors.white, borderRadius: BorderRadius.only( topLeft: Radius.circular(30), topRight: Radius.circular(30), ), ), height: MediaQuery.of(context).size.height * 0.9, child: Column( children: [ // 顶部关闭按钮 Padding( padding: EdgeInsets.only( top: MediaQuery.of(context).size.height * 0.03, left: MediaQuery.of(context).size.width * 0.05, ), child: Row( children: [ Container( height: 40, width: 40, decoration: BoxDecoration( color: AppColors.drawerTextListTileColor, borderRadius: BorderRadius.circular(10), ), child: IconButton( onPressed: () { Navigator.of(context).pop(); }, icon: const Icon(Icons.close, color: Colors.white), ), ), const Spacer(), ], ), ), // 用Expanded让WebView占满剩余空间 Expanded( child: Stack( children: [ WebView( initialUrl: resultParsed.topUpWallet.url, javascriptMode: JavascriptMode.unrestricted, // 支付页面需开启JS支持 onPageStarted: (url) { setState(() => isLoading = true); }, onPageFinished: (url) { setState(() => isLoading = false); }, // 拦截导航,防止跳转到外部浏览器 navigationDelegate: (NavigationRequest request) { // 只允许支付域名下的链接在WebView内打开 if (request.url.startsWith('https://你的支付域名前缀')) { return NavigationDecision.navigate; } // 其他链接禁止跳转,可根据需求调整 return NavigationDecision.prevent; }, ), // 加载状态指示器 if (isLoading) const Center(child: CircularProgressIndicator()), ], ), ), ], ), ); }, ); }, );
关键说明
- WebView替代launchUrl:直接将支付页面嵌入App内部,完全避免外部跳转。
- Expanded布局:确保WebView占满模态框除顶部按钮外的所有可用空间。
- JavaScript支持:绝大多数支付页面依赖JavaScript,必须设置
JavascriptMode.unrestricted。 - 导航拦截:通过
navigationDelegate控制页面跳转,确保支付流程全程在WebView内完成。
内容的提问来源于stack exchange,提问作者Farid Ahmadov
相关产品推荐
相关产品推荐

