Skip to content

How to use Custom NativeAdTemplate in common main #120

@long06031999

Description

@long06031999

Hello,
I would like to ask how to use a custom template with NativeAd.

When I implement NativeAd, I always have to create an expect class like this:

public expect class NativeAdSmallTemplate : NativeAdTemplate

And I must implement all functions defined in your public abstract class NativeAdTemplate().

As a result, every time I create a new template, I have to re-implement many methods, which makes the process quite complex and repetitive, even though some components are reused multiple times across templates.

I have the following suggestion:

@DependsOnGoogleMobileAds
@Composable
public expect fun NativeAd(
    loadedAd: NativeAdHandler,
    nativeAdTemplate: @Composable NativeAdUiScope.(NativeAdData) -> Unit,
)
public interface NativeAdUiScope {
    public val nativeAdData: NativeAdData

    @Composable
    public fun NativeAdAdvertiser(modifier: Modifier = Modifier, content: @Composable () -> Unit = {})

    @Composable
    public fun NativeAdChoices(modifier: Modifier = Modifier)

    @Composable
    public fun NativeAdMedia(modifier: Modifier = Modifier)

    @Composable
    public fun NativeAdPrice(modifier: Modifier = Modifier, content: @Composable () -> Unit = {})

    @Composable
    public fun NativeAdStarRating(modifier: Modifier = Modifier, content: @Composable () -> Unit = {})

    @Composable
    public fun NativeAdStore(modifier: Modifier = Modifier, content: @Composable () -> Unit = {})

    @Composable
    public fun NativeAdAttribution(modifier: Modifier = Modifier, text: String = "Ad")

    @Composable
    public fun NativeAdHeadline(modifier: Modifier = Modifier, content: @Composable () -> Unit = {})

    @Composable
    public fun NativeAdIcon(modifier: Modifier = Modifier)

    @Composable
    public fun NativeAdBody(modifier: Modifier = Modifier, content: @Composable () -> Unit = {})

    @Composable
    public fun NativeAdCallToAction(modifier: Modifier = Modifier, content: @Composable () -> Unit = {})
}

in android side

public class AndroidNativeAdUiScope(
    override val nativeAdData: NativeAdData
) : NativeAdUiScope {
    @Composable
    override fun NativeAdAdvertiser(
        modifier: Modifier,
        content: @Composable (() -> Unit)
    ) {
        val nativeAdView =
            LocalNativeAdView.current ?: throw IllegalStateException("NativeAdView null")
        AndroidView(
            factory = { context ->
                ComposeView(context).apply {
                    id = View.generateViewId()
                    setContent(content)
                    nativeAdView.advertiserView = this
                }
            },
            modifier = modifier,
            update = { view -> view.setContent(content) },
        )
    }

    @Composable
    override fun NativeAdChoices(
        modifier: Modifier
    ) {
        val nativeAdView =
            LocalNativeAdView.current ?: throw IllegalStateException("NativeAdView null")
        val localContext = LocalContext.current
        AndroidView(
            factory = {
                AdChoicesView(localContext).apply {
                    minimumWidth = 15
                    minimumHeight = 15
                }
            },
            update = { view -> nativeAdView.adChoicesView = view },
            modifier = modifier,
        )
    }

    @Composable
    override fun NativeAdMedia(
        modifier: Modifier
    ) {
        val nativeAdView =
            LocalNativeAdView.current ?: throw IllegalStateException("NativeAdView null")
        val localContext = LocalContext.current
        AndroidView(
            factory = { MediaView(localContext) },
            update = { view ->
                nativeAdView.mediaView = view
            },
            modifier = modifier,
        )
    }

    @Composable
    override fun NativeAdPrice(
        modifier: Modifier,
        content: @Composable (() -> Unit)
    ) {
        val nativeAdView =
            LocalNativeAdView.current ?: throw IllegalStateException("NativeAdView null")
        val localContext = LocalContext.current
        val localComposeView =
            remember { ComposeView(localContext).apply { id = View.generateViewId() } }
        AndroidView(
            factory = {
                nativeAdView.priceView = localComposeView
                localComposeView.apply { setContent(content) }
            },
            modifier = modifier,
        )
    }

    @Composable
    override fun NativeAdStarRating(
        modifier: Modifier,
        content: @Composable (() -> Unit)
    ) {
        val nativeAdView =
            LocalNativeAdView.current ?: throw IllegalStateException("NativeAdView null")
        val localContext = LocalContext.current
        val localComposeView =
            remember { ComposeView(localContext).apply { id = View.generateViewId() } }
        AndroidView(
            factory = {
                nativeAdView.starRatingView = localComposeView
                localComposeView.apply { setContent(content) }
            },
            modifier = modifier,
        )
    }

    @Composable
    override fun NativeAdStore(
        modifier: Modifier,
        content: @Composable (() -> Unit)
    ) {
        val nativeAdView =
            LocalNativeAdView.current ?: throw IllegalStateException("NativeAdView null")
        val localContext = LocalContext.current
        val localComposeView =
            remember { ComposeView(localContext).apply { id = View.generateViewId() } }
        AndroidView(
            factory = {
                nativeAdView.storeView = localComposeView
                localComposeView.apply { setContent(content) }
            },
            modifier = modifier,
        )
    }

    @Composable
    override fun NativeAdAttribution(
        modifier: Modifier,
        text: String
    ) {
        Box(
            modifier =
                modifier
                    .background(ButtonDefaults.buttonColors().containerColor)
                    .clip(ButtonDefaults.shape)
        ) {
            Text(color = ButtonDefaults.buttonColors().contentColor, text = text)
        }
    }

    @Composable
    override fun NativeAdHeadline(modifier: Modifier, content: @Composable () -> Unit) {
        val nativeAdView =
            LocalNativeAdView.current ?: throw IllegalStateException("NativeAdView null")
        val localContext = LocalContext.current
        val localComposeView =
            remember { ComposeView(localContext).apply { id = View.generateViewId() } }
        AndroidView(
            factory = {
                nativeAdView.headlineView = localComposeView
                localComposeView.apply {
                    setContent(content)
                }
            },
            modifier = modifier,
        )
    }

    @Composable
    override fun NativeAdIcon(modifier: Modifier) {
        val nativeAdView =
            LocalNativeAdView.current ?: throw IllegalStateException("NativeAdView null")
        val localContext = LocalContext.current
        val localComposeView =
            remember { ComposeView(localContext).apply { id = View.generateViewId() } }
        AndroidView(
            factory = {
                nativeAdView.iconView = localComposeView
                localComposeView.apply {
                    setContent {
                        nativeAdData.icon?.let { icon ->
                            icon.drawable?.toBitmap()?.let { bitmap ->
                                Image(
                                    modifier = Modifier.clip(RoundedCornerShape(8.dp)),
                                    bitmap = bitmap.asImageBitmap(),
                                    contentDescription = "Icon"
                                )
                            }
                        } ?: Box(
                            modifier = Modifier
                                .width(80.dp)
                                .aspectRatio(1f)
                                .clip(RoundedCornerShape(8.dp))
                                .background(Color.White)
                        )
                    }
                }
            },
            modifier = modifier,
        )
    }

    @Composable
    override fun NativeAdBody(modifier: Modifier, content: @Composable () -> Unit) {
        val nativeAdView =
            LocalNativeAdView.current ?: throw IllegalStateException("NativeAdView null")
        val localContext = LocalContext.current
        val localComposeView =
            remember { ComposeView(localContext).apply { id = View.generateViewId() } }
        AndroidView(
            factory = {
                nativeAdView.bodyView = localComposeView
                localComposeView.apply {
                    setContent(content)
                }
            },
            modifier = modifier,
        )
    }

    @Composable
    override fun NativeAdCallToAction(modifier: Modifier, content: @Composable () -> Unit) {
        val nativeAdView =
            LocalNativeAdView.current ?: throw IllegalStateException("NativeAdView null")
        val localContext = LocalContext.current
        val localComposeView =
            remember { ComposeView(localContext).apply { id = View.generateViewId() } }
        AndroidView(
            factory = {
                nativeAdView.callToActionView = localComposeView
                localComposeView.apply {
                    setContent(content)
                }
            },
            modifier = modifier,
        )
    }
}

so my implement just re-write in common main (not in platform side)

private fun NativeAdUiScope.NativeAdSmallTemplate(nativeAd: NativeAdData){
     Column(
        modifier = Modifier
            .fillMaxWidth()
            .height(95.sdp)
            .border(
                1.sdp,
                MaterialTheme.englishPalette.outline,
                RoundedCornerShape(8.sdp)
            )
            .background(colors.last(), RoundedCornerShape(8.sdp))
            .padding(12.sdp)
    ) {
        Row {
            NativeAdIcon()
NativeAdHeadline {}
.......
}
}
}

And Use

NativeAd(
          loadedAd = nativeAdHandler,
          nativeAdTemplate = { nativeAd ->
                          NativeAdSmallTemplate(nativeAd)
          },
)

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions