Skip to content

Commit d32fc1b

Browse files
committed
added ads
1 parent 07ee778 commit d32fc1b

File tree

21 files changed

+812
-86
lines changed

21 files changed

+812
-86
lines changed

composeApp/build.gradle.kts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,9 +143,11 @@ kotlin {
143143
implementation(libs.android)
144144
implementation(libs.activity)
145145
implementation(libs.activity.compose)
146+
implementation(libs.ads)
146147
implementation(libs.appcompat)
147148
implementation(libs.multidex)
148149
implementation(libs.splashscreen)
150+
implementation(libs.ump)
149151
implementation(libs.html.converter)
150152

151153
implementation(libs.ktor.jvm)

composeApp/src/androidMain/AndroidManifest.xml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
1010
<uses-permission android:name="android.permission.INTERNET"/>
1111
<uses-permission android:name="dev.datlag.burningseries.READ_DATABASE" />
12+
<uses-permission android:name="com.google.android.gms.permission.AD_ID" />
1213

1314
<queries>
1415
<package android:name="dev.datlag.burningseries" />
@@ -251,5 +252,18 @@
251252
<meta-data
252253
android:name="open_source_license"
253254
android:value="GNU AFFERO GENERAL PUBLIC LICENSE Version 3" />
255+
256+
<meta-data
257+
android:name="com.google.android.gms.ads.APPLICATION_ID"
258+
android:value="ca-app-pub-3940256099942544~3347511713" />
259+
260+
<property
261+
android:name="android.adservices.AD_SERVICES_CONFIG"
262+
android:resource="@xml/gma_ad_services_config"
263+
tools:replace="android:resource" />
264+
265+
<meta-data
266+
android:name="com.google.android.gms.ads.DELAY_APP_MEASUREMENT_INIT"
267+
android:value="true"/>
254268
</application>
255269
</manifest>

composeApp/src/androidMain/kotlin/dev/datlag/aniflow/App.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ class App : MultiDexApplication(), DIAware {
3535
.detectAll()
3636
.permitDiskReads()
3737
.permitDiskWrites()
38+
.permitCustomSlowCalls()
3839
.penaltyLog()
3940
.penaltyDialog()
4041
.build()

composeApp/src/androidMain/kotlin/dev/datlag/aniflow/MainActivity.kt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@ import com.google.android.play.core.appupdate.AppUpdateManagerFactory
2424
import com.google.android.play.core.appupdate.AppUpdateOptions
2525
import com.google.android.play.core.install.model.AppUpdateType
2626
import com.google.android.play.core.ktx.requestAppUpdateInfo
27+
import dev.datlag.aniflow.other.ConsentInfo
2728
import dev.datlag.aniflow.other.DomainVerifier
29+
import dev.datlag.aniflow.other.LocalConsentInfo
2830
import dev.datlag.aniflow.other.UpdateManager
2931
import dev.datlag.aniflow.other.UserHelper
3032
import dev.datlag.aniflow.ui.navigation.RootComponent
@@ -65,10 +67,13 @@ class MainActivity : AppCompatActivity() {
6567
manager.startUpdateFlow(info, this, AppUpdateOptions.defaultOptions(type))
6668
}
6769

70+
val consentInfo = ConsentInfo(this)
71+
6872
setContent {
6973
CompositionLocalProvider(
7074
LocalLifecycleOwner provides lifecycleOwner,
71-
LocalEdgeToEdge provides true
75+
LocalEdgeToEdge provides true,
76+
LocalConsentInfo provides consentInfo
7277
) {
7378
App(
7479
di = di
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package dev.datlag.aniflow.other
2+
3+
import android.app.Activity
4+
import com.google.android.gms.ads.MobileAds
5+
import com.google.android.ump.ConsentInformation
6+
import com.google.android.ump.ConsentRequestParameters
7+
import com.google.android.ump.UserMessagingPlatform
8+
import java.util.concurrent.atomic.AtomicBoolean
9+
10+
actual class ConsentInfo(private val activity: Activity) {
11+
12+
private var isMobileAdsInitialized = AtomicBoolean(false)
13+
14+
private val consentInformation = UserMessagingPlatform.getConsentInformation(activity)
15+
private val params = ConsentRequestParameters.Builder().build()
16+
17+
actual val privacy: Boolean
18+
get() = consentInformation.privacyOptionsRequirementStatus == ConsentInformation.PrivacyOptionsRequirementStatus.REQUIRED
19+
20+
actual fun initialize() {
21+
consentInformation.requestConsentInfoUpdate(
22+
activity,
23+
params,
24+
{
25+
// success
26+
UserMessagingPlatform.loadAndShowConsentFormIfRequired(activity) {
27+
// dismiss
28+
initializeMobileAds()
29+
}
30+
},
31+
{
32+
// error
33+
initializeMobileAds(true)
34+
}
35+
)
36+
}
37+
38+
actual fun reset() {
39+
consentInformation.reset()
40+
}
41+
42+
actual fun showPrivacyForm() {
43+
UserMessagingPlatform.showPrivacyOptionsForm(activity) {
44+
// dismiss
45+
initializeMobileAds()
46+
}
47+
}
48+
49+
private fun initializeMobileAds(force: Boolean = false) {
50+
if (consentInformation.canRequestAds() || force) {
51+
if (isMobileAdsInitialized.get()) {
52+
return
53+
}
54+
55+
MobileAds.initialize(activity)
56+
isMobileAdsInitialized.set(true)
57+
}
58+
}
59+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package dev.datlag.aniflow.ui.custom
2+
3+
import androidx.compose.foundation.layout.fillMaxWidth
4+
import androidx.compose.runtime.Composable
5+
import androidx.compose.runtime.getValue
6+
import androidx.compose.ui.Modifier
7+
import androidx.compose.ui.viewinterop.AndroidView
8+
import com.google.android.gms.ads.AdListener
9+
import com.google.android.gms.ads.AdRequest
10+
import com.google.android.gms.ads.AdSize
11+
import dev.datlag.aniflow.BuildKonfig
12+
import dev.datlag.aniflow.Sekret
13+
import dev.datlag.aniflow.other.StateSaver
14+
import com.google.android.gms.ads.AdView
15+
import com.google.android.gms.ads.LoadAdError
16+
import com.google.android.gms.ads.VideoOptions
17+
import com.google.android.gms.ads.nativead.NativeAdOptions
18+
import dev.datlag.tooling.decompose.lifecycle.collectAsStateWithLifecycle
19+
import io.github.aakira.napier.Napier
20+
21+
@Composable
22+
actual fun AdView(id: String, type: AdType) {
23+
val nativeAdState = rememberCustomNativeAdState(
24+
adUnit = id,
25+
nativeAdOptions = NativeAdOptions.Builder()
26+
.setVideoOptions(
27+
VideoOptions.Builder()
28+
.setStartMuted(true).setClickToExpandRequested(true)
29+
.build()
30+
).setRequestMultipleImages(true)
31+
.build(),
32+
adListener = object : AdListener() {
33+
override fun onAdFailedToLoad(p0: LoadAdError) {
34+
super.onAdFailedToLoad(p0)
35+
Napier.e(p0.message)
36+
}
37+
}
38+
)
39+
40+
val nativeAd by nativeAdState.nativeAd.collectAsStateWithLifecycle()
41+
42+
nativeAd?.let { NativeAdCard(it, Modifier.fillMaxWidth()) }
43+
}
44+
45+
actual object Ads {
46+
actual fun native(): String? {
47+
return if (StateSaver.sekretLibraryLoaded) {
48+
Sekret.androidAdNative(BuildKonfig.packageName)
49+
} else {
50+
null
51+
}
52+
}
53+
54+
actual fun banner(): String? {
55+
return if (StateSaver.sekretLibraryLoaded) {
56+
Sekret.androidAdBanner(BuildKonfig.packageName)
57+
} else {
58+
null
59+
}
60+
}
61+
}
62+
63+
@Composable
64+
actual fun BannerAd(id: String, modifier: Modifier) {
65+
AndroidView(
66+
factory = { context ->
67+
AdView(context).apply {
68+
adUnitId = id
69+
setAdSize(AdSize.BANNER)
70+
loadAd(AdRequest.Builder().build())
71+
}
72+
},
73+
modifier = modifier
74+
)
75+
}

0 commit comments

Comments
 (0)