由於項目裏接入了廣告,包括但不限於穿山甲sdk和廣點通sdk,視頻廣告是收益比較高的廣告,項目裏面出現的地方比較多。流程一般都是UI上有個按鈕,點擊按鈕,請求到激勵視頻廣告,然後直接打開該廣告,也就是跳轉到廣告視頻頁面,等廣告播放結束後,會有關閉按鈕,點擊關閉按鈕,廣告sdk會觸發暴露出來的回調;如果請求廣告失敗,我們自己也會處理;這兩種情況我們都是可以掌控的,也就是說這兩種情況,我們都會有方法接收到事件,我們可以根據相應的事件,做出下一步的處理,比如給用戶發獎勵,或者重新請求廣告。
打開廣告激勵視頻的方法如下
穿山甲 : nativeAd.showRewardVideoAd(activity); // nativeAd 是 TTRewardVideoAd 類型
廣點通 : rewardVideoAD.showAD(); // rewardVideoAD 是 RewardVideoAD 類型
上面方法都是 sdk 提供的方法,我們直接調用即可。但問題也來了,如果廣告獲取到了,同時也調用了該方法,如果廣告頁面沒打開怎麼辦?上面兩個方法都是 void 類型,如果說廣告頁面打開失敗,但是沒有回調事件,那麼我們的UI界面由於沒有接到下一步的指示,可能會一直固定在當前頁面,甚至給人一種卡死的感覺,這種體驗無意是很差的。
怎麼辦?sdk沒提供方法,這就需要我們自己額外用些方法來檢查了,加些防護。
這種場景比較好復現,比如說我們請求了廣告,此時把app切到後臺,比如說回到桌面,1秒後廣告接口有廣告返回,此時觸發了 showRewardVideoAd(activity) 或 showAD() 方法,注意這時候app還在後臺,不可見的狀態,有些手機比如 oppp ,此時就不會跳轉到廣告頁面,即使此時重新計入app,也不行。我們怎麼處理呢?最簡單的方式,用 Handler 延遲方法,我們在調用廣告打開的方法的同時,用 Handler 延遲3秒執行段代碼,檢測app此時打開的Activity中,是否有當前打開的廣告頁面,比如 廣點通的 Activity : PortraitADActivity,穿山甲的 Activity:TTRewardVideoActivity 或 TTRewardExpressVideoActivity。 老樣子,
Application 的 registerActivityLifecycleCallbacks() 方法再次被用到,根據它的回調方法,來儲存當前所有的 Activity, 方法如下
public class GlobalActivityLifecycle implements Application.ActivityLifecycleCallbacks {
private static GlobalActivityLifecycle sInstance;
public static void register(Application app) {
if (sInstance == null) {
synchronized (GlobalActivityLifecycle.class) {
if (sInstance == null) {
sInstance = new GlobalActivityLifecycle();
app.registerActivityLifecycleCallbacks(sInstance);
}
}
}
}
private static HashSet<String> mActivityNameSet = new HashSet<>();
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
mActivityNameSet.add(activity.getClass().getSimpleName());
}
@Override
public void onActivityStarted(Activity activity) {
}
@Override
public void onActivityResumed(Activity activity) {
}
@Override
public void onActivityPaused(Activity activity) {
}
@Override
public void onActivityStopped(Activity activity) {
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
@Override
public void onActivityDestroyed(Activity activity) {
mActivityNameSet.remove(activity.getClass().getSimpleName());
}
public static boolean isContainActivity(String activitySimpleName){
return mActivityNameSet.contains(activitySimpleName);
}
public static boolean isContainActivity(String ... names){
for(String name : names){
if(mActivityNameSet.contains(name)){
return true;
}
}
return false;
}
}
上面是工具類,下面是調用方法
Handler mHandler = new Handler(Looper.getMainLooper());
/**
* 穿山甲
*/
public void showRewardVideoAd(Activity activity, TTRewardVideoAd nativeAd) {
nativeAd.showRewardVideoAd(activity);
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
if(!GlobalActivityLifecycle.isContainActivity("TTRewardVideoActivity", "TTRewardExpressVideoActivity")){
// TODO: 在 這個裏面做一些告知UI的操作,意思是界面打開失敗了
}
}
}, 3000);
}
/**
* 廣點通
*/
public void tryShowRewardVideo(RewardVideoAD rewardVideoAD) {
rewardVideoAD.showAD();
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
if(!GlobalActivityLifecycle.isContainActivity("PortraitADActivity")){
// TODO: 在 這個裏面做一些告知UI的操作,意思是界面打開失敗了
}
}
}, 3000);
}
以上是思路,具體的大家可以通過擴展方法的形參,添加回調,或者使用觀察者模式發送通知,總之符合自己項目的業務邏輯即可。上面的方法是通過集合來檢查 Activity 的名字,可能有人會問,爲什麼不直接用 App裏最 top 的Activity 來檢測?假如說我們成功的打開了激勵視頻頁面,這時候我們切入了後臺,或者點擊了視頻廣告,又打開了一個新的廣告頁面,這樣最頂端的Activity就不是激勵視頻廣告頁面了,這樣就誤判了。
以上只是提供一個思路,希望起到拋磚引玉的作用。