Flutter浏览器无法在自有WebView新标签加载外部应用链接
问题说明
使用flutter_inappwebview开发Flutter浏览器应用时,处理外部链接跳转遇到以下问题:
- 首次从第三方应用(如WhatsApp)选择本浏览器打开链接,链接会在第三方应用内置的WebView实例中加载,不会在独立的浏览器APP新标签页显示;
- 后续点击外部链接选择本浏览器,仅会唤起浏览器APP,但不会加载目标链接。
期望效果:每次选择本浏览器打开外部链接,均在浏览器的新标签页中加载目标链接。
核心原因
- Android端:Intent过滤器未配置正确的启动模式,导致应用被第三方应用以单任务模式唤起,链接数据无法传递到独立进程;同时未处理
ACTION_VIEWIntent的链接数据,无法触发新标签页创建逻辑。 - Flutter端:未在应用冷启动、热启动时监听外部传入的链接数据,也未将链接传递到已有的
OpenNewTab()方法。 - iOS端:
Info.plist的URL Scheme配置不完整,链接数据无法正确传递到APP。
解决方案
1. Android端配置修复
修改AndroidManifest.xml中主Activity的配置,确保应用以独立进程唤起并接收链接数据:
<activity android:name=".MainActivity" android:launchMode="singleTop" android:exported="true" android:theme="@style/LaunchTheme" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" android:hardwareAccelerated="true" android:windowSoftInputMode="adjustResize"> <!-- 启动页配置 --> <meta-data android:name="io.flutter.embedding.android.NormalTheme" android:resource="@style/NormalTheme" /> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> <!-- 外部链接处理的Intent过滤器 --> <intent-filter android:autoVerify="true"> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <data android:scheme="http" /> <data android:scheme="https" /> </intent-filter> <meta-data android:name="flutterEmbedding" android:value="2" /> </activity>
2. iOS端配置修复
修改Info.plist,添加URL Scheme和通用链接支持:
<!-- URL Scheme支持 --> <key>CFBundleURLTypes</key> <array> <dict> <key>CFBundleURLSchemes</key> <array> <string>http</string> <string>https</string> </array> </dict> </array> <!-- 允许任意网络请求(适配测试环境) --> <key>NSAppTransportSecurity</key> <dict> <key>NSAllowsArbitraryLoads</key> <true/> </dict> <!-- 支持查询HTTP/HTTPS链接 --> <key>LSApplicationQueriesSchemes</key> <array> <string>http</string> <string>https</string> </array>
3. Flutter代码调整
处理Android端Intent数据
创建MainActivity.kt,重写onNewIntent方法将链接传递给Flutter:
import io.flutter.embedding.android.FlutterActivity import io.flutter.embedding.engine.FlutterEngine import io.flutter.plugin.common.MethodChannel class MainActivity : FlutterActivity() { private val CHANNEL = "com.yourapp.channel/external_links" override fun configureFlutterEngine(flutterEngine: FlutterEngine) { super.configureFlutterEngine(flutterEngine) // 处理冷启动时的Intent链接 intent.data?.let { uri -> sendLinkToFlutter(uri.toString(), flutterEngine) } } override fun onNewIntent(intent: android.content.Intent?) { super.onNewIntent(intent) intent?.data?.let { uri -> sendLinkToFlutter(uri.toString(), flutterEngine!!) } } private fun sendLinkToFlutter(link: String, flutterEngine: FlutterEngine) { MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).invokeMethod("openExternalLink", link) } }
在HomePage中监听链接并打开新标签
修改home_page.dart,添加MethodChannel监听和iOS链接处理逻辑:
import 'package:flutter/services.dart'; import 'package:flutter_inappwebview/flutter_inappwebview.dart'; import 'package:uni_links/uni_links.dart'; class HomePage extends StatefulWidget { const HomePage({super.key}); @override State<HomePage> createState() => _HomePageState(); } class _HomePageState extends State<HomePage> { final MethodChannel _channel = const MethodChannel("com.yourapp.channel/external_links"); List<WebViewTab> tabs = []; @override void initState() { super.initState(); // 监听Android端传入的链接 _channel.setMethodCallHandler((call) async { if (call.method == "openExternalLink") { String? url = call.arguments as String?; url?.let(OpenNewTab); } }); // 处理iOS冷启动和后续链接 WidgetsBinding.instance.addPostFrameCallback((_) => _handleIosLinks()); } Future<void> _handleIosLinks() async { // 冷启动链接 final Uri? initialUri = await getInitialUri(); initialUri?.toString().let(OpenNewTab); // 后续跳转链接 uriLinkStream.listen((Uri? uri) => uri?.toString().let(OpenNewTab)); } // 已有打开新标签方法 void OpenNewTab(String url) { setState(() { tabs.add(WebViewTab( key: UniqueKey(), url: Uri.parse(url), )); }); } @override Widget build(BuildContext context) { // 你的页面布局代码 return Scaffold( // ... 现有布局 ); } }
确保WebViewTab正确接收URL
修改webview_tab.dart,保证初始URL配置正确:
class WebViewTab extends StatefulWidget { final Uri url; const WebViewTab({super.key, required this.url}); @override State<WebViewTab> createState() => _WebViewTabState(); } class _WebViewTabState extends State<WebViewTab> { late InAppWebViewController webViewController; @override Widget build(BuildContext context) { return InAppWebView( initialUrlRequest: URLRequest(url: widget.url), onWebViewCreated: (controller) => webViewController = controller, shouldOverrideUrlLoading: (controller, navigationAction) async { final uri = navigationAction.request.url; return uri != null ? NavigationActionPolicy.ALLOW : NavigationActionPolicy.CANCEL; }, ); } }
内容的提问来源于stack exchange,提问作者ayushkadbe
相关产品推荐
相关产品推荐

