Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reference to old GoogleMobileAdsViewFactory after flutter activity is recreated [Android] #265

Closed
rckrdstrgrd opened this issue Jun 4, 2021 · 6 comments
Assignees
Labels
bug Something isn't working

Comments

@rckrdstrgrd
Copy link

rckrdstrgrd commented Jun 4, 2021

Plugin Version

0.13.0

Steps to Reproduce

When testing the plugin in a flutter add-to-app Android project, using a cached FlutterEngine. The ads stops working after the flutter activity is closed and then reopened, i.e the flutter activity is destroyed and recreated. The ads are blank or display an error view. If there isn't something wrong in my project setup I think this is caused by an old/wrong reference to GoogleMobileAdsViewFactory after the activity is recreated.

When the activity is recreated GoogleMobileAdsPlugin.onAttachedToActivity is called and then initializePlugin. initializePlugin will create a new view factory and attempt to register it, but the registration of the new view factory will fail since the PlatformViewRegistry do not allow updates. This results in an outdated/mismatched reference for the AdInstanceManager between GoogleMobileAdsViewFactory and GoogleMobileAdsPlugin.

Does the plugin support the flutter activity to be recreated?

Flutter (Channel stable, 2.2.1, on macOS 11.3.1 20E241 darwin-x64, locale en-SE) • Flutter version 2.2.1 at /Users/rickard/Dev/flutter/sdk • Framework revision 02c026b03c (8 days ago), 2021-05-27 12:24:44 -0700 • Engine revision 0fdb562ac8 • Dart version 2.13.1

Android toolchain - develop for Android devices (Android SDK version 30.0.3)
• Android SDK at /Users/rickard/Dev/Android/sdk
• Platform android-30, build-tools 30.0.3
• ANDROID_HOME = /Users/rickard/Dev/Android/sdk
• Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java
• Java version OpenJDK Runtime Environment (build 11.0.8+10-b944.6916264)

@jjliu15 jjliu15 added the bug Something isn't working label Jun 7, 2021
@rckrdstrgrd
Copy link
Author

Any updates on this? Does the plugin support a cached flutter engine? I can not get it to load ads when starting the flutter engine when the application starts. Below are some errors from the log:

2021-07-07 15:20:44.605 29584-29685/com.example.myapplication E/flutter: [ERROR:flutter/lib/ui/ui_dart_state.cc(199)] Unhandled Exception: MissingPluginException(No implementation found for method loadBannerAd on channel plugins.flutter.io/google_mobile_ads)
    #0      MethodChannel._invokeMethod (package:flutter/src/services/platform_channel.dart:156:7)
    <asynchronous suspension>
    #1      BannerAd.load (package:google_mobile_ads/src/ad_containers.dart:541:5)
    <asynchronous suspension>
2021-07-07 15:20:44.606 29584-29685/com.example.myapplication E/flutter: [ERROR:flutter/lib/ui/ui_dart_state.cc(199)] Unhandled Exception: MissingPluginException(No implementation found for method create on channel flutter/platform_views)
    #0      MethodChannel._invokeMethod (package:flutter/src/services/platform_channel.dart:156:7)
    <asynchronous suspension>
    #1      AndroidViewController.create (package:flutter/src/services/platform_views.dart:748:5)
    <asynchronous suspension>

Here is an example project that was used to generate the above logs: https://github.com/rckrdstrgrd/googleads-mobile-flutter-issue-265

@jjliu15 jjliu15 self-assigned this Aug 11, 2021
@jjliu15
Copy link
Collaborator

jjliu15 commented Aug 17, 2021

Loading ads from a cached engine currently does not work. This happens because GoogleMobileAdsPlugin.java waits for ActivityAware.onAttachedToActivity() before registering its method channel. The dart code is executed before the activity is started, which is causing the error.

After fixing this I'm able to load and show an ad the first time we open the FlutterActivity. However I get this new error when showing the Flutter activity again after closing it:

E/flutter: [ERROR:flutter/shell/platform/android/platform_view_android_jni_impl.cc(49)] java.lang.IllegalStateException: The overlay surface (id:0) doesn't exist
        at io.flutter.plugin.platform.PlatformViewsController.onDisplayOverlaySurface(PlatformViewsController.java:796)
        at io.flutter.embedding.engine.FlutterJNI.onDisplayOverlaySurface(FlutterJNI.java:960)
        at android.os.MessageQueue.nativePollOnce(Native Method)
        at android.os.MessageQueue.next(MessageQueue.java:336)
        at android.os.Looper.loop(Looper.java:174)
        at android.app.ActivityThread.main(ActivityThread.java:7356)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
A/flutter: [FATAL:flutter/shell/platform/android/platform_view_android_jni_impl.cc(1414)] Check failed: CheckException(env). 
A/libc: Fatal signal 6 (SIGABRT), code -6 (SI_TKILL) in tid 15403 (e.myapplication), pid 15403 (e.myapplication)

@blasten @bparrishMines do you know if PlatformViews support this use case? Or if there's some API we need to call between showing the Flutter Activity again to reset the PlatformsViewsController state?

@bparrishMines
Copy link
Collaborator

bparrishMines commented Aug 24, 2021

So it looks like when an engine is detached from a FlutterActivity. FlutterActivity.release is called. This eventually leads down to PlatformViewsController.destroyOverlaySurfaces.

Despite that, the old AdViews are attached to the old Activity, so all references should/will be removed. So I think the only way Flutter could support detaching a cached engine and restarting new Activity with it, is if it recreated all the AdViews with the new Activity and their creation arguments. (e.g. PlatformViewFactory.create). Which I don't think is exactly what you are looking for, but could be a possible solution. I can create an issue to track this feature.

I think you were looking to use the old AdViews with a newly started Activity. I don't think this is possible unless there is a way to change the Context passed to a View. It is mostly a limitation of Android.

Also from: https://developer.android.com/guide/components/activities/activity-lifecycle#ondestroy

If the activity is finishing, onDestroy() is the final lifecycle callback the activity receives. If onDestroy() is called as the result > of a configuration change, the system immediately creates a new activity instance and then calls onCreate() on that new ?> instance in the new configuration.

@jjliu15
Copy link
Collaborator

jjliu15 commented Sep 17, 2021

It should be possible to at least load ads from a cached engine the first time.

Based on what @bparrishMines said, reusing the cached engine to redisplay ads is trickier. It may be possible to use MutableContextWrapper to update the context, but based on this stackoverflow post there could be unintentional bugs from switching the context. Imo it's worth at least exploring.

@blasten
Copy link

blasten commented Sep 27, 2021

There's an issue in the implementation that affects all platform views, so this is a Flutter bug.

@jjliu15
Copy link
Collaborator

jjliu15 commented Jul 13, 2022

This should be resolved by flutter/engine#28894

@jjliu15 jjliu15 closed this as completed Jul 13, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

4 participants