Hello everyone, I want to warn everyone who wants ...
# compose
a
Hello everyone, I want to warn everyone who wants to use NativeAdView in Compose, now there is a problem with the fact that onAdImpression only fires once on the first ad, and on the rest of the screens the ad is rendered but not taken into account. A little later, we found a workaround for ads to be counted, but later there were problems with the fact that clicks were no longer counted in admob and even cancelled. Therefore, consider this if you are given a similar task.
🙏 5
r
Hi @Alexander What was the workaround?
a
@rsktash
Copy code
private fun View.requestLayoutWithDelay(delayMillis: Long) {
    postDelayed({
        val t = parent?.parent?.parent
        if (t == null) {
            postDelayed({
                val k = parent?.parent?.parent
                if (k != null) {
                    k.requestLayout()
                } else {
                    Timber.d("NativeBanner: parent is null again")
                }
            }, delayMillis)
        } else {
            t.requestLayout()
        }
    }, delayMillis)
}
Copy code
AndroidViewBinding(
    factory = AdmobBannerBinding::inflate,
    update = {
        
        ...
        
        if (it.root.tag != true) {
            it.root.requestLayoutWithDelay(NATIVE_BANNER_REQUEST_LAYOUT_DELAY)
            it.root.tag = true
        }
    },
    modifier = modifier
        .background(Color.Black)
        .fillMaxWidth()
)
r
@Alexander Thank you! is it the working solution for now? Did admob team give a solution to your issue?
a
@rsktash This solution is currently in production.
@rsktash admob team has not yet provided a solution to the problem.
r
Hi @Alexander what about the clicks? Is it ok
a
@rsktash Hi, clicks work fine for me.
n
Hi, i got the same issue with NativeAdView. Decided to not use it this time. I want to ask about the BANNER ad? does it meet the same behavior? my implementation:
Copy code
AndroidView(
                modifier = Modifier
                    .fillMaxWidth(),
                factory = {

                    
                        AdView(context).apply {
                            setAdSize(AdSize.BANNER)
                            adUnitId = unitId

                            adListener = object : AdListener() {
                                override fun onAdImpression() {
                                    super.onAdImpression()
                                    Timber.v("Banner Ad Impressed.")
                                }

                                override fun onAdLoaded() {
                                    super.onAdLoaded()
                                  placeholder.visibility = View.GONE
                                }
                            }
                            loadAd(AdRequest.Builder().build()
                        })
                    }
                }
            )
a
@Namhn1495 AdView works better in Compose, so if the test ads work, then you have everything set up correctly.
o
Hello! I had the same issue with AdManagerAdView wrapped in Compose AndroidView. Thank you very much for the workaround! 🙏 I have a bit improved the solution. The delay was error prone there as usual.. If we call adView.rootView.requestLayout() from onAdLoaded() callback, it works.. So apparently it needs a layout after ad is loaded.
s
Thank you all for the suggestions here. @Oya Canli using
onAdLoaded()
to invoke
adView.rootView.requestLayout()
is an interesting suggestion. I am also in a similar situation, we already have a working version with
delay
logic but it seems that when the app is in the wild the solution works intermittently. Really curious to know what kind of issues did you run into when using
delay
? Can you also shed some light on your implementation of using
onAdLoaded()
? From what I understand you would only display the Ad when you have a successfully fetched an Ad, how does tying
onAdLoaded
to
requestLayout
help in this scenario? If you are fetching Ads for a list, you might already have received an
onAdLoaded
callback before the Ad item comes into view. Anything you share will be very helpful, since at the minute I am contemplating if it would be worth while to pursue the approach for my use case. Thank you again 🙂
o
Hi @Sudhanshu Siddh, sorry I missed your message. I actually don't know why we need to call requestLayout, I got the idea from Oleksandr's solution above. Source code is obfuscated so I don't know what is going on under the hood. (Maybe he would know more about it?) Delay was sometimes working, sometimes not.. I wrote logs everywhere and compared with recyclerview implementation and guessed that that "delay" is actually waiting for onAdLoaded() . And indeed, it works without exception now. I shared the snippets on SO if you want: https://stackoverflow.com/questions/76100292/ad-impressions-are-not-count-when-admanageradview-is-used-with-jetpack-compose
c
Hi @Alexander What is the value for NATIVE_BANNER_REQUEST_LAYOUT_DELAY?
Hi @Alexander @Oya Canli Do we have other solutions to address the issue now?
o
I haven't tried another solution since. I haven't used delays. Requesting layout in onAdLoaded worked fine for me. Ad team confirmed that bug is fixed and impressions are called each time.
a
@Cấn Văn Nghị
Copy code
private const val NATIVE_BANNER_REQUEST_LAYOUT_DELAY = 1500L
@Oya Canli I left a question on the ad team forum, but they didn’t write to me that they fixed it, from which version did they fix it?
o
No no, I am misinderstood, sorry. I was talking about ad team of our company :) So the workaround worked, that was what I meant. No, the bug is not fixed yet by Google afaik.
c
Hi @Alexander just want to know, does the workaround still work well on your product?
a
@Cấn Văn Nghị Yes it works.
d
@Alexander Hey, Can you please check if I am doing this right? I am getting ad impressions in the debug build but not in the release build
AndroidView(
modifier = Modifier.
_fillMaxSize_(),
factory =
*{* context *->*
LayoutInflater.from(context)
.inflate(R.layout.
_nativead_layout_, null, false) as NativeAdView
*}*, update = *{* view *->*
val advertiser = view.findViewById<TextView>(R.id._tv_ad_advertiser_)
val title = view.findViewById<TextView>(R.id.
_tv_ad_headline_)
val description = view.findViewById<TextView>(R.id.
_tv_ad_body_)
val icon = view.findViewById<ImageView>(R.id.
_iv_ad_app_icon_)
val ctaButton = view.findViewById<Button>(R.id.
_btn_ad_call_to_action_)
val fullImage = view.findViewById<ImageView>(R.id.
_iv_full_image_)
val mediaView = view.findViewById<MediaView>(R.id.
_ad_media_view_google_)
view.
_mediaView_ = mediaView
chosenAd.value?.
_let_ *{*
_setNativeAdCustom_(
*it*,
view, advertiser, title, description, icon, view.
_context_,
ctaButton, fullImage ) view.setNativeAd(
*it*)
view.
_requestLayoutWithDelay_(400)
}
}
)
Copy code
private fun View.requestLayoutWithDelay(delayMillis: Long) {
    post {
        val t = parent.findAndroidComposeViewParent()
        if (t == null) {
            println("Calling in if for requesting layout")
            postDelayed(delayMillis) {
                val k = parent.findAndroidComposeViewParent()
                if (k != null) {
                    k.requestLayout()
                } else {
                    Log.i("TAG", "This should never happen")
                }
            }
        } else {
            println("Calling in else for requesting layout")
            t.requestLayout()
        }
    }
}

private fun ViewParent?.findAndroidComposeViewParent(): ViewParent? = when {
    this != null && this::class.java.simpleName == "AndroidComposeView" -> this
    this != null -> this.parent.findAndroidComposeViewParent() ?: this
    else -> null
}
Thanks
postDelayed(delayMillis) {
val k = parent.findAndroidComposeViewParent() if (k != null) { k.requestLayout() } else { Log.i("TAG", "This should never happen") } } In the release build, I checked that it goes into this else condition
c
@Doraswamy Vamsi Looks like Proguard obfuscated code. did you try adding this line?
Copy code
-keep class androidx.compose.ui.platform.AndroidComposeView
d
@Cấn Văn Nghị I tried @Alexander’s solution and the issue is solved
c
Look likes the issue was fixed on the latest compose version
👍 1
312 Views