Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added support for app open ads #44

Merged
merged 9 commits into from
Jul 2, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 37 additions & 4 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ The extension can be configured by adding the following fields to `game.project`
[admob]
app_id_ios = ca-app-pub-3940256099942544~1458002511
app_id_android = ca-app-pub-3940256099942544~3347511713
app_open_android = ca-app-pub-3940256099942544/9257395921
app_open_ios = ca-app-pub-3940256099942544/5575463023
ios_tracking_usage_description = Your data will be used to provide you a better and personalized ad experience.
```

Expand All @@ -37,6 +39,12 @@ This is your iOS AdMob app ID. An app ID is a unique ID number assigned to your
### app_id_android
This is your Android AdMob app ID. An app ID is a unique ID number assigned to your apps when they're added to AdMob. The app ID is used to identify your apps.

### app_open_android
Ad unit to use for App Open ads on Android. If this value is set App Open Ads will be shown when the app is brought to the foreground.

### app_open_ios
Ad unit to use for App Open ads on iOS. If this value is set App Open Ads will be shown when the app is brought to the foreground.

### ios_tracking_usage_description

Before requesting the unique IDFA string for a device on iOS 14 the application must request user authorization to access app-related data for tracking the user or the device. This is done automatically when `admob.request_idfa()` is called. The string set in `admob.ios_tracking_usage_description` will be shown to the user.
Expand Down Expand Up @@ -120,16 +128,26 @@ local function admob_callback(self, message_id, message)
end
```

### Ad formats

The extension supports the following ad formats:

* App Open Ads - App open ads are a special ad format intended for publishers wishing to monetize their app load screens. App open ads can be closed by your users at any time. App open ads can be shown when users bring your app to the foreground.
* Banner Ads - Banner ads are rectangular ads that occupy a portion of an app's layout. They stay on screen while users are interacting with the app.
* Interstitial Ads - Interstitial ads are full-screen ads that cover the interface of an app until closed by the user.
* Rewarded Ads - Rewarded ads are ads that users have the option of interacting with in exchange for in-app rewards.
* Rewarded Interstitial Ads - Rewarded interstitial is a type of incentivized ad format that allows you offer rewards for ads that appear automatically during natural app transitions. Unlike rewarded ads, users aren't required to opt-in to view a rewarded interstitial.


### Loading ads

Before an ad unit can be displayed it has to be loaded:

```lua
admob.load_banner(ad_unit, size)
admob.load_interstitial(ad_unit)
admob.load_rewarded(ad_unit)
admob.load_rewarded_interstitial(ad_unit)
admob.load_banner(ad_unit, size)
```

The callback function will be invoked when the ad unit is ready:
Expand All @@ -150,6 +168,8 @@ local function admob_callback(self, message_id, message)
-- same as above
elseif message_id == admob.MSG_BANNER then
-- same as above
elseif message_id == admob.MSG_APPOPEN then
-- same as above
end
```

Expand All @@ -162,15 +182,14 @@ admob.is_rewarded_loaded()
admob.is_rewarded_interstitial_loaded()
```


### Showing ads
Once an ad unit has been loaded it is ready to be shown:

```lua
admob.show_banner(position)
admob.show_interstitial()
admob.show_rewarded()
admob.show_rewarded_interstitial()
admob.show_banner(position)
```

The callback function will be invoked when the ad unit is shown:
Expand All @@ -197,10 +216,24 @@ local function admob_callback(self, message_id, message)
-- same as above
elseif message_id == admob.MSG_BANNER then
-- same as above
elseif message_id == admob.MSG_APPOPEN then
-- same as above
end
```

Banner ads can be hidden and destroyed:
### App Open Ads

App Open Ads will automatically be loaded and shown if an ad unit id is provided in the `game.project` configuration (see above). If you wish to manually load and show App Open Ads you can leave the `game.project` configuration blank and instead use the following functions:

```lua
admob.load_appopen(ad_unit)
admob.show_appopen()
admob.is_appopen_loaded()
```

### Banner ads

In addition to loading and showing Banner Ads they can also be hidden and destroyed:

```lua
admob.hide_banner()
Expand Down
51 changes: 51 additions & 0 deletions extension-admob/api/admob.script_api
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,54 @@
[Android](https://developers.google.com/admob/android/ad-inspector),
[iOS](https://developers.google.com/admob/ios/ad-inspector)

#*****************************************************************************************************

- name: load_appopen
type: function
desc: Starts loading an AppOpen Ad, can only be called after `admob.MSG_INITIALIZATION` event
Original docs
[Android](https://developers.google.com/admob/android/app-open),
[iOS](https://developers.google.com/admob/ios/app-open)

parameters:
- name: ad_unit_id
type: string
desc: Ad unit ID, for test ads use on Android `"ca-app-pub-3940256099942544/9257395921"`, or
on iOS `"ca-app-pub-3940256099942544/5575463023"`
Original docs
[Android](https://developers.google.com/admob/android/app-open),
[iOS](https://developers.google.com/admob/ios/app-open)

#*****************************************************************************************************

- name: show_appopen
type: function
desc: Shows loaded AppOpen Ad, can only be called after `admob.EVENT_LOADED`
Original docs
[Android](https://developers.google.com/admob/android/app-open),
[iOS](https://developers.google.com/admob/ios/app-open)

examples:
- desc: |-
```lua
if admob and admob.is_appopen_loaded() then
admob.show_appopen()
end
```

#*****************************************************************************************************

- name: is_appopen_loaded
type: function
desc: Checks if AppOpen Ad is loaded and ready to show
Original docs
[Android](https://developers.google.com/admob/android/app-open),
[iOS](https://developers.google.com/admob/ios/app-open)

returns:
- name: is_ready
type: boolean

#*****************************************************************************************************

- name: load_interstitial
Expand Down Expand Up @@ -479,6 +527,9 @@
- name: MSG_REWARDED_INTERSTITIAL
type: number

- name: MSG_APPOPEN
type: number

#*****************************************************************************************************

- name: EVENT_CLOSED
Expand Down
2 changes: 1 addition & 1 deletion extension-admob/ext.manifest
Original file line number Diff line number Diff line change
Expand Up @@ -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"]
britzl marked this conversation as resolved.
Show resolved Hide resolved

ios:
context:
Expand Down
3 changes: 3 additions & 0 deletions extension-admob/manifests/android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
36 changes: 34 additions & 2 deletions extension-admob/src/admob.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ static const char DEFOLD_USERAGENT[] = "defold-3.4.1";
static int Lua_Initialize(lua_State* L)
{
DM_LUA_STACK_CHECK(L, 0);
Initialize(DEFOLD_USERAGENT);
Initialize();
return 0;
}

Expand All @@ -29,6 +29,24 @@ static int Lua_SetCallback(lua_State* L)
return 0;
}

static int Lua_LoadAppOpen(lua_State* L)
{
DM_LUA_STACK_CHECK(L, 0);
if (lua_type(L, 1) != LUA_TSTRING) {
return DM_LUA_ERROR("Expected string, got %s. Wrong type for App Open Ad UnitId variable '%s'.", luaL_typename(L, 1), lua_tostring(L, 1));
}
const char* unitId_lua = luaL_checkstring(L, 1);
LoadAppOpen(unitId_lua);
return 0;
}

static int Lua_ShowAppOpen(lua_State* L)
{
DM_LUA_STACK_CHECK(L, 0);
ShowAppOpen();
return 0;
}

static int Lua_LoadInterstitial(lua_State* L)
{
DM_LUA_STACK_CHECK(L, 0);
Expand Down Expand Up @@ -155,6 +173,14 @@ static int Lua_IsBannerLoaded(lua_State* L)
return 1;
}

static int Lua_IsAppOpenLoaded(lua_State* L)
{
DM_LUA_STACK_CHECK(L, 1);
bool is_loaded = IsAppOpenLoaded();
lua_pushboolean(L, is_loaded);
return 1;
}

static int Lua_SetPrivacySettings(lua_State* L)
{
DM_LUA_STACK_CHECK(L, 0);
Expand Down Expand Up @@ -189,6 +215,8 @@ static const luaL_reg Module_methods[] =
{
{"initialize", Lua_Initialize},
{"set_callback", Lua_SetCallback},
{"load_appopen", Lua_LoadAppOpen},
{"show_appopen", Lua_ShowAppOpen},
{"load_interstitial", Lua_LoadInterstitial},
{"show_interstitial", Lua_ShowInterstitial},
{"load_rewarded", Lua_LoadRewarded},
Expand All @@ -203,6 +231,7 @@ static const luaL_reg Module_methods[] =
{"is_interstitial_loaded", Lua_IsInterstitialLoaded},
{"is_rewarded_interstitial_loaded", Lua_IsRewardedInterstitialLoaded},
{"is_banner_loaded", Lua_IsBannerLoaded},
{"is_appopen_loaded", Lua_IsAppOpenLoaded},
{"set_privacy_settings", Lua_SetPrivacySettings},
{"request_idfa", Lua_RequestIDFA},
{"show_ad_inspector", Lua_ShowAdInspector},
Expand All @@ -225,6 +254,7 @@ static void LuaInit(lua_State* L)
SETCONSTANT(MSG_INITIALIZATION)
SETCONSTANT(MSG_IDFA)
SETCONSTANT(MSG_REWARDED_INTERSTITIAL)
SETCONSTANT(MSG_APPOPEN)

SETCONSTANT(EVENT_CLOSED)
SETCONSTANT(EVENT_FAILED_TO_SHOW)
Expand Down Expand Up @@ -280,13 +310,15 @@ static void LuaInit(lua_State* L)

static dmExtension::Result AppInitializeAdmob(dmExtension::AppParams* params)
{
dmLogInfo("AppInitializeAdmob");
return dmExtension::RESULT_OK;
}

static dmExtension::Result InitializeAdmob(dmExtension::Params* params)
{
dmLogInfo("InitializeAdmob");
LuaInit(params->m_L);
Initialize_Ext();
Initialize_Ext(params, DEFOLD_USERAGENT);
InitializeCallback();
return dmExtension::RESULT_OK;
}
Expand Down
39 changes: 32 additions & 7 deletions extension-admob/src/admob_android.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ struct Admob
jobject m_AdmobJNI;

jmethodID m_Initialize;
jmethodID m_LoadAppOpen;
jmethodID m_ShowAppOpen;
jmethodID m_LoadInterstitial;
jmethodID m_ShowInterstitial;
jmethodID m_LoadRewarded;
Expand All @@ -29,6 +31,7 @@ struct Admob
jmethodID m_DestroyBanner;
jmethodID m_ShowBanner;
jmethodID m_HideBanner;
jmethodID m_IsAppOpenLoaded;
jmethodID m_IsRewardedLoaded;
jmethodID m_IsInterstitialLoaded;
jmethodID m_IsRewardedInterstitialLoaded;
Expand Down Expand Up @@ -98,7 +101,9 @@ static void CallVoidMethodBool(jobject instance, jmethodID method, bool cbool)

static void InitJNIMethods(JNIEnv* env, jclass cls)
{
g_admob.m_Initialize = env->GetMethodID(cls, "initialize", "(Ljava/lang/String;)V");
g_admob.m_Initialize = env->GetMethodID(cls, "initialize", "()V");
g_admob.m_LoadAppOpen = env->GetMethodID(cls, "loadAppOpen", "(Ljava/lang/String;)V");
g_admob.m_ShowAppOpen = env->GetMethodID(cls, "showAppOpen", "()V");
g_admob.m_LoadInterstitial = env->GetMethodID(cls, "loadInterstitial", "(Ljava/lang/String;)V");
g_admob.m_ShowInterstitial = env->GetMethodID(cls, "showInterstitial", "()V");
g_admob.m_LoadRewarded = env->GetMethodID(cls, "loadRewarded", "(Ljava/lang/String;)V");
Expand All @@ -114,33 +119,53 @@ static void InitJNIMethods(JNIEnv* env, jclass cls)
g_admob.m_ShowAdInspector = env->GetMethodID(cls, "showAdInspector", "()V");
g_admob.m_UpdateBannerLayout= env->GetMethodID(cls, "updateBannerLayout", "()V");

g_admob.m_IsAppOpenLoaded = env->GetMethodID(cls, "isAppOpenLoaded", "()Z");
g_admob.m_IsRewardedLoaded = env->GetMethodID(cls, "isRewardedLoaded", "()Z");
g_admob.m_IsInterstitialLoaded = env->GetMethodID(cls, "isInterstitialLoaded", "()Z");
g_admob.m_IsRewardedInterstitialLoaded = env->GetMethodID(cls, "isRewardedInterstitialLoaded", "()Z");
g_admob.m_IsBannerLoaded = env->GetMethodID(cls, "isBannerLoaded", "()Z");
g_admob.m_SetMaxAdContentRating = env->GetMethodID(cls, "setMaxAdContentRating", "(I)V");
}

void Initialize_Ext()
void Initialize_Ext(dmExtension::Params* params, const char* defoldUserAgent)
{
dmAndroid::ThreadAttacher threadAttacher;
JNIEnv* env = threadAttacher.GetEnv();
jclass cls = dmAndroid::LoadClass(env, "com.defold.admob.AdmobJNI");

InitJNIMethods(env, cls);

jmethodID jni_constructor = env->GetMethodID(cls, "<init>", "(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_android", 0);
jstring jappOpenAdUnitId = env->NewStringUTF(appOpenAdUnitId);
jstring jdefoldUserAgent = env->NewStringUTF(defoldUserAgent);
jmethodID jni_constructor = env->GetMethodID(cls, "<init>", "(Landroid/app/Activity;Ljava/lang/String;Ljava/lang/String;)V");
g_admob.m_AdmobJNI = env->NewGlobalRef(env->NewObject(cls, jni_constructor, threadAttacher.GetActivity()->clazz, jappOpenAdUnitId, jdefoldUserAgent));
env->DeleteLocalRef(jappOpenAdUnitId);
env->DeleteLocalRef(jdefoldUserAgent);
}

void Finalize_Ext()
{
}

void Initialize(const char* defoldUserAgent)
void Initialize()
{
CallVoidMethodChar(g_admob.m_AdmobJNI, g_admob.m_Initialize);
britzl marked this conversation as resolved.
Show resolved Hide resolved
}

void LoadAppOpen(const char* unitId)
{
CallVoidMethodChar(g_admob.m_AdmobJNI, g_admob.m_LoadAppOpen, unitId);
}

void ShowAppOpen()
{
CallVoidMethod(g_admob.m_AdmobJNI, g_admob.m_ShowAppOpen);
}

bool IsAppOpenLoaded()
{
CallVoidMethodChar(g_admob.m_AdmobJNI, g_admob.m_Initialize, defoldUserAgent);
return CallBoolMethod(g_admob.m_AdmobJNI, g_admob.m_IsAppOpenLoaded);
}

void LoadInterstitial(const char* unitId)
Expand Down
3 changes: 2 additions & 1 deletion extension-admob/src/admob_callback_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ enum MessageId
MSG_BANNER = 3,
MSG_INITIALIZATION = 4,
MSG_IDFA = 5,
MSG_REWARDED_INTERSTITIAL = 6
MSG_REWARDED_INTERSTITIAL = 6,
MSG_APPOPEN = 7
};

enum MessageEvent
Expand Down
Loading