Skip to content

How to use Custom NativeAdTemplate in common main #120

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)
          },
)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions