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

webview_flutter结合appTrackingTransparency处理Cookie技术咨询(含苹果拒审解决及示例代码需求)

Hey fellow dev, I’ve been through this exact scenario where an app got rejected because WebView cookies triggered Apple’s tracking rules. Here’s a practical implementation to handle ATT authorization alongside cookie control, plus tips to "hide" (restrict) unwanted cookies.

1. Core Logic Overview

  • Trigger ATT Prompt: Detect when the WebView attempts to set cookies, then launch the App Tracking Transparency authorization dialog.
  • Cookie Control:
    • If user grants authorization: Allow cookies to be stored and used normally.
    • If user denies/restricts: Block cookie storage and clear any existing related cookies.

2. Step-by-Step Implementation Code

First, add required dependencies to your pubspec.yaml:

dependencies:
  webview_flutter: ^4.4.0 # Use latest stable version
  app_tracking_transparency: ^2.0.4 # Use latest stable version
import 'package:app_tracking_transparency/app_tracking_transparency.dart';
import 'package:webview_flutter/webview_flutter.dart';
import 'package:webview_flutter_android/webview_flutter_android.dart';
import 'package:webview_flutter_wkwebview/webview_flutter_wkwebview.dart';

class WebViewCookieHandler extends StatefulWidget {
  final String initialUrl;
  const WebViewCookieHandler({super.key, required this.initialUrl});

  @override
  State<WebViewCookieHandler> createState() => _WebViewCookieHandlerState();
}

class _WebViewCookieHandlerState extends State<WebViewCookieHandler> {
  late WebViewController _controller;
  final CookieManager _cookieManager = CookieManager();
  bool _attAuthorized = false;

  @override
  void initState() {
    super.initState();
    _initAtt();
    _initWebViewController();
  }

  // Initialize ATT status on app start
  Future<void> _initAtt() async {
    final TrackingStatus status = await AppTrackingTransparency.requestTrackingAuthorization();
    setState(() {
      _attAuthorized = status == TrackingStatus.authorized;
    });
  }

  // Setup WebView controller with cookie intercept logic
  void _initWebViewController() {
    late final PlatformWebViewControllerCreationParams params;
    if (WebViewPlatform.instance is WebKitWebViewPlatform) {
      params = WebKitWebViewControllerCreationParams(
        allowsInlineMediaPlayback: true,
        mediaTypesRequiringUserAction: const <PlaybackMediaTypes>{},
      );
    } else {
      params = const PlatformWebViewControllerCreationParams();
    }

    final WebViewController controller = WebViewController.fromPlatformCreationParams(params);

    // Listen for page start to check/trigger ATT before cookies are set
    controller.setNavigationDelegate(NavigationDelegate(
      onPageStarted: (String url) async {
        if (!_attAuthorized) {
          // Re-request ATT if user hasn't decided yet
          final TrackingStatus status = await AppTrackingTransparency.requestTrackingAuthorization();
          setState(() {
            _attAuthorized = status == TrackingStatus.authorized;
          });
          // Update cookie permissions right after ATT decision
          await _updateCookiePermissions();
        }
      },
      onNavigationRequest: (NavigationRequest request) async {
        // Block cookie headers if user denied ATT
        if (!_attAuthorized) {
          final modifiedHeaders = Map.from(request.headers)..remove('Cookie');
          // Note: For full blocking, you might need to use a custom request interceptor
          return NavigationDecision.navigate;
        }
        return NavigationDecision.navigate;
      },
    ));

    // Load initial URL with base settings
    controller.loadRequest(Uri.parse(widget.initialUrl));
    _controller = controller;
  }

  // Update cookie permissions based on ATT status
  Future<void> _updateCookiePermissions() async {
    if (!_attAuthorized) {
      // Clear all existing cookies for the WebView
      await _cookieManager.deleteAllCookies();
      // Restrict cookies on iOS (WKWebView)
      if (WebViewPlatform.instance is WebKitWebViewPlatform) {
        final WebKitWebViewController webKitController = _controller.platform as WebKitWebViewController;
        await webKitController.setPreferences(
          WebKitPreferences(
            allowsContentJavaScript: true,
            thirdPartyCookiesEnabled: false,
          ),
        );
      }
      // Disable cookie acceptance on Android
      if (WebViewPlatform.instance is AndroidWebViewPlatform) {
        final AndroidWebViewController androidController = _controller.platform as AndroidWebViewController;
        await androidController.setSettings(AndroidSettings(
          javaScriptEnabled: true,
          acceptCookie: false,
        ));
      }
    } else {
      // Re-enable cookies if user authorized
      if (WebViewPlatform.instance is AndroidWebViewPlatform) {
        final AndroidWebViewController androidController = _controller.platform as AndroidWebViewController;
        await androidController.setSettings(AndroidSettings(acceptCookie: true));
      }
      if (WebViewPlatform.instance is WebKitWebViewPlatform) {
        final WebKitWebViewController webKitController = _controller.platform as WebKitWebViewController;
        await webKitController.setPreferences(WebKitPreferences(thirdPartyCookiesEnabled: true));
      }
    }
  }

  @override
  Widget build(BuildContext context) {
    return WebViewWidget(controller: _controller);
  }
}

3. How to "Hide" Cookies in WebView Flutter

"Hiding" cookies typically means restricting tracking-focused cookies to avoid Apple’s rejection triggers. Here are actionable methods:

  • Block Third-Party Cookies: On iOS, disable thirdPartyCookiesEnabled in WKWebView preferences. On Android 11+, use acceptThirdPartyCookies to block cross-domain cookies.
  • Auto-Clear Cookies: Delete cookies when the WebView is disposed or when ATT is denied, using _cookieManager.deleteCookiesForDomain() to target specific domains instead of all.
  • Request Interception: Use NavigationDelegate.onNavigationRequest to strip Cookie headers from outgoing requests if the user hasn’t authorized tracking.
  • Restrict Cookie Scope: Manually set cookies only for your first-party domain using CookieManager.setCookie() with strict domain and path parameters.

4. Additional Compliance Tips

  • Update Info.plist: Add the mandatory NSUserTrackingUsageDescription to explain why you need tracking authorization:
    <key>NSUserTrackingUsageDescription</key>
    <string>We use tracking to personalize your in-app web experience and improve our services.</string>
    
  • Test Edge Cases: Verify that the ATT prompt appears before any cookies are stored, and that denied authorization fully blocks cookie persistence.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 17:02:44