需求: 接入Google AdMob 开屏,横幅,插屏,激励视频
一、Google开发者账号
- 到Google注册一个账号;
- 登陆google开发者后台;
- 使用支持跨境信用卡,支付25美金(永久),即可提交应用;
二、cocoscreator发布原生项目
- 配置好creator原生开发环境后,可直接构建发布android项目;
- APP API:建议勾选
armeabi-v7a
与arm64-v8a
; - AndroidSDK根据google ad要求,截止目前支持开屏的话需要
android-30
; - 其他没啥好说的,直接构建;
- 项目目录下回生成
native/engine/android
,一般不是特殊需求在这里面改就行,不会每次构建或者迁移项目被覆盖和路径带来的问题;
三、cocoscreator发布原生项目
- 测试广告
非正式包一定要用测试ID,非正式包一定要用测试ID,非正式包一定要用测试ID
- 测试应用ID:
ca-app-pub-3940256099942544~3347511713
- 测试广告单元ID如下表:
广告格式 | 示例广告单元 ID |
---|---|
开屏广告 | ca-app-pub-3940256099942544/3419835294 |
横幅广告 | ca-app-pub-3940256099942544/6300978111 |
插页式广告 | ca-app-pub-3940256099942544/1033173712 |
插页式视频广告 | ca-app-pub-3940256099942544/8691691433 |
激励广告 | ca-app-pub-3940256099942544/5224354917 |
插页式激励广告 | ca-app-pub-3940256099942544/5354046379 |
原生高级广告 | ca-app-pub-3940256099942544/2247696110 |
原生高级视频广告 | ca-app-pub-3940256099942544/1044960115 |
四、接入前准备
- 适配 AndroidX,需在 发布的android项目下gradle.properties 文件添加如下配置代码:
android.useAndroidX=true
android.enableJetifier=true
此处没有在native下,移植或重新构建需要重新修改;
应用级build.gradle
下,添加Google AdMob所需依赖的库:
def lifecycle_version = "2.0.0"
implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-runtime:$lifecycle_version"
annotationProcessor "androidx.lifecycle:lifecycle-compiler:$lifecycle_version"
implementation 'com.google.android.gms:play-services-ads:20.6.0'
AndroidManifest.xml
下<application>
内添加应用ID:
<meta-data
android:name="com.google.android.gms.ads.APPLICATION_ID"
android:value="ca-app-pub-3940256099942544~3347511713"/>
五、开屏广告
- 原理是新建一个Activity,让他优先AppActivity启动,广告关闭后再跳转AppActivity启动游戏;
- 新建java类
SplashActivity.java
与MyApplication.java
,SplashActivity作为优先启动的Activity,MyApplication用于在Activity上显示开屏AD; - MyApplication.java源码如下(此类不用做修改):
/*
* Copyright 2021 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.cocos.game;
import android.app.Activity;
import android.app.Application;
import android.app.Application.ActivityLifecycleCallbacks;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.lifecycle.Lifecycle.Event;
import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.OnLifecycleEvent;
import androidx.lifecycle.ProcessLifecycleOwner;
import com.google.android.gms.ads.AdError;
import com.google.android.gms.ads.AdRequest;
import com.google.android.gms.ads.FullScreenContentCallback;
import com.google.android.gms.ads.LoadAdError;
import com.google.android.gms.ads.MobileAds;
import com.google.android.gms.ads.appopen.AppOpenAd;
import com.google.android.gms.ads.appopen.AppOpenAd.AppOpenAdLoadCallback;
import com.google.android.gms.ads.initialization.InitializationStatus;
import com.google.android.gms.ads.initialization.OnInitializationCompleteListener;
import java.util.Date;
/** Application class that initializes, loads and show ads when activities change states. */
public class MyApplication extends Application
implements ActivityLifecycleCallbacks, LifecycleObserver {
private AppOpenAdManager appOpenAdManager;
private Activity currentActivity;
@Override
public void onCreate() {
super.onCreate();
this.registerActivityLifecycleCallbacks(this);
MobileAds.initialize(
this,
new OnInitializationCompleteListener() {
@Override
public void onInitializationComplete(
@NonNull InitializationStatus initializationStatus) {}
});
ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
appOpenAdManager = new AppOpenAdManager();
}
/** LifecycleObserver method that shows the app open ad when the app moves to foreground. */
@OnLifecycleEvent(Event.ON_START)
protected void onMoveToForeground() {
// Show the ad (if available) when the app moves to foreground.
appOpenAdManager.showAdIfAvailable(currentActivity);
}
/** ActivityLifecycleCallback methods. */
@Override
public void onActivityCreated(@NonNull Activity activity, @Nullable Bundle savedInstanceState) {}
@Override
public void onActivityStarted(@NonNull Activity activity) {
// An ad activity is started when an ad is showing, which could be AdActivity class from Google
// SDK or another activity class implemented by a third party mediation partner. Updating the
// currentActivity only when an ad is not showing will ensure it is not an ad activity, but the
// one that shows the ad.
if (!appOpenAdManager.isShowingAd) {
currentActivity = activity;
}
}
@Override
public void onActivityResumed(@NonNull Activity activity) {}
@Override
public void onActivityPaused(@NonNull Activity activity) {}
@Override
public void onActivityStopped(@NonNull Activity activity) {}
@Override
public void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle outState) {}
@Override
public void onActivityDestroyed(@NonNull Activity activity) {}
/**
* Shows an app open ad.
*
* @param activity the activity that shows the app open ad
* @param onShowAdCompleteListener the listener to be notified when an app open ad is complete
*/
public void showAdIfAvailable(
@NonNull Activity activity,
@NonNull OnShowAdCompleteListener onShowAdCompleteListener) {
// We wrap the showAdIfAvailable to enforce that other classes only interact with MyApplication
// class.
appOpenAdManager.showAdIfAvailable(activity, onShowAdCompleteListener);
}
/**
* Interface definition for a callback to be invoked when an app open ad is complete
* (i.e. dismissed or fails to show).
*/
public interface OnShowAdCompleteListener {
void onShowAdComplete();
}
/** Inner class that loads and shows app open ads. */
private class AppOpenAdManager {
private static final String LOG_TAG = "AppOpenAdManager";
private static final String AD_UNIT_ID = "ca-app-pub-3940256099942544/3419835294";
private AppOpenAd appOpenAd = null;
private boolean isLoadingAd = false;
private boolean isShowingAd = false;
/** Keep track of the time an app open ad is loaded to ensure you don't show an expired ad. */
private long loadTime = 0;
/** Constructor. */
public AppOpenAdManager() {}
/**
* Load an ad.
*
* @param context the context of the activity that loads the ad
*/
private void loadAd(Context context) {
// Do not load ad if there is an unused ad or one is already loading.
if (isLoadingAd || isAdAvailable()) {
return;
}
isLoadingAd = true;
AdRequest request = new AdRequest.Builder().build();
AppOpenAd.load(
context,
AD_UNIT_ID,
request,
AppOpenAd.APP_OPEN_AD_ORIENTATION_PORTRAIT,
new AppOpenAdLoadCallback() {
/**
* Called when an app open ad has loaded.
*
* @param ad the loaded app open ad.
*/
@Override
public void onAdLoaded(AppOpenAd ad) {
appOpenAd = ad;
isLoadingAd = false;
loadTime = (new Date()).getTime();
Log.d(LOG_TAG, "onAdLoaded.");
// Toast.makeText(context, "onAdLoaded", Toast.LENGTH_SHORT).show();
}
/**
* Called when an app open ad has failed to load.
*
* @param loadAdError the error.
*/
@Override
public void onAdFailedToLoad(LoadAdError loadAdError) {
isLoadingAd = false;
Log.d(LOG_TAG, "onAdFailedToLoad: " + loadAdError.getMessage());
// Toast.makeText(context, "onAdFailedToLoad", Toast.LENGTH_SHORT).show();
}
});
}
/** Check if ad was loaded more than n hours ago. */
private boolean wasLoadTimeLessThanNHoursAgo(long numHours) {
long dateDifference = (new Date()).getTime() - loadTime;
long numMilliSecondsPerHour = 3600000;
return (dateDifference < (numMilliSecondsPerHour * numHours));
}
/** Check if ad exists and can be shown. */
private boolean isAdAvailable() {
// Ad references in the app open beta will time out after four hours, but this time limit
// may change in future beta versions. For details, see:
// https://support.google.com/admob/answer/9341964?hl=en
return appOpenAd != null && wasLoadTimeLessThanNHoursAgo(4);
}
/**
* Show the ad if one isn't already showing.
*
* @param activity the activity that shows the app open ad
*/
private void showAdIfAvailable(@NonNull final Activity activity) {
showAdIfAvailable(
activity,
new OnShowAdCompleteListener() {
@Override
public void onShowAdComplete() {
// Empty because the user will go back to the activity that shows the ad.
}
});
}
/**
* Show the ad if one isn't already showing.
*
* @param activity the activity that shows the app open ad
* @param onShowAdCompleteListener the listener to be notified when an app open ad is complete
*/
private void showAdIfAvailable(
@NonNull final Activity activity,
@NonNull OnShowAdCompleteListener onShowAdCompleteListener) {
// If the app open ad is already showing, do not show the ad again.
if (isShowingAd) {
Log.d(LOG_TAG, "The app open ad is already showing.");
return;
}
// If the app open ad is not available yet, invoke the callback then load the ad.
if (!isAdAvailable()) {
Log.d(LOG_TAG, "The app open ad is not ready yet.");
onShowAdCompleteListener.onShowAdComplete();
loadAd(activity);
return;
}
Log.d(LOG_TAG, "Will show ad.");
appOpenAd.setFullScreenContentCallback(
new FullScreenContentCallback() {
/** Called when full screen content is dismissed. */
@Override
public void onAdDismissedFullScreenContent() {
// Set the reference to null so isAdAvailable() returns false.
appOpenAd = null;
isShowingAd = false;
Log.d(LOG_TAG, "onAdDismissedFullScreenContent.");
// Toast.makeText(activity, "onAdDismissedFullScreenContent", Toast.LENGTH_SHORT).show();
onShowAdCompleteListener.onShowAdComplete();
loadAd(activity);
}
/** Called when fullscreen content failed to show. */
@Override
public void onAdFailedToShowFullScreenContent(AdError adError) {
appOpenAd = null;
isShowingAd = false;
Log.d(LOG_TAG, "onAdFailedToShowFullScreenContent: " + adError.getMessage());
// Toast.makeText(activity, "onAdFailedToShowFullScreenContent", Toast.LENGTH_SHORT).show();
onShowAdCompleteListener.onShowAdComplete();
loadAd(activity);
}
/** Called when fullscreen content is shown. */
@Override
public void onAdShowedFullScreenContent() {
Log.d(LOG_TAG, "onAdShowedFullScreenContent.");
// Toast.makeText(activity, "onAdShowedFullScreenContent", Toast.LENGTH_SHORT).show();
}
});
isShowingAd = true;
appOpenAd.show(activity);
}
}
}
- MyApplication.java延迟后加载ad,ad关闭后负责跳转:
/** Splash Activity that inflates splash activity xml. */
public class SplashActivity extends Activity {
private static final String LOG_TAG = "SplashActivity";
/**
* Number of seconds to count down before showing the app open ad. This simulates the time needed
* to load the app.
*/
private static final long COUNTER_TIME = 2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
// Create a timer so the SplashActivity will be displayed for a fixed amount of time.
createTimer(COUNTER_TIME);
}
/**
* Create the countdown timer, which counts down to zero and show the app open ad.
*
* @param seconds the number of seconds that the timer counts down from
*/
private void createTimer(long seconds) {
CountDownTimer countDownTimer =
new CountDownTimer(seconds * 1000, 1000) {
@Override
public void onTick(long millisUntilFinished) {
}
@Override
public void onFinish() {
Application application = getApplication();
// If the application is not an instance of MyApplication, log an error message and
// start the MainActivity without showing the app open ad.
if (!(application instanceof MyApplication)) {
Log.e(LOG_TAG, "Failed to cast application to MyApplication.");
startMainActivity();
return;
}
// Show the app open ad.
((MyApplication) application).showAdIfAvailable(SplashActivity.this,new OnShowAdCompleteListener() {
@Override
public void onShowAdComplete() {
startMainActivity();
}
});
}
};
countDownTimer.start();
}
/** Start the MainActivity. */
public void startMainActivity() {
Intent intent = new Intent(this, AppActivity.class);
this.startActivity(intent);
}
}
- R.layout.activity_splash:
<?xml version="1.0" encoding="UTF-8"?>
<android.widget.LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/activity_splash"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FFFFFF"
android:orientation="horizontal"
android:visibility="visible">
<TextView
android:id="@+id/textView3"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:layout_weight="1"
android:gravity="center"
android:lineSpacingExtra="12dp"
android:text="@string/app_splash"
android:textAlignment="center"
android:textSize="16sp"
android:textStyle="bold" />
</android.widget.LinearLayout>
- 最后在
AndroidManifest.xml
中设置优先启动
<application
android:name="com.cocos.game.MyApplication"
<!-- ...... -->
/>
<activity
android:name="com.cocos.game.SplashActivity"
android:exported="true"
android:noHistory="true"
android:screenOrientation="portrait"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- ...... -->
</application>
六、横幅、插屏、以及激励视频
- 加载完进入AppActivity后,做其他广告的初始化;
------ ------ ------ ------ ------ ------ ------ 未完待续。