flutter icon indicating copy to clipboard operation
flutter copied to clipboard

[webview_flutter] crash on [FWFWebView initWithFrame:configuration:binaryMessenger:instanceManager:]

Open dujj opened this issue 2 years ago • 5 comments

The characteristics of Future cannot guarantee that WKWebViewConfiguration is created before WKWebView, resulting in a crash

- (void)createWithIdentifier:(nonnull NSNumber *)identifier
     configurationIdentifier:(nonnull NSNumber *)configurationIdentifier
                       error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error {
  WKWebViewConfiguration *configuration = (WKWebViewConfiguration *)[self.instanceManager
      instanceForIdentifier:configurationIdentifier.longValue];
  FWFWebView *webView = [[FWFWebView alloc] initWithFrame:CGRectMake(0, 0, 0, 0)
                                            configuration:configuration
                                          binaryMessenger:self.binaryMessenger
                                          instanceManager:self.instanceManager];
  [self.instanceManager addDartCreatedInstance:webView withIdentifier:identifier.longValue];
}

The code above is in webview_flutter_wkwebview 2.9.5 file: FWFWebViewHostApi.m line:113~123 configuration maybe nil

class _WebKitWebViewWidgetState extends State<WebKitWebViewWidget> {
  late final WebKitWebViewPlatformController controller;

  @override
  void initState() {
    super.initState();
    controller = WebKitWebViewPlatformController(
      creationParams: widget.creationParams,
      callbacksHandler: widget.callbacksHandler,
      javascriptChannelRegistry: widget.javascriptChannelRegistry,
      configuration: widget.configuration,
      webViewProxy: widget.webViewProxy,
    );
  }

  @override
  Widget build(BuildContext context) {
    return widget.onBuildWidget(controller);
  }
}

The code above is in webview_flutter_wkwebview 2.9.5 file: web_kit_webview_widget.dart line:58~77 create WebKitWebViewPlatformController will create WKWebViewConfiguration and WKWebView

WebKitWebViewPlatformController({
    required CreationParams creationParams,
    required this.callbacksHandler,
    required this.javascriptChannelRegistry,
    WKWebViewConfiguration? configuration,
    @visibleForTesting this.webViewProxy = const WebViewWidgetProxy(),
  }) : super(callbacksHandler) {
    _setCreationParams(
      creationParams,
      configuration: configuration ?? WKWebViewConfiguration(),
    );
  }

Future<void> _setCreationParams(
    CreationParams params, {
    required WKWebViewConfiguration configuration,
  }) async {
    _setWebViewConfiguration(
      configuration,
      allowsInlineMediaPlayback: params.webSettings?.allowsInlineMediaPlayback,
      autoMediaPlaybackPolicy: params.autoMediaPlaybackPolicy,
    );

    webView = webViewProxy.createWebView(
      configuration,
      observeValue: withWeakRefenceTo(
        callbacksHandler,
        (WeakReference<WebViewPlatformCallbacksHandler> weakReference) {
          return (
            String keyPath,
            NSObject object,
            Map<NSKeyValueChangeKey, Object?> change,
          ) {
            final double progress =
                change[NSKeyValueChangeKey.newValue]! as double;
            weakReference.target?.onProgress((progress * 100).round());
          };
        },
      ),
    );

    webView.setUIDelegate(uiDelegate);

    await addJavascriptChannels(params.javascriptChannelNames);

    webView.setNavigationDelegate(navigationDelegate);

    if (params.userAgent != null) {
      webView.setCustomUserAgent(params.userAgent);
    }

    if (params.webSettings != null) {
      updateSettings(params.webSettings!);
    }

    if (params.backgroundColor != null) {
      webView.setOpaque(false);
      webView.setBackgroundColor(Colors.transparent);
      webView.scrollView.setBackgroundColor(params.backgroundColor);
    }

    if (params.initialUrl != null) {
      await loadUrl(params.initialUrl!, null);
    }
  }

The code above is in webview_flutter_wkwebview 2.9.5 file: web_kit_webview_widget.dart line:82~240 create WKWebViewConfiguration and WKWebView with Future

 Future<void> createForInstances(WKWebViewConfiguration instance) {
    return create(instanceManager.addDartCreatedInstance(instance));
  }

Future<void> createForInstances(
    WKWebView instance,
    WKWebViewConfiguration configuration,
  ) {
    return create(
      instanceManager.addDartCreatedInstance(instance),
      instanceManager.getIdentifier(configuration)!,
    );
  }

If there is a delay of 3 seconds in creating WKWebViewConfiguration, then iOS cannot get WKWebViewConfiguration when creating a webview, and a crash will inevitably occur

test code:

  Future<void> create(int arg_identifier) async {
    print('-----create WKWebViewConfigurationHostApi flutter');
     await Future.delayed(Duration(seconds: 3));

The code above is in webview_flutter_wkwebview 2.9.5 file: web_kit.pigeon.dart line:767

dujj avatar Dec 06 '22 02:12 dujj

Hi @dujj, can you provide a code sample along with steps to reproduce that don't involve editing the plugin code?

Thank you

danagbemava-nc avatar Dec 06 '22 10:12 danagbemava-nc

@bparrishMines It sounds like there may be a race in some async setup code here.

stuartmorgan avatar Dec 06 '22 13:12 stuartmorgan

@danagbemava-nc This problem is caused by crash collection in the production environment. Tried to reproduce the issue using minimal example code, but failed. This issue is random and may be related to machine performance. By analyzing the code, it is concluded that there may be a competitive relationship. Seeing the asynchronous calling method in the source code, since it is asynchronous, the fixed delay will trigger this problem at a higher level without affecting the program logic. The results have been verified, and it is indeed a competitive relationship caused by asynchrony. .

dujj avatar Dec 07 '22 01:12 dujj

Thanks for the info.

Labeling for further investigation from the team.

@dujj Please share the crash that you collected in production.

Thank you

danagbemava-nc avatar Dec 07 '22 06:12 danagbemava-nc

#0 Thread
NSInvalidArgumentException
Configuration cannot be nil

解析原始
0 CoreFoundation ___exceptionPreprocess + 164
2 CoreFoundation ___CFDictionaryCreateGeneric
3 QMUIKit __29+[NSException(QMUI_KVC) load]_block_invoke_3 + 516
4 WebKit -[WKWebView _initializeWithConfiguration:] + 88
5 WebKit -[WKWebView initWithFrame:configuration:] + 72
6 webview_flutter_wkwebview -[FWFWebView initWithFrame:configuration:binaryMessenger:instanceManager:] + 104
7 webview_flutter_wkwebview -[FWFWebViewHostApiImpl createWithIdentifier:configurationIdentifier:error:] + 216
8 webview_flutter_wkwebview __FWFWKWebViewHostApiSetup_block_invoke + 128
9 Flutter 0x0000000106e38000 + 5730632
10 Flutter 0x0000000106e38000 + 278156
11 libdispatch.dylib __dispatch_call_block_and_release + 32
20 UIKitCore _UIApplicationMain + 340

dujj avatar Dec 07 '22 09:12 dujj

This issue is assigned to @bparrishMines but has had no recent status updates. Please consider unassigning this issue if it is not going to be addressed in the near future. This allows people to have a clearer picture of what work is actually planned. Thanks!

flutter-triage-bot[bot] avatar Nov 23 '23 01:11 flutter-triage-bot[bot]

@stuartmorgan @bparrishMines Any update about this issue ?

I have this crash too webview_flutter: ^4.0.7

DanielFrTB avatar May 23 '24 09:05 DanielFrTB