luis901101 / oauth_webauth

BSD 3-Clause "New" or "Revised" License
15 stars 17 forks source link

Webview crash on click #13

Closed leakb closed 1 year ago

leakb commented 1 year ago

Hi,

I got a curious behavior when I try to use this library.

Whenever i click on anything inside the webview (link, text field, radio button) the webview seems to crash and restart. In the terminal I can see following output for iOS / Android:

iOS

[+3279 ms] flutter: #0      MethodChannel._invokeMethod (package:flutter/src/services/platform_channel.dart:313:7)
            <asynchronous suspension>
            #1      InAppWebViewController.getCertificate (package:flutter_inappwebview/src/in_app_webview/in_app_webview_controller.dart:2133:10)
            <asynchronous suspension>
            #2      BaseWebViewState.initWebView.<anonymous closure> (package:oauth_webauth/src/base_web_view.dart:152:18)
            <asynchronous suspension>
[        ] flutter: MissingPluginException(No implementation found for method getCertificate on channel com.pichillilorenzo/flutter_inappwebview_43)

Android

[+7561 ms] I/AssistStructure(17974): Flattened final assist data: 264 bytes, containing 1 windows, 2 views
[ +473 ms] I/PlatformViewsController(17974): Using hybrid composition for platform view: 23
[   +1 ms] I/flutter (17974): #0      State.setState.<anonymous closure> (package:flutter/src/widgets/framework.dart:1097:9)
[        ] I/flutter (17974): #1      State.setState (package:flutter/src/widgets/framework.dart:1132:6)
[        ] I/flutter (17974): #2      _PlatformViewLinkState._onPlatformViewCreated (package:flutter/src/widgets/platform_view.dart:930:5)
[        ] I/flutter (17974): #3      AndroidViewController.create (package:flutter/src/services/platform_views.dart:805:15)
[        ] I/flutter (17974): <asynchronous suspension>
[        ] I/flutter (17974): setState() called after dispose(): _PlatformViewLinkState#4111c(lifecycle state: defunct, not mounted)
[        ] I/flutter (17974): This error happens if you call setState() on a State object for a widget that no longer appears in the widget tree (e.g., whose parent widget no longer includes the widget in its build). This error can occur when code calls setState() from a timer or an animation callback.
[        ] I/flutter (17974): The preferred solution is to cancel the timer or stop listening to the animation in the dispose() callback. Another solution is to check the "mounted" property of this object before calling setState() to ensure the object is still in the tree.
[        ] I/flutter (17974): This error might indicate a memory leak if setState() is being called because another object is retaining a reference to this State object after it has been removed from the tree. To avoid memory leaks, consider breaking the reference to this object during dispose().
[  +22 ms] E/Surface (17974): getSlotFromBufferLocked: unknown buffer: 0xb40000738de3d4e0
[        ] D/EGL_emulation(17974): eglCreateContext: 0xb40000739de6c9e0: maj 3 min 0 rcv 3

My assumtion being, this is merely a symptom of the crash, not the cause.

Setup: iOS 16.2 Android API 30

pubspec.yaml

environment:
  sdk: ">=2.19.6 <3.0.0"
dependencies:
  [...]
  flutter_inappwebview: ^5.7.2+3
  oauth_webauth: ^4.0.0+14
  oauth2: ^2.0.0

Code: Within a TraceableStatefulWidget

final authentication _authentication = getIt<Authentication>();
[...]
Widget _buildLogin() {
  return Column(
    children: [
      CupertinoButton(
      onPressed: () async {
        await _authentication.handleLogin();
      },
      child: Text(
        AppLocalizations.of(context)!.login,
        style: GenericStyle.button,
      ),
    );
    ],
  );
}

Within the Authentication class

@action
Future<bool> login(BuildContext context) async {
  var config = OAuthConfiguration(
    authorizationEndpointUrl: https://www.example.com/auth,
    tokenEndpointUrl: https://www.example.com/token,
    redirectUrl: https://www.someOtherDomain.com/oauth2redirect,
    clientId: 1234,
    scopes: [scope1, scope2, scope3],
    onCertificateValidate: (certificate) {
      return true;
    });
  final result = await OAuthWebScreen.start(
        context: context,
        configuration: config);
      if (result != null) {
        // check some stuff
        return true;
      }
  return false;
}

This also sounds really similar to another issue from last year: #7 . Did that ever get resolved? Any help would be appreciated.

luis901101 commented 1 year ago

Hi. Regarding the logs you shared:

iOS: It seems an issue with getCertificate() function on flutter_inappwebview plugin, I'm not sure if you are setting a custom certificate validator, anyways the getCertificate() function should not throw MissingPluginException, I just tested it with latest version and it just work... I have no idea if some dependency conflict could cause such exception. For this I can only recommend to check the flutter_inappwebview docs about certificate handling.

Android: about setState() called after dispose(), you can check the only Widget in which oauth_webauth uses setState() is in base_web_view.dart in which I override the function to make sure setState to be called only if widget is already mounted, so no way to be called after dispose. And about hybrid composition, this is set to true by default, you could test it with false in the sample code to see if it fixes something.

I wish I could be of more help, but I haven't been able to reproduce such issues, yes the Android issue seems similar to #7 and I tested a lot there but I couldn't reproduce the issue. I use this plugin in 2 big projects with a lot of dependencies and I have been using it since first release almost 2 years ago. I have used it to authenticate with Keycloak using OAuth 2 Authorization code grant.

My recommendation which is the same I did for the other issue: Test the sample project in the plugin sources, use the sample project pointing to your OAuth identity provider server, there you will be able to debug and check where is failing. If it works as expected then add the rest of the dependencies you use in your project to check if something is conflicting with it.

leakb commented 1 year ago

Hi,

did as you recommended: Used the sample project and plugged in my OID provider server credentials/config -> everything works as expected Added all the dependencies i use in my App and added them to the sample project -> everything is working perfectly Added parts of the login widget from my app to the sample project -> still everything works

I had no luck identifying what causes the problem. It is some weird interaction between the rest of my app code and the webview. I'll take a break from this particular problem and revisit it when i have upgraded to Flutter >= 3.10.

luis901101 commented 1 year ago

Thanks @leakb for reporting it.