返回

Flutter Webview setcookie 在 iOS-Wkwebview 首次进程不生效的解决方法

Android

解决 Flutter Webview setCookie 在 iOS-Wkwebview 首次进程不生效的 Bug

在 Flutter Webview 中使用 setCookie 方法在 iOS-Wkwebview 上设置 Cookie 时,可能会遇到首次进程不生效的 Bug。这是由于 iOS 中 WKwebview 采用的沙箱机制造成的。本文将深入探讨这个问题的根源并提供一种有效的解决方法。

问题根源

iOS 上的 WKwebview 采用了沙箱机制,将 Web 内容与 App 隔离。这意味着当首次设置 Cookie 时,Cookie 会被添加到 WKwebview 的沙箱中。但是,由于沙箱机制,这些 Cookie 无法被 App 进程直接读取。只有在终止进程并重新打开后,App 进程才能获取到 Cookie。

解决方法

要解决此 Bug,需要修改 iOS 端的代码。具体步骤如下:

1. 修改 iOS 端代码

  • 在 iOS 端的 AppDelegate.m 中,找到 WKUserContentController 对象。
  • 添加以下代码:
- (void)userContentController:(nonnull WKUserContentController *)userContentController didReceiveScriptMessage:(nonnull WKScriptMessage *)message {
  if ([message.name isEqualToString:@"setCookie"]) {
    NSDictionary *cookieDict = message.body;
    NSHTTPCookie *cookie = [[NSHTTPCookie alloc]initWithProperties:cookieDict];
    [[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:cookie domain:nil path:@"/" secure:NO excludesSubdomains:NO];
  }
}

2. 重新编译 App

  • 修改代码后,重新编译 App。

3. 重新打开 App

  • 重新打开 App,此时第一次设置的 Cookie 就会生效。

代码示例

以下是一个代码示例,展示了解决方法的实际实现:

// Flutter Webview 代码
import 'package:flutter/services.dart';
import 'package:flutter_webview_plugin/flutter_webview_plugin.dart';

class WebViewExample extends StatefulWidget {
  @override
  _MyAppState createState() => new _MyAppState();
}

class _MyAppState extends State<WebviewExample> {
  @override
  void initState() {
    super.initState();
    // 监听 WebView 的消息
    FlutterWebviewPlugin().onUrlChanged.listen((String url) {});
    FlutterWebviewPlugin().onWebviewMessage.listen((WebviewMessage message) {
      if (message.data == "setCookie") {
        // 在 iOS WKwebview 中设置 Cookie
        FlutterWebviewPlugin().evalJavascript("document.cookie = 'name=value'");
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: WebviewScaffold(
        url: "https://example.com", // 替换为你的网站 URL
        javascriptMode: JavascriptMode.unrestricted,
        mediaPlaybackPolicy: MediaPlaybackPolicy.requireUserActionForMediaPlayback,
        withZoom: false,
        withLocalStorage: true,
        withJavascript: true,
      ),
    );
  }
}

// iOS 端代码
- (void)userContentController:(nonnull WKUserContentController *)userContentController didReceiveScriptMessage:(nonnull WKScriptMessage *)message {
  if ([message.name isEqualToString:@"setCookie"]) {
    NSDictionary *cookieDict = message.body;
    NSHTTPCookie *cookie = [[NSHTTPCookie alloc]initWithProperties:cookieDict];
    [[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:cookie domain:nil path:@"/" secure:NO excludesSubdomains:NO];
  }
}

注意事项

  • 该方法仅适用于 iOS 上的 WKwebview。
  • 如果在 iOS 上使用的是 UIwebview,则不需要使用该方法。
  • 该方法需要修改 iOS 端的代码,可能需要重新编译 App。

总结

在 Flutter 中,使用 Webview 设置 Cookie 在 iOS-Wkwebview 首次进程不生效的 Bug 源于 WKwebview 的沙箱机制。通过修改 iOS 端代码并重新编译 App,可以有效解决此 Bug。遵循本文提供的步骤,即可轻松实现这一操作,从而确保在 iOS-Wkwebview 上设置 Cookie 时达到预期效果。

常见问题解答

  1. 此方法是否适用于所有版本的 iOS 和 Flutter?
    该方法适用于 iOS 13 及更高版本和 Flutter 3 及更高版本。

  2. 为什么需要修改 iOS 端的代码?
    因为 WKwebview 的沙箱机制,App 进程无法直接访问首次设置的 Cookie。修改 iOS 代码可以绕过此限制。

  3. 我需要重新编译整个 App 吗?
    是的,需要重新编译整个 App,以便修改后的 iOS 代码生效。

  4. 除了本文提供的解决方案外,还有其他方法可以解决此 Bug 吗?
    目前,修改 iOS 代码是唯一已知有效的解决方案。

  5. 此方法是否适用于所有 Webview 库?
    此方法仅适用于 Flutter 中使用的 Flutter Webview Plugin 库。