poingstudios / godot-admob-android

Godot's AdMob Plugin for Android with support for Mediations.
https://poingstudios.github.io/godot-admob-plugin/
MIT License
352 stars 37 forks source link

Fatal Exception on Banner.getWidth #230

Closed catabriga closed 4 weeks ago

catabriga commented 3 months ago

Godot version

4.2.2

Plugin version

v3.1.1

Phone information

Motorola One Vision Android 11

Issue description

Sometimes the app crashes due to a fatal exception in the admob addon. The issue appears to happen when the width of the banner is requested but the ad size has not been initialized yet. This happens because the mAdSize variable is labeled as lateinit, but it is possible for godot to try to access it before it is initialized.

Here is a stacktrace of a crash:

06-19 17:22:29.582 24073 24112 D poing-godot-admob: Godot-PoingStudios-3.1.1
06-19 17:22:29.642 24073 24073 D poing-godot-admob: Safe Area of screen: Rect(158, 0 - 0, 0).
06-19 17:22:29.649 24073 24073 D DynamitePackage: Instantiating com.google.android.gms.ads.ChimeraAdManagerCreatorImpl
06-19 17:22:29.651 24073 24073 I Ads     : Use RequestConfiguration.Builder().setTestDeviceIds(Arrays.asList("136BBDB30B9C9186BD5931B2A7BF5AF6")) to get test ads on this device.
06-19 17:22:29.662 24073 24073 D poing-godot-admob: OnLayoutChanged
06-19 17:22:29.690 24073 24302 W ConnectionStatusConfig: Dynamic lookup for intent failed for action: com.google.android.gms.ads.service.START
06-19 17:22:30.600 24073 24112 I godot   : destroy_ad_view
06-19 17:22:31.609 24073 24073 I DynamiteModule: Considering local module com.google.android.gms.ads.dynamite:0 and remote module com.google.android.gms.ads.dynamite:241199801
06-19 17:22:31.609 24073 24073 I DynamiteModule: Selected remote version of com.google.android.gms.ads.dynamite, version >= 241199801
06-19 17:22:31.617 24073 24112 I godot   : create_ad_view
06-19 17:22:31.617 24073 24112 I godot   : register_ad_listener
06-19 17:22:31.617 24073 24112 I godot   : ad_view not null
06-19 17:22:31.618 24073 24112 D poing-godot-admob: Godot-PoingStudios-3.1.1
06-19 17:22:31.626 24073 24073 D poing-godot-admob: Safe Area of screen: Rect(158, 0 - 0, 0).
06-19 17:22:31.644 24073 24112 I godot   : _on_ad_loaded
06-19 17:22:31.677 24073 24112 I godot   : 0 0
06-19 17:22:31.677 24073 24112 I godot   : 0 0
06-19 17:22:31.741 24073 24112 W libEGL  : EGLNativeWindowType 0x7548f01f90 disconnect failed
06-19 17:22:31.790 24073 24073 D poing-godot-admob: Safe Area of screen: Rect(158, 0 - 0, 0).
06-19 17:22:31.796 24073 24073 D DynamitePackage: Instantiating com.google.android.gms.ads.ChimeraAdManagerCreatorImpl
06-19 17:22:31.798 24073 24073 I Ads     : Use RequestConfiguration.Builder().setTestDeviceIds(Arrays.asList("136BBDB30B9C9186BD5931B2A7BF5AF6")) to get test ads on this device.
06-19 17:22:31.800 24073 24112 E AndroidRuntime: FATAL EXCEPTION: GLThread 1421
06-19 17:22:31.800 24073 24112 E AndroidRuntime: Process: org.godotengine.graphwar, PID: 24073
06-19 17:22:31.800 24073 24112 E AndroidRuntime: kotlin.UninitializedPropertyAccessException: lateinit property mAdSize has not been initialized
06-19 17:22:31.800 24073 24112 E AndroidRuntime:    at com.poingstudios.godot.admob.ads.adformats.Banner.getWidth(Banner.kt:239)
06-19 17:22:31.800 24073 24112 E AndroidRuntime:    at com.poingstudios.godot.admob.ads.PoingGodotAdMobAdView.get_width(PoingGodotAdMobAdView.kt:98)
06-19 17:22:31.800 24073 24112 E AndroidRuntime:    at org.godotengine.godot.GodotLib.step(Native Method)
06-19 17:22:31.800 24073 24112 E AndroidRuntime:    at org.godotengine.godot.gl.GodotRenderer.onDrawFrame(GodotRenderer.java:57)
06-19 17:22:31.800 24073 24112 E AndroidRuntime:    at org.godotengine.godot.gl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1576)
06-19 17:22:31.800 24073 24112 E AndroidRuntime:    at org.godotengine.godot.gl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1278)
06-19 17:22:31.804 24073 24073 D poing-godot-admob: OnLayoutChanged
06-19 17:22:31.834 24073 25517 W Ads     : Not retrying to fetch app settings
06-19 17:22:31.838 24073 24314 W ConnectionStatusConfig: Dynamic lookup for intent failed for action: com.google.android.gms.ads.service.START
06-19 17:22:32.052 24073 24112 I Process : Sending signal. PID: 24073 SIG: 9
06-19 17:22:32.384  4225  4225 I Zygote  : Process 24073 exited due to signal 9 (Killed)

Steps to reproduce

The crash does not happen very frequently. To reproduce it reliably I made my app automatically change between two screens such as that one of the screens shows a banner and the other does not. This causes the banner to repeatedly load and unload, which triggers the crash after some minutes.

Additional context

No response

gumaciel commented 3 months ago

Hi, are you trying to set an ad size manually?

catabriga commented 3 months ago

I'm not changing the ad size manually.

Here are the only scripts that interact with the addon in my code:

extends Control

var ad_view : AdView

signal ad_loaded

func _ready():
    #The initializate needs to be done only once, ideally at app launch.
    MobileAds.initialize()
    create_ad_view()

func create_ad_view() -> void:
    print("create_ad_view")
    var ad_switch = get_node("GameAdSwitch")

    if ad_switch.are_ads_enabled():
        if ad_view:
            destroy_ad_view()

        var unit_id = ad_switch.get_ad_unit_id()                
        ad_view = AdView.new(unit_id, AdSize.FULL_BANNER, AdPosition.Values.BOTTOM)

        register_ad_listener()

        var ad_request := AdRequest.new()
        ad_view.load_ad(ad_request)

func destroy_ad_view() -> void:
    print("destroy_ad_view")
    if ad_view:
        #always call this method on all AdFormats to free memory on Android/iOS
        ad_view.destroy()
        ad_view = null

func register_ad_listener() -> void:
    print("register_ad_listener")
    if ad_view != null:
        print("ad_view not null")
        var ad_listener := AdListener.new()

        ad_listener.on_ad_failed_to_load = func(load_ad_error : LoadAdError) -> void:
            print("_on_ad_failed_to_load: " + load_ad_error.message)
        ad_listener.on_ad_clicked = func() -> void:
            print("_on_ad_clicked")
        ad_listener.on_ad_closed = func() -> void:
            print("_on_ad_closed")
        ad_listener.on_ad_impression = func() -> void:
            print("_on_ad_impression")
        ad_listener.on_ad_loaded = func() -> void:
            print("_on_ad_loaded")
            print(ad_view.get_width(), ' ', ad_view.get_height())
            print(ad_view.get_width_in_pixels(), ' ', ad_view.get_height_in_pixels())           
            ad_loaded.emit()
        ad_listener.on_ad_opened = func() -> void:
            print("_on_ad_opened")

        ad_view.ad_listener = ad_listener

And also this one:

extends MarginContainer

# Called when the node enters the scene tree for the first time.
func _ready():
    visibility_changed.connect(_update_size)

    var ad_holder = get_node("/root/GameRootNode/Ad_holder")
    ad_holder.ad_loaded.connect(_update_size)

func _on_visibility_changed():
    #print("_on_visibility_changed")
    _update_size.call_deferred()

func _update_size():
    #print("_update_size")
    #var ad_holder = get_tree().get_root().find_child("Ad_holder")
    var ad_holder = get_node("/root/GameRootNode/Ad_holder")
    if ad_holder.ad_view:   
        self.custom_minimum_size.x = ad_holder.ad_view.get_width_in_pixels()
        self.custom_minimum_size.y = ad_holder.ad_view.get_height_in_pixels()
    else:
        self.custom_minimum_size.x = 0
        self.custom_minimum_size.y = 0
catabriga commented 2 months ago

I have created a PR that solves this issue: https://github.com/poingstudios/godot-admob-android/pull/233

gumaciel commented 2 months ago

Thank you I will review

gumaciel commented 4 weeks ago

@catabriga merged, will be on v3.0.5 soon, thank you very much!