Hey guys, I have a Compose application that shows ...
# compose
a
Hey guys, I have a Compose application that shows a list of items with Google AdManager Banner Ads using
com.google.android.gms.ads.admanager.AdManagerAdView
and AndroidView Compose Wrapper (the code is in the thread). It works great when I use test AdManager Ads. But there is an issue in production (please have a look at the screenshot provided): • Arrow 1 - the video of the Ad Banner is not displayed after the Ad Banner is bind and shown. • Arrow 2 - If I move the app to the background and then to the foreground (or if I scroll the Ad Banner off and back on screen), the video is shown. If I wait for 5 mins or more after binding and showing the Ad Banner, the video won't appear - so I think that some (screen) event/method call is missing. I found the adView.rootView.requestLayout() workaround for the other Ad Banner issue but it didn't help me. I also tried to call
invalidate()
,
postInvalidate()
and
requestFocus()
but nothing helped. Cannot understand what (screen) event is missing for the Ad Banner to show a video by default. Can you please suggest me how to fix this issue? Any ideas are appreciated!
Example code of Compose Ad Banner:
Copy code
@Composable
fun AdManagerAdBanner(
    adUnit: AdManagerUnitUiModel,
    modifier: Modifier = Modifier,
) {
    Box {
        AndroidView(
            modifier = modifier.fillMaxWidth(),
            factory = { context ->
                AdManagerAdView(context).apply {
                    setAdSizes(adUnit.adSizes)
                    adUnitId = adUnit.unitId
                    val adRequest = AdRequest.Builder().build()
                    loadAd(adRequest)
                }
            },
        )
    }
}
f
AdViews are temperamental. Did you see in the logs something like "Not enough space to show ad" ?
Are you set an AdListener ? do you have any adError ?
are mark as loaded ?
a
@FranSoto • As far as I remember, I haven't seen "Not enough space to show ad". But let me double check now. • Yes, I have AdListener and the
onAdLoaded()
success callback is invoked
f
Also reviewing your code. Is inside a lazy column ?
a
@FranSoto Yes, it's inside a LazyColumn. I have a list of items and Ad Banner can be shown between items
f
then do a change. factory can return the adView directly
👀 1
and on update load the ad
sometimes you will need to delay a little the load of the ad, with a handler or using adManagerAdView.doOnLayout { val adRequest = AdRequest.Builder().build() adManagerAdView.loadAd(request) }
Not the best approach for Compose
but these AdViews are monsters
xDDD
😅 1
a
I definitely agree with you. Have several issues just with Ads + Compose... I wonder why the Google Ads Team hasn't added the default Compose support yet? 🤷 > "Not enough space to show ad" Double checked - no such logs. I just see next error: > I ExoPlayerAdapter initialized. > E JS: Uncaught TypeError: a is not a function (https://www.gstatic.com/mysidia/65b7c9b572ca84ca7b7b2a701d74fc82.js?tag=video_2019:224)
Hm... For some reason I added adView.rootView.requestLayout() again and now it started working. I simplified my code quite a lot now - maybe
requestLayout
doesn't take effect if I have several inner callbacks. Let me carefully check my latest changes and I will update the thread with the up-to-date info. Btw, thanks a lot for your suggestions!
doOnLayout
is probably not the best idea but I quite interesting 🙂
@FranSoto So, I checked: • adView.rootView.requestLayout() helps maybe in 75% of cases but still doesn't work all the time. • doOnLayout didn't help at all. Do you maybe know what events are called when I move the app to the background and then back to the foreground? This background-foreground move 100% fixes the issue - the animated content (video) of the Ad Banner always appears. Or maybe you know how to debug the view events on background-foreground? Cannot find a way to understand what events are being called
f
interesting, I worked a lot with AdViews 4 years ago. So i am not 100% sure if something change. The AdView usually control if it being presented or not, and also control if it move to back fore to pause play the video
mmmm
you can obtain the videocontroller from an admanageradview
a
@FranSoto I tried to get a videocontroller but it says there is no video - so, the animated part of Ad Banner is not considered as a real video.
f
really ?
a
Maybe if a banner is just a video, maybe then videocontroller is not empty. But I don't have such type of banners
f
could be. I worked with native ads and you can control almost everything an only a couple of banner types.
however this is similar to an issue that i had placing adviews inside a recycler. I messed up with the pause / resume / destroy ad lifecycle. Compose's lifecycle don't match exactly view's lifecycle
a
@FranSoto Have just checked to be sure:
Copy code
videoController.hasVideoContent()
returns false in both cases: • if video is shown by default • or if it is not shown
I messed up with the pause / resume / destroy ad lifecycle.
Compose's lifecycle don't match exactly view's lifecycle
I also feel that the issue might be related to lifecycle events and
requestLayout()
helps to decrease amount of not-shown animated parts. But cannot think of a better fix for now 😞 Hope there is another API or anything else that could solve this issue completely - like as I move the app to background and then to the foreground
f
did you try to force a recomposition?
a
@FranSoto What do you mean by this? You think a recomposition can help to trigger the necessary lifecycle event?
f
not sure, but is something easy to test
a
Checked - and recomposition doesn't help.
f
when you did it? the recomposition fired the update section of the AndroidView, that now load the ad. If doens't help, is not related with when the ad is loaded. basically we are forcing another load
a
Hi @FranSoto, would be great to share a minimum reproducible example with you but, unfortunately, the issue happens only on prod. Test banner unitIds are very simple - just a test image and that's it. But if you have a production AdMob/AdManager account, I can prepare the min reproducible example and you will set your Banner unitIds. Please let me know. Speaking about the recomposition - that's how I implemented it:
Copy code
@Composable
fun AdManagerAdBanner(
    adUnit: AdManagerUnitUiModel,
    modifier: Modifier = Modifier,
) {
    val text = remember { mutableStateOf("foo") }
    val context = LocalContext.current

    val adView = remember {
        AdManagerAdView(context).apply {
            setAdSizes(adUnit.adSizes)
            adUnitId = adUnit.unitId

            adListener = object : AdListener() {

                override fun onAdLoaded() {
                    super.onAdLoaded()
                    rootView.requestLayout()
                    text.value = "bar"
                }
            }
            
            val adRequest = AdRequest.Builder().build()
            loadAd(adRequest)
        }
    }

    key(text.value) {
        AndroidView(
            modifier = modifier.fillMaxWidth(),
            factory = {
                adView.parentViewGroup?.removeView(adView)
                adView
            },
        )
    }
}
115 Views