Skip to content

Commit 4e5885f

Browse files
Nicholas Ventimigliacopybara-github
authored andcommitted
Added Jetpack Compose Native Compose Sample.
PiperOrigin-RevId: 683790668
1 parent 66c9aa6 commit 4e5885f

13 files changed

Lines changed: 620 additions & 6 deletions

File tree

kotlin/advanced/JetpackComposeDemo/app/build.gradle.kts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ dependencies {
3636
implementation("androidx.core:core-ktx:1.13.1")
3737
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.8.4")
3838
implementation(platform("androidx.compose:compose-bom:2024.06.00"))
39-
implementation("androidx.compose.ui:ui")
40-
implementation("androidx.compose.ui:ui-graphics")
39+
implementation("androidx.compose.ui:ui:1.7.3")
40+
implementation("androidx.compose.ui:ui-graphics:1.7.3")
4141
implementation("androidx.compose.material3:material3")
4242
implementation("androidx.compose.foundation:foundation")
4343
implementation("androidx.navigation:navigation-compose:2.7.7")

kotlin/advanced/JetpackComposeDemo/app/src/main/AndroidManifest.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
<meta-data
1717
android:name="com.google.android.gms.ads.APPLICATION_ID"
1818
android:value="ca-app-pub-3940256099942544~3347511713" />
19+
<meta-data android:name="com.google.android.gms.ads.flag.NATIVE_AD_DEBUGGER_ENABLED"
20+
android:value="true" />
1921
<meta-data
2022
android:name="com.google.android.gms.ads.flag.OPTIMIZE_AD_LOADING"
2123
android:value="true" />
@@ -29,6 +31,11 @@
2931
<category android:name="android.intent.category.LAUNCHER" />
3032
</intent-filter>
3133
</activity>
34+
<activity
35+
android:name="com.google.android.gms.example.jetpackcomposedemo.NativeComposeActivity"
36+
android:exported="true"
37+
android:theme="@style/Theme.JetpackComposeDemo">
38+
</activity>
3239
</application>
3340

3441
</manifest>

kotlin/advanced/JetpackComposeDemo/app/src/main/java/com/google/android/gms/example/jetpackcomposedemo/GoogleMobileAdsApplication.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,6 @@ class GoogleMobileAdsApplication : Application() {
2323
const val TAG = "GoogleMobileAdsSample"
2424

2525
const val BANNER_AD_UNIT_ID = "ca-app-pub-3940256099942544/9214589741"
26+
const val NATIVE_AD_UNIT_ID = "ca-app-pub-3940256099942544/1044960115"
2627
}
2728
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
/*
2+
* Copyright 2024 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.android.gms.example.jetpackcomposedemo.formats
18+
19+
import android.util.Log
20+
import androidx.compose.foundation.Image
21+
import androidx.compose.foundation.background
22+
import androidx.compose.foundation.layout.Box
23+
import androidx.compose.foundation.layout.Column
24+
import androidx.compose.foundation.layout.Row
25+
import androidx.compose.foundation.layout.fillMaxHeight
26+
import androidx.compose.foundation.layout.fillMaxWidth
27+
import androidx.compose.foundation.layout.height
28+
import androidx.compose.foundation.layout.padding
29+
import androidx.compose.foundation.layout.wrapContentHeight
30+
import androidx.compose.material3.ButtonDefaults
31+
import androidx.compose.material3.MaterialTheme
32+
import androidx.compose.material3.Surface
33+
import androidx.compose.material3.Text
34+
import androidx.compose.runtime.Composable
35+
import androidx.compose.runtime.getValue
36+
import androidx.compose.runtime.mutableStateOf
37+
import androidx.compose.runtime.remember
38+
import androidx.compose.runtime.setValue
39+
import androidx.compose.ui.Alignment
40+
import androidx.compose.ui.Modifier
41+
import androidx.compose.ui.draw.clip
42+
import androidx.compose.ui.graphics.asImageBitmap
43+
import androidx.compose.ui.platform.LocalContext
44+
import androidx.compose.ui.tooling.preview.Preview
45+
import androidx.compose.ui.unit.dp
46+
import androidx.core.graphics.drawable.toBitmap
47+
import com.example.jetpackcomposedemo.R
48+
import com.google.android.gms.ads.AdRequest
49+
import com.google.android.gms.ads.LoadAdError
50+
import com.google.android.gms.ads.nativead.NativeAd
51+
import com.google.android.gms.compose_util.NativeAdBodyView
52+
import com.google.android.gms.compose_util.NativeAdCallToActionView
53+
import com.google.android.gms.compose_util.NativeAdHeadlineView
54+
import com.google.android.gms.compose_util.NativeAdIconView
55+
import com.google.android.gms.compose_util.NativeAdMediaView
56+
import com.google.android.gms.compose_util.NativeAdPriceView
57+
import com.google.android.gms.compose_util.NativeAdStarRatingView
58+
import com.google.android.gms.compose_util.NativeAdState
59+
import com.google.android.gms.compose_util.NativeAdStoreView
60+
import com.google.android.gms.compose_util.NativeAdView
61+
import com.google.android.gms.example.jetpackcomposedemo.GoogleMobileAdsApplication.Companion.NATIVE_AD_UNIT_ID
62+
import com.google.android.gms.example.jetpackcomposedemo.GoogleMobileAdsApplication.Companion.TAG
63+
import com.google.android.gms.example.jetpackcomposedemo.ui.theme.JetpackComposeDemoTheme
64+
65+
@Composable
66+
fun NativeScreen() {
67+
68+
// Construct a native state to configure the NativeComposable.
69+
val nativeAdState = {
70+
NativeAdState(
71+
adUnitId = NATIVE_AD_UNIT_ID,
72+
adRequest = AdRequest.Builder().build(),
73+
onAdLoaded = { Log.i(TAG, "Native ad is loaded.") },
74+
onAdFailedToLoad = { error: LoadAdError ->
75+
Log.e(TAG, "Native ad failed to load with error: ${error.message}")
76+
},
77+
onAdImpression = { Log.i(TAG, "Native ad recorded an impression.") },
78+
onAdClicked = { Log.i(TAG, "Native ad was clicked.") },
79+
onAdOpened = { Log.i(TAG, "Native ad was opened.") },
80+
onAdClosed = { Log.i(TAG, "Native ad was closed.") },
81+
)
82+
}
83+
84+
// Native ad composable.
85+
SampleNativeTemplate(nativeAdState)
86+
}
87+
88+
@Composable
89+
fun SampleNativeTemplate(nativeAdState: NativeAdState) {
90+
91+
// Cache the mutable state.
92+
var nativeAd by remember { mutableStateOf<NativeAd?>(null) }
93+
94+
Box(modifier = Modifier.padding(8.dp).wrapContentHeight(Alignment.Top)) {
95+
NativeAdView(nativeAdState, nativeAdResult = { nativeAd = it }) {
96+
Column(Modifier.align(Alignment.TopStart).wrapContentHeight(Alignment.Top)) {
97+
AdAttribution()
98+
99+
Row {
100+
nativeAd?.icon?.let { icon ->
101+
NativeAdIconView(Modifier.padding(5.dp)) {
102+
icon.drawable?.toBitmap()?.let { bitmap ->
103+
Image(bitmap = bitmap.asImageBitmap(), "Icon")
104+
}
105+
}
106+
}
107+
Column {
108+
nativeAd?.headline?.let {
109+
NativeAdHeadlineView {
110+
Text(text = it, style = MaterialTheme.typography.headlineLarge)
111+
}
112+
}
113+
114+
nativeAd?.starRating?.let {
115+
NativeAdStarRatingView {
116+
Text(text = "Rated $it", style = MaterialTheme.typography.labelMedium)
117+
}
118+
}
119+
}
120+
}
121+
122+
nativeAd?.body?.let { NativeAdBodyView { Text(text = it) } }
123+
124+
NativeAdMediaView(Modifier.fillMaxWidth().height(500.dp).fillMaxHeight())
125+
126+
Row(Modifier.align(Alignment.End).padding(5.dp)) {
127+
nativeAd?.price?.let {
128+
NativeAdPriceView(Modifier.padding(5.dp).align(Alignment.CenterVertically)) {
129+
Text(text = it)
130+
}
131+
}
132+
nativeAd?.store?.let {
133+
NativeAdStoreView(Modifier.padding(5.dp).align(Alignment.CenterVertically)) {
134+
Text(text = it)
135+
}
136+
}
137+
nativeAd?.callToAction?.let {
138+
NativeAdCallToActionView(Modifier.padding(5.dp)) {
139+
// Do not use a compose button because it overrides the native ad asset click handler
140+
// and prevents the ad from being clicked.
141+
FakeButton(it)
142+
}
143+
}
144+
}
145+
}
146+
}
147+
}
148+
}
149+
150+
@Composable
151+
fun AdAttribution() {
152+
val context = LocalContext.current
153+
Box(
154+
modifier =
155+
Modifier.background(ButtonDefaults.buttonColors().containerColor).clip(ButtonDefaults.shape)
156+
) {
157+
Text(
158+
color = ButtonDefaults.buttonColors().contentColor,
159+
text = context.getString(R.string.attribution),
160+
)
161+
}
162+
}
163+
164+
/**
165+
* A composition which looks like a button but without a click handler. This is used because a
166+
* compose button overrides the native ad asset click handler and prevents the ad from being
167+
* clicked.
168+
*/
169+
@Composable
170+
fun FakeButton(text: String) {
171+
Box(
172+
modifier =
173+
Modifier.background(ButtonDefaults.buttonColors().containerColor)
174+
.clip(ButtonDefaults.shape)
175+
.padding(ButtonDefaults.ContentPadding)
176+
) {
177+
Text(color = ButtonDefaults.buttonColors().contentColor, text = text)
178+
}
179+
}
180+
181+
@Preview
182+
@Composable
183+
fun NativeLayoutScreenPreview() {
184+
JetpackComposeDemoTheme {
185+
Surface(color = MaterialTheme.colorScheme.background) { NativeScreen() }
186+
}
187+
}

kotlin/advanced/JetpackComposeDemo/app/src/main/java/com/google/android/gms/example/jetpackcomposedemo/main/HomeScreen.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,13 @@ fun HomeScreen(
3636
) {
3737
Text(LocalContext.current.getString(R.string.nav_lazy_banner))
3838
}
39+
Button(
40+
onClick = { navController.navigate(NavDestinations.Native.name) },
41+
enabled = uiState.canRequestAds,
42+
modifier = Modifier.fillMaxWidth(),
43+
) {
44+
Text(LocalContext.current.getString(R.string.nav_native))
45+
}
3946
}
4047
}
4148

kotlin/advanced/JetpackComposeDemo/app/src/main/java/com/google/android/gms/example/jetpackcomposedemo/main/MainScreen.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ import androidx.navigation.compose.rememberNavController
4141
import com.example.jetpackcomposedemo.R
4242
import com.google.android.gms.example.jetpackcomposedemo.formats.BannerScreen
4343
import com.google.android.gms.example.jetpackcomposedemo.formats.LazyBannerScreen
44+
import com.google.android.gms.example.jetpackcomposedemo.formats.NativeScreen
4445
import com.google.android.gms.example.jetpackcomposedemo.ui.theme.JetpackComposeDemoTheme
4546

4647
@Composable
@@ -81,6 +82,7 @@ fun MainScreen(googleMobileAdsViewModel: MainViewModel, modifier: Modifier = Mod
8182
composable(NavDestinations.Home.name) { HomeScreen(uiState, navController) }
8283
composable(NavDestinations.Banner.name) { BannerScreen() }
8384
composable(NavDestinations.LazyBanner.name) { LazyBannerScreen() }
85+
composable(NavDestinations.Native.name) { NativeScreen() }
8486
}
8587
Spacer(Modifier.windowInsetsBottomHeight(WindowInsets.systemBars))
8688
}

kotlin/advanced/JetpackComposeDemo/app/src/main/java/com/google/android/gms/example/jetpackcomposedemo/main/NavDestinations.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ enum class NavDestinations {
44
Home,
55
Banner,
66
LazyBanner,
7+
Native,
78
}

kotlin/advanced/JetpackComposeDemo/app/src/main/res/values/strings.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
<resources>
2+
<string name="attribution">Ad</string>
23
<string name="app_name">Google Mobile Ads Jetpack Compose Demo</string>
34
<string name="adinspector_open_button">Ad Inspector</string>
45
<string name="main_title">Jetpack Compose Demo</string>
56
<string name="nav_home">Home</string>
67
<string name="nav_banner">Banner</string>
78
<string name="nav_lazy_banner">Lazy Banner</string>
9+
<string name="nav_native">Native</string>
810
<string name="privacy_options_open_button">Show Privacy Options Form</string>
911
<string name="text_reload">Reload Ad</string>
1012
<string-array name="lazy_banner_filler_content">

kotlin/advanced/JetpackComposeDemo/compose-util/build.gradle.kts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ dependencies {
2727
implementation("androidx.core:core-ktx:1.13.1")
2828
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.8.4")
2929
implementation(platform("androidx.compose:compose-bom:2024.06.00"))
30-
implementation("androidx.compose.ui:ui")
31-
implementation("androidx.compose.ui:ui-graphics")
30+
implementation("androidx.compose.ui:ui:1.7.3")
31+
implementation("androidx.compose.ui:ui-graphics:1.7.3")
3232
implementation("androidx.compose.material3:material3")
3333
implementation("androidx.compose.foundation:foundation")
3434
implementation("com.google.android.gms:play-services-ads:23.4.0")
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
33

4+
<uses-permission android:name="android.permission.INTERNET" />
45
</manifest>

0 commit comments

Comments
 (0)