From c79db1b955e7a5b506fc194dc0c8b06a88ca2de1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Ritzl?= Date: Sat, 15 Jun 2024 11:18:09 +0200 Subject: [PATCH] First version --- extension-admob/ext.manifest | 2 +- .../manifests/android/build.gradle | 3 + extension-admob/src/admob.cpp | 2 +- extension-admob/src/admob_android.cpp | 10 +- extension-admob/src/admob_ios.mm | 2 +- extension-admob/src/admob_private.h | 4 +- .../src/java/com/defold/admob/AdmobJNI.java | 114 +++++++++++++++++- game.project | 1 + 8 files changed, 127 insertions(+), 11 deletions(-) diff --git a/extension-admob/ext.manifest b/extension-admob/ext.manifest index 5aced13..7ad4d96 100644 --- a/extension-admob/ext.manifest +++ b/extension-admob/ext.manifest @@ -3,7 +3,7 @@ name: "AdMobExt" platforms: android: context: - aaptExtraPackages: ["androidx.work", "com.google.android.gms.common", "androidx.startup"] + aaptExtraPackages: ["androidx.work", "com.google.android.gms.common", "androidx.startup", "androidx.lifecycle"] ios: context: diff --git a/extension-admob/manifests/android/build.gradle b/extension-admob/manifests/android/build.gradle index ffbdf7d..2f874ee 100644 --- a/extension-admob/manifests/android/build.gradle +++ b/extension-admob/manifests/android/build.gradle @@ -5,4 +5,7 @@ repositories { dependencies { // https://developers.google.com/admob/android/quick-start#example_app-level_buildgradle_excerpt implementation 'com.google.android.gms:play-services-ads:22.6.0' + implementation "androidx.lifecycle:lifecycle-common:2.3.1" + implementation "androidx.lifecycle:lifecycle-process:2.3.1" + annotationProcessor "androidx.lifecycle:lifecycle-compiler:2.3.1" } diff --git a/extension-admob/src/admob.cpp b/extension-admob/src/admob.cpp index 2d100d7..21e0040 100644 --- a/extension-admob/src/admob.cpp +++ b/extension-admob/src/admob.cpp @@ -286,7 +286,7 @@ static dmExtension::Result AppInitializeAdmob(dmExtension::AppParams* params) static dmExtension::Result InitializeAdmob(dmExtension::Params* params) { LuaInit(params->m_L); - Initialize_Ext(); + Initialize_Ext(params); InitializeCallback(); return dmExtension::RESULT_OK; } diff --git a/extension-admob/src/admob_android.cpp b/extension-admob/src/admob_android.cpp index 63eaddb..599f0bf 100644 --- a/extension-admob/src/admob_android.cpp +++ b/extension-admob/src/admob_android.cpp @@ -121,7 +121,7 @@ static void InitJNIMethods(JNIEnv* env, jclass cls) g_admob.m_SetMaxAdContentRating = env->GetMethodID(cls, "setMaxAdContentRating", "(I)V"); } -void Initialize_Ext() +void Initialize_Ext(dmExtension::Params* params) { dmAndroid::ThreadAttacher threadAttacher; JNIEnv* env = threadAttacher.GetEnv(); @@ -129,9 +129,11 @@ void Initialize_Ext() InitJNIMethods(env, cls); - jmethodID jni_constructor = env->GetMethodID(cls, "", "(Landroid/app/Activity;)V"); - - g_admob.m_AdmobJNI = env->NewGlobalRef(env->NewObject(cls, jni_constructor, threadAttacher.GetActivity()->clazz)); + const char* appOpenAdUnitId = dmConfigFile::GetString(params->m_ConfigFile, "admob.app_open_ad_unit_id", 0); + jstring jappOpenAdUnitId = env->NewStringUTF(appOpenAdUnitId); + jmethodID jni_constructor = env->GetMethodID(cls, "", "(Landroid/app/Activity;Ljava/lang/String;)V"); + g_admob.m_AdmobJNI = env->NewGlobalRef(env->NewObject(cls, jni_constructor, threadAttacher.GetActivity()->clazz, jappOpenAdUnitId)); + env->DeleteLocalRef(jappOpenAdUnitId); } void Finalize_Ext() diff --git a/extension-admob/src/admob_ios.mm b/extension-admob/src/admob_ios.mm index 1bf10c8..3821628 100755 --- a/extension-admob/src/admob_ios.mm +++ b/extension-admob/src/admob_ios.mm @@ -441,7 +441,7 @@ void DestroyBanner() { //-------------------------------------------------- -void Initialize_Ext() { +void Initialize_Ext(dmExtension::Params* params) { UIWindow* window = dmGraphics::GetNativeiOSUIWindow(); uiViewController = window.rootViewController; diff --git a/extension-admob/src/admob_private.h b/extension-admob/src/admob_private.h index f6fe464..aca0479 100644 --- a/extension-admob/src/admob_private.h +++ b/extension-admob/src/admob_private.h @@ -2,6 +2,8 @@ #pragma once +#include + namespace dmAdmob { @@ -42,7 +44,7 @@ enum MaxAdRating MAX_AD_CONTENT_RATING_MA = 3 }; -void Initialize_Ext(); +void Initialize_Ext(dmExtension::Params* params); void Finalize_Ext(); void Initialize(const char* defoldUserAgent); diff --git a/extension-admob/src/java/com/defold/admob/AdmobJNI.java b/extension-admob/src/java/com/defold/admob/AdmobJNI.java index 82f7536..316efee 100644 --- a/extension-admob/src/java/com/defold/admob/AdmobJNI.java +++ b/extension-admob/src/java/com/defold/admob/AdmobJNI.java @@ -14,8 +14,16 @@ import android.content.Context; import android.content.SharedPreferences; +import androidx.lifecycle.LifecycleObserver; +import androidx.lifecycle.ProcessLifecycleOwner; +import androidx.lifecycle.OnLifecycleEvent; +import androidx.lifecycle.Lifecycle.Event; + import com.google.android.gms.ads.AdSize; import com.google.android.gms.ads.AdView; +import com.google.android.gms.ads.appopen.AppOpenAd; +import com.google.android.gms.ads.appopen.AppOpenAd.AppOpenAdLoadCallback; +import com.google.android.gms.ads.FullScreenContentCallback; import com.google.android.gms.ads.AdListener; import com.google.android.gms.ads.AdRequest; import com.google.android.gms.ads.AdError; @@ -43,7 +51,7 @@ import org.json.JSONObject; import org.json.JSONException; -public class AdmobJNI { +public class AdmobJNI implements LifecycleObserver { private static final String TAG = "AdmobJNI"; @@ -102,11 +110,30 @@ public class AdmobJNI { private String defoldUserAgent = "defold-x.y.z"; - private Activity activity; - public AdmobJNI(Activity activity) { + // BEGIN APP OPEN AD + private String appOpenAdUnitId = null; + private AppOpenAd appOpenAd = null; + private boolean isLoadingAppOpenAd = false; + private boolean isShowingAppOpenAd = false; + // END APP OPEN AD + + + public AdmobJNI(Activity activity, String appOpenAdUnitId) { this.activity = activity; + this.appOpenAdUnitId = appOpenAdUnitId; + + // If App Open Ads are used we need to set up a lifecycle observer + // to know when the app moves to the foreground + if (appOpenAdUnitId != null) { + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + ProcessLifecycleOwner.get().getLifecycle().addObserver(AdmobJNI.this); + } + }); + } } public void initialize(String defoldUserAgent) { @@ -243,6 +270,87 @@ private AdRequest createAdRequest() { return new AdRequest.Builder().setRequestAgent(defoldUserAgent).build(); } +//-------------------------------------------------- +// App Open Ads + + @OnLifecycleEvent(Event.ON_START) + protected void onMoveToForeground() { + // If the app open ad is already showing, do not show the ad again + if (isShowingAppOpenAd) { + Log.d(TAG, "The app open ad is already showing."); + return; + } + + // If the app open ad is not available yet then load it + if (appOpenAd == null) { + Log.d(TAG, "The app open ad is not ready yet."); + loadAppOpenAd(appOpenAdUnitId); + return; + } + + appOpenAd.setFullScreenContentCallback( + new FullScreenContentCallback() { + + @Override + public void onAdDismissedFullScreenContent() { + // Called when fullscreen content is dismissed. + // Clean up state and load a new ad + Log.d(TAG, "Ad dismissed fullscreen content."); + appOpenAd = null; + isShowingAppOpenAd = false; + loadAppOpenAd(appOpenAdUnitId); + } + + @Override + public void onAdFailedToShowFullScreenContent(AdError adError) { + // Called when fullscreen content failed to show. + // Clean up state and load a new ad + Log.d(TAG, adError.getMessage()); + appOpenAd = null; + isShowingAppOpenAd = false; + loadAppOpenAd(appOpenAdUnitId); + } + + @Override + public void onAdShowedFullScreenContent() { + // Called when fullscreen content is shown. + Log.d(TAG, "Ad showed fullscreen content."); + } + }); + isShowingAppOpenAd = true; + appOpenAd.show(activity); + } + + // Load an app open ad with the provided ad unit id + private void loadAppOpenAd(String adUnitId) { + // Do not load ad if there is an unused ad or one is already loading. + if (isLoadingAppOpenAd || appOpenAd != null) { + return; + } + + isLoadingAppOpenAd = true; + AdRequest request = new AdRequest.Builder().build(); + AppOpenAd.load( + activity, adUnitId, request, + AppOpenAd.APP_OPEN_AD_ORIENTATION_PORTRAIT, + new AppOpenAdLoadCallback() { + @Override + public void onAdLoaded(AppOpenAd ad) { + // Called when an app open ad has loaded. + Log.d(TAG, "Ad was loaded."); + appOpenAd = ad; + isLoadingAppOpenAd = false; + } + + @Override + public void onAdFailedToLoad(LoadAdError loadAdError) { + // Called when an app open ad has failed to load. + Log.d(TAG, loadAdError.getMessage()); + isLoadingAppOpenAd = false; + } + }); + } + //-------------------------------------------------- // Interstitial ADS diff --git a/game.project b/game.project index ddb2b04..dc8d3f7 100644 --- a/game.project +++ b/game.project @@ -35,5 +35,6 @@ include_dirs = extension-admob [admob] app_id_ios = ca-app-pub-3940256099942544~1458002511 app_id_android = ca-app-pub-3940256099942544~3347511713 +app_open_ad_unit_id = ca-app-pub-3940256099942544/9257395921 ios_tracking_usage_description = Your data will be used to provide you a better and personalized ad experience.