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

Flutter浏览器无法在自有WebView新标签加载外部应用链接

问题说明

使用flutter_inappwebview开发Flutter浏览器应用时,处理外部链接跳转遇到以下问题:

  • 首次从第三方应用(如WhatsApp)选择本浏览器打开链接,链接会在第三方应用内置的WebView实例中加载,不会在独立的浏览器APP新标签页显示;
  • 后续点击外部链接选择本浏览器,仅会唤起浏览器APP,但不会加载目标链接。

期望效果:每次选择本浏览器打开外部链接,均在浏览器的新标签页中加载目标链接。


核心原因
  1. Android端:Intent过滤器未配置正确的启动模式,导致应用被第三方应用以单任务模式唤起,链接数据无法传递到独立进程;同时未处理ACTION_VIEW Intent的链接数据,无法触发新标签页创建逻辑。
  2. Flutter端:未在应用冷启动、热启动时监听外部传入的链接数据,也未将链接传递到已有的OpenNewTab()方法。
  3. 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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 05:44:56