谷歌原生廣告接入
今天來分享一下谷歌原生廣告的接入的經驗
首先,我先說明一下,谷歌廣告的種類,在建立應用的時候,選擇匯入廣告,然後選擇廣告種類的時候,會看到三個種類,一個是橫幅的,一個是全面視訊的,一個是插屏視屏的,除了那個橫幅的廣告,其餘兩個都是全屏的廣告,但是如果你看過谷歌的廣告開發文件的話,你就會發現有一個原生廣告,這個廣告就像朋友圈,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,真的是有點尷尬,如果讀者還有什麼問題,可以問我,可以一起討論學習。