1. 程式人生 > >谷歌原生廣告接入

谷歌原生廣告接入

今天來分享一下谷歌原生廣告的接入的經驗

首先,我先說明一下,谷歌廣告的種類,在建立應用的時候,選擇匯入廣告,然後選擇廣告種類的時候,會看到三個種類,一個是橫幅的,一個是全面視訊的,一個是插屏視屏的,除了那個橫幅的廣告,其餘兩個都是全屏的廣告,但是如果你看過谷歌的廣告開發文件的話,你就會發現有一個原生廣告,這個廣告就像朋友圈,qq空間這些,列表廣告的插入效果。

效果就是最近我們這個專案想要達到的效果,但是,帳號管理那哥們給了我兩個id然後就讓我接這個,後來程式碼寫好了。測試id都能拿到廣告,但是換成自己的id就是拿不到,網上搜了很久,有說要等幾個小時的,各種原因,後來我懷疑是廣告種類的問題,我就去找那哥們看帳號所選的種類,果然,他選的是一個全屏視訊的廣告(獎金視訊),然後讓我去接原生的,後來我就讓他重新選,他說,沒有原生廣告那個選項,然後我就懵逼了。

仔細看了一下文件上面的提示,emmmm,這就很尷尬了。

https://developers.google.com/admob/android/native-advanced-unified


就是這個,那哥們英語好直接就看懂了。然後我翻譯過來一看就是:


谷歌提示說這個是高階版本的,已經發布給一些釋出商,如果你想要接入的話,emmmm。看到這兒,我想基本上是沒戲了,然後就有了上文,接入facebook的廣告,專案就快要上線了。然後這個時候讓我重新接廣告,真的是有點小無語,好在facebook遇到的坑不算很多,一天就搞定了,不然真的就很尷尬了。

好了雖然這樣但是我還是分享一下怎麼接入這個高階的原生廣告,說不定哪天谷歌就給開放給大眾了呢,也說不定,是吧。

老規矩還是先是導包配置什麼的,這裡谷歌的開發文件已經說的很清楚了。我就不再囉嗦了,照著做就可以了。

https://developers.google.com/admob/android/quick-start

文件的下方清楚的展示了四個種類的廣告,但是呢,你去給你的應用建立廣告的時候才會發現,你只能選擇三個,native這個就是沒有,氣不氣。。。

好了,繼續講怎麼接入,首先接入廣告第一行程式碼就是要配置你的id


比如說這裡,就馬上要你填寫app的id了,如果你說你沒有,但是也想看一下效果怎麼辦?這個好辦,谷歌有提供專門的測試id給你測試用,然後我也是用的這個測試id才看到的效果


比如說就是這個

https://developers.google.com/admob/android/test-ads

谷歌的文件裡面專門有些了,和我一樣粗心大意的同學就可以看看了。每個廣告種類都有專門的id供你選擇,這裡我說一下,那個測試只看你的unit id  你的app id可以填寫你自己的,效果是一樣的,不影響。

接下來就可以寫一個方法去拿廣告了,我直接是去谷歌的demo裡面copy 的,然後改一些自己想要的,這裡我貼上我改後的程式碼:

private void refreshAd() {
    AdLoader.Builder builder = new AdLoader.Builder(mActivity, ADMOB_AD_UNIT_ID);
builder.forUnifiedNativeAd(new UnifiedNativeAd.OnUnifiedNativeAdLoadedListener() {
        // OnUnifiedNativeAdLoadedListener implementation.
@Override
public void onUnifiedNativeAdLoaded(UnifiedNativeAd unifiedNativeAd) {
            //成功拿到廣告  並且設定到adView當中
UnifiedNativeAdView adView = (UnifiedNativeAdView) mActivity.getLayoutInflater().inflate(R.layout.item_video_list_admob, null);
populateUnifiedNativeAdView(unifiedNativeAd, adView);
//判斷廣告有沒有拿完
if (adLoader.isLoading()){
                LogUtils.logLocalD("廣告-正在載入廣告");
}else {
                LogUtils.logLocalD("廣告-拿到所有廣告");
                if (adMobGetLisenter != null) adMobGetLisenter.getAdViewOk(unifiedNativeAdViews);
}
        }

    });
VideoOptions videoOptions = new VideoOptions.Builder()
            .setStartMuted(true)//視訊廣告是否靜音
.build();
NativeAdOptions adOptions = new NativeAdOptions.Builder()
            .setVideoOptions(videoOptions)
            .build();
builder.withNativeAdOptions(adOptions);
adLoader = builder.withAdListener(new AdListener() {
        @Override
public void onAdFailedToLoad(int errorCode) {//獲取廣告失敗
LogUtils.logLocalD("廣告Failed to load native ad: "
+ errorCode);
            if (adMobGetLisenter != null) adMobGetLisenter.getAdViewFail(errorCode);
}
    }).build();
AdRequest request = new AdRequest.Builder()
            .build();
adLoader.loadAds(request,5);
}

這裡和demo裡面有些不一樣,我請求的是多條廣告所以用的是loadAds這個方法,demo裡面用的是loadAd這個方法是獲取一條廣告,失敗的話就走onAdFailedToLoad這個方法。成功的話就走onUnifiedNativeAdLoaded這個方法,拿到一個unifiedNativeAd物件(存有廣告的資訊和一些其他雜七雜八的)。然後回到多條廣告,多條廣告你會問,怎麼返回的啊,返回值還是單個物件啊,並沒有返回一個list給我啊,別慌。仔細看谷歌的文件,上面寫的是多次呼叫返回,what?什麼意思。當時我就有點不明白了。我怎麼判斷,廣告都返回給我了了?我怎麼知道我要的5條廣告都OK了呢?直到我不知道從哪兒看到了這一句:adLoader.isLoading()   然後我就懂了,直接給你了嘛。判斷廣告有沒有拿完。

 //成功拿到廣告  並且設定到adView當中
UnifiedNativeAdView adView = (UnifiedNativeAdView) mActivity.getLayoutInflater().inflate(R.layout.item_video_list_admob, null);
populateUnifiedNativeAdView(unifiedNativeAd, adView);
//判斷廣告有沒有拿完
if (adLoader.isLoading()){
                LogUtils.logLocalD("廣告-正在載入廣告");
}else {
                LogUtils.logLocalD("廣告-拿到所有廣告");
                if (adMobGetLisenter != null) adMobGetLisenter.getAdViewOk(unifiedNativeAdViews);
}

所以就有了這些程式碼。我把每次得到的unifiedNativeAd這個物件都傳給了populateUnifiedNativeAdView這個方法處理,然後在這個類裡面建立了我要的adViews  一個廣告view的list  然後我判斷一下廣告如果是拿完了,就調一下監聽,返回我想要的list,然後就可以把list裡面的view內容拿去用,加到你的主列表裡面還是幹啥。都隨便了。

接下來我們看一下unifiedNativeAd轉view的那個方法:

private void populateUnifiedNativeAdView(UnifiedNativeAd nativeAd, UnifiedNativeAdView adView) {
        // Get the video controller for the ad. One will always be provided, even if the ad doesn't
        // have a video asset.
VideoController vc = nativeAd.getVideoController();
// Create a new VideoLifecycleCallbacks object and pass it to the VideoController. The
        // VideoController will call methods on this object when events occur in the video
        // lifecycle.
vc.setVideoLifecycleCallbacks(new VideoController.VideoLifecycleCallbacks() {
            public void onVideoEnd() {
                // Publishers should allow native ads to complete video playback before refreshing
                // or replacing them with another ad in the same UI location.
//                refresh.setEnabled(true);
//                videoStatus.setText("Video status: Video playback has ended.");
super.onVideoEnd();
}
        });
adView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
            @Override
public void onViewAttachedToWindow(View view) {
                LogUtils.logLocalD("廣告:onViewAttachedToWindow");
}

            @Override
public void onViewDetachedFromWindow(View view) {
                LogUtils.logLocalD("廣告:onViewDetachedFromWindow");
}
        });
adView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
            @Override
public void onLayoutChange(View view, int i, int i1, int i2, int i3, int i4, int i5, int i6, int i7) {
                LogUtils.logLocalD("廣告:onLayoutChange");
}
        });
MediaView mediaView = adView.findViewById(R.id.ad_media);
ImageView mainImageView = adView.findViewById(R.id.ad_image);
// Apps can check the VideoController's hasVideoContent property to determine if the
        // NativeAppInstallAd has a video asset.
if (vc.hasVideoContent()) {
            adView.setMediaView(mediaView);
mainImageView.setVisibility(View.GONE);
//            videoStatus.setText(String.format(Locale.getDefault(),
//                    "Video status: Ad contains a %.2f:1 video asset.",
//                    vc.getAspectRatio()));
} else {
            adView.setImageView(mainImageView);
mediaView.setVisibility(View.GONE);
// At least one image is guaranteed.
try{
                List<NativeAd.Image> images = nativeAd.getImages();
mainImageView.setImageDrawable(images.get(0).getDrawable());
}catch (Exception e){
                e.printStackTrace();
}

//            refresh.setEnabled(true);
//            videoStatus.setText("Video status: Ad does not contain a video asset.");
}

        adView.setHeadlineView(adView.findViewById(R.id.ad_headline));
adView.setBodyView(adView.findViewById(R.id.ad_body));
adView.setCallToActionView(adView.findViewById(R.id.ad_call_to_action));
adView.setIconView(adView.findViewById(R.id.ad_app_icon));
adView.setPriceView(adView.findViewById(R.id.ad_price));
adView.setStarRatingView(adView.findViewById(R.id.ad_stars));
adView.setStoreView(adView.findViewById(R.id.ad_store));
adView.setAdvertiserView(adView.findViewById(R.id.ad_advertiser));
// Some assets are guaranteed to be in every UnifiedNativeAd.
((TextView) adView.getHeadlineView()).setText(nativeAd.getHeadline());//title 題目
((TextView) adView.getBodyView()).setText(nativeAd.getBody());//內容
((TextView) adView.getCallToActionView()).setText(nativeAd.getCallToAction());//按鈕文字內容 ps:訪問網站
        // These assets aren't guaranteed to be in every UnifiedNativeAd, so it's important to
        // check before trying to display them.
if (nativeAd.getIcon() == null) {//廣告app圖示  ps:facebook app
adView.getIconView().setVisibility(View.GONE);
} else {
            ((CircleImageView) adView.getIconView())
                    .setImageDrawable(nativeAd.getIcon().getDrawable());
adView.getIconView().setVisibility(View.VISIBLE);
}

        if (nativeAd.getPrice() == null) {//未知
adView.getPriceView().setVisibility(View.GONE);
} else {
            adView.getPriceView().setVisibility(View.GONE);
((TextView) adView.getPriceView()).setText(nativeAd.getPrice());
}

        if (nativeAd.getStore() == null) {//未知
adView.getStoreView().setVisibility(View.GONE);
} else {
            adView.getStoreView().setVisibility(View.GONE);
((TextView) adView.getStoreView()).setText(nativeAd.getStore());
}

        if (nativeAd.getStarRating() == null) {//評價 --星星圖示
adView.getStarRatingView().setVisibility(View.GONE);
} else {
            ((RatingBar) adView.getStarRatingView())
                    .setRating(nativeAd.getStarRating().floatValue());
adView.getStarRatingView().setVisibility(View.VISIBLE);
}

        if (nativeAd.getAdvertiser() == null) {//廣告商 ps:facebook
adView.getAdvertiserView().setVisibility(View.GONE);
} else {
            ((TextView) adView.getAdvertiserView()).setText(nativeAd.getAdvertiser());
adView.getAdvertiserView().setVisibility(View.VISIBLE);
}

        adView.setNativeAd(nativeAd);
unifiedNativeAdViews.add(adView);
}

這麼多?不用看了。也是去谷歌給出的demo裡面copy的,然後自己改改,繫結檢視,就自己看了。可以自定義你想要的廣告介面。還是很方便的,其中有一個mediaView和ImageView的切換,這裡如果拿到的是視訊的話就判斷一下用mediaView,這裡還是很好理解的,demo裡面判斷都給你寫好了,不用操心。好了,我還把谷歌的demo地址給出來:

https://github.com/googleads/googleads-mobile-android-examples/tree/master/java/admob/NativeAdvancedExample


這裡,demo裡面沒有,大概意思也猜的到,就是給adview新增監聽的,比如廣告出現了,廣告隱藏了,被滑動了。這些,事件的返回,但是,沒有點選事件的返回,對的沒錯,沒有找到有這個事件的監聽。試過很多方法也拿不到,最後我還是就放棄了,2333。

unifiedNativeAdViews.add(adView);一波操作完了之後,然後我就把我弄好的adView存到了我的list裡面,前面說到的,判斷我的廣告拿全了之後,我就通過監聽把list返回給了呼叫方,然後就完事兒了。接入還是很簡單的,就具體說下可能遇到的坑。


先是說一下佈局,佈局是要由谷歌給的容器包裹起來,不然是會報錯的。

然後就是網路的問題。多條廣告請求的時候尤為重要,需要開vpn不然的話不容易拿到廣告,測試廣告也是如此,然後就是有時候谷歌就是不會給你返回廣告的,你可以改改你的請求條數,來不斷的試一下。

好了,完事兒。看起來好像遇到的坑並不多,但是英文不好,又要去慢慢翻英文的文件的時候,還是挺惱火的,還各種問題,比如換成自己id就拿不到廣告,就迷惑了很久,最後才發現,emmm,真的是有點尷尬,如果讀者還有什麼問題,可以問我,可以一起討論學習。