Android 穿山甲廣告聯(lián)盟接入

一、SDK接入

參考官方接入文檔,基于穿山甲版本號: 3.1.0.0
導(dǎo)入 aar 及 SDK 依賴的 jar 包

將本 SDK 壓縮包內(nèi)的 open_ad_sdk.aar 復(fù)制到 Application Module/libs 文件夾(沒有的話須手動創(chuàng)建), 并將以下代碼添加到您 app 的

repositories {
    flatDir {
        dirs 'libs'
    }
}
depedencies {
    compile(name: 'open_ad_sdk', ext: ‘a(chǎn)ar')
}
添加權(quán)限

穿山甲SDK建議您添加下述權(quán)限,并建議在您的隱私協(xié)議中向開發(fā)者聲明穿山甲SDK會獲取下述權(quán)限并應(yīng)用于廣告投放。

<!--必要權(quán)限-->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

<!--可選權(quán)限-->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
<uses-permission android:name="android.permission.GET_TASKS"/>

<!--可選,穿山甲提供“獲取地理位置權(quán)限”和“不給予地理位置權(quán)限,開發(fā)者傳入地理位置參數(shù)”兩種方式上報用戶位置,兩種方式均可不選,添加位置權(quán)限或參數(shù)將幫助投放定位廣告-->
<!--請注意:無論通過何種方式提供給穿山甲用戶地理位置,均需向用戶聲明地理位置權(quán)限將應(yīng)用于穿山甲廣告投放,穿山甲不強(qiáng)制獲取地理位置信息-->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

<!-- 如果有視頻相關(guān)的廣告且使用textureView播放,請務(wù)必添加,否則黑屏 -->
<uses-permission android:name="android.permission.WAKE_LOCK" />

注意:穿山甲SDK不強(qiáng)制獲取以上權(quán)限,即使沒有獲取可選權(quán)限SDK也能正常運(yùn)行;獲取以上權(quán)限將幫助穿山甲優(yōu)化投放廣告精準(zhǔn)度和用戶的交互體驗(yàn),提高eCPM。

為獲取更好的廣告推薦效果,以及提高激勵視頻廣告、下載類廣告等填充率,建議在廣告請求前,合適的時機(jī)調(diào)用 SDK 提供的方法,如在用戶第一次啟動您的 app 后的主界面時調(diào)用如下方法:

TTAdManager接口中的方法,context可以是Activity或Application
void requestPermissionIfNecessary(Context context);

適配 Android7.0 及以上

如果您的應(yīng)用需要在 Android7.0 及以上環(huán)境運(yùn)行,請?jiān)?AndroidManifest 中添加如下代碼:

<provider
 android:name="com.bytedance.sdk.openadsdk.TTFileProvider"
 android:authorities="${applicationId}.TTFileProvider"
 android:exported="false"
 android:grantUriPermissions="true">
<meta-data
     android:name="android.support.FILE_PROVIDER_PATHS"
     android:resource="@xml/file_paths" />
</provider>

在 res/xml 目錄下,新建一個 xml 文件 file_paths,在該文件中添加如下代碼:

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <external-path name="tt_external_root" path="." />
    <external-path name="tt_external_download" path="Download" />
    <external-files-path name="tt_external_files_download" path="Download" />
    <files-path name="tt_internal_file_download" path="Download" />
    <cache-path name="tt_internal_cache_download" path="Download" />
</paths>
為了適配下載和安裝相關(guān)功能,在工程中引用的包 com.android.support:support-v4:24.2.0
使用24.2.0以及以上版本。
provider 配置

注意:單進(jìn)程或多進(jìn)程都必須配置

<provider
    android:name="com.bytedance.sdk.openadsdk.multipro.TTMultiProvider"
    android:authorities="${applicationId}.TTMultiProvider"
    android:exported="false" />
代碼混淆配置

如果您需要使用 proguard 混淆代碼,需確保不要混淆 SDK 的代碼。 請?jiān)?proguard.cfg 文件(或其他混淆文件)尾部添加如下配置:

-keep class com.bytedance.sdk.openadsdk.** { *; }
-keep public interface com.bytedance.sdk.openadsdk.downloadnew.** {*;}
-keep class com.pgl.sys.ces.* {*;}

注意

  • SDK 代碼被混淆后會導(dǎo)致廣告無法展現(xiàn)或者其它異常。

  • 本 SDK 最低支持 Android4.0 (API Level 14) 及以上版本。

  • targetSdkVersion API 23及以上,需要動態(tài)獲取權(quán)限,所以請確保調(diào)用本SDK的任何接口前,已經(jīng)申請到了SDK要求的所有權(quán)限,否則SDK部分特性可能受限。

  • SDK中使用的so文件支持五種架構(gòu):x86,x86_64,armeabi,armeabi-v7a,arm64-v8a 如果您應(yīng)用中支持的架構(gòu)超出這 五種,請?jiān)赽uild.gradle中使用abiFilters選擇支持的架構(gòu)。

 ndk { // 設(shè)置支持的 SO 庫構(gòu)架,注意這里要根據(jù)你的實(shí)際情況來設(shè)置 
        abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64', 'armeabi'
      }
SDK 初始化配置

開發(fā)者需要在 Application#onCreate()方法中調(diào)用以下代碼來初始化穿山甲 sdk。 目前 sdk 已支持多進(jìn)程,必須在所有進(jìn)程都初始化!

public class DemoApplication extends Application {
    public static String PROCESS_NAME_XXXX = "process_name_xxxx";

    @Override
    public void onCreate() {
        super.onCreate();

        //強(qiáng)烈建議在應(yīng)用對應(yīng)的Application#onCreate()方法中調(diào)用,避免出現(xiàn)content為null的異常
        TTAdSdk.init(context,
                            new TTAdConfig.Builder()
                                    .appId("5001121")
                                    .useTextureView(false) //使用TextureView控件播放視頻,默認(rèn)為SurfaceView,當(dāng)有SurfaceView沖突的場景,可以使用TextureView
                                    .appName("APP測試媒體")
                                    .titleBarTheme(TTAdConstant.TITLE_BAR_THEME_DARK)
                                    .allowShowNotify(true) //是否允許sdk展示通知欄提示
                                    .allowShowPageWhenScreenLock(true) //是否在鎖屏場景支持展示廣告落地頁
                                    .debug(true) //測試階段打開,可以通過日志排查問題,上線時去除該調(diào)用
                                    .directDownloadNetworkType(TTAdConstant.NETWORK_STATE_WIFI, TTAdConstant.NETWORK_STATE_4G) //允許直接下載的網(wǎng)絡(luò)狀態(tài)集合
                                    .supportMultiProcess(false) //是否支持多進(jìn)程,true支持
                                    //.httpStack(new MyOkStack3())//自定義網(wǎng)絡(luò)庫,demo中給出了okhttp3版本的樣例,其余請自行開發(fā)或者咨詢工作人員。
                                    .build());

    }
}
初始化接口說明
    /**
     *穿山甲sdk初始化入口
     *
     * @param context 必須是application context
     * @param config  初始化配置信息,必要參數(shù)
     * @return TTAdManager實(shí)例
     */
    public static TTAdManager init(Context context, TTAdConfig config);
初始化配置參數(shù)說明:
    public static class TTAdConfig.Builder {
        private String mAppId;// 必選參數(shù),設(shè)置應(yīng)用的AppId
        private String mAppName;// 必選參數(shù),設(shè)置應(yīng)用名稱
        private boolean mIsPaid = false;// 可選參數(shù),設(shè)置是否為計(jì)費(fèi)用戶:true計(jì)費(fèi)用戶、false非計(jì)費(fèi)用戶。默認(rèn)為false非計(jì)費(fèi)用戶
        private int mGender = TTAdConstant.GENDER_UNKNOWN;// 可選參數(shù),設(shè)置用戶性別。默認(rèn)為未知TTAdConstant#GENDER_UNKNOWN
        private int mAge;// 可選參數(shù),設(shè)置用戶年齡 **須大于0**
        private String mKeywords;// 可選參數(shù),設(shè)置用戶畫像的關(guān)鍵詞列表 **不能超過為1000個字符**
        private String mData;// 可選參數(shù),設(shè)置額外的用戶信息 **不能超過為1000個字符**
        private int mTitleBarTheme = TTAdConstant.TITLE_BAR_THEME_LIGHT;// 可選參數(shù),設(shè)置落地頁主題,默認(rèn)為TTAdConstant#TITLE_BAR_THEME_LIGHT
        private boolean mAllowShowNotify = true;// 可選參數(shù),設(shè)置是否允許SDK彈出通知:true允許、false禁止。默認(rèn)為true允許
        private boolean mIsDebug = false;// 可選參數(shù),是否打開debug調(diào)試信息輸出:true打開、false關(guān)閉。默認(rèn)false關(guān)閉
        private boolean mAllowShowPageWhenScreenLock = false;// 可選參數(shù),設(shè)置是否允許落地頁出現(xiàn)在鎖屏上面:true允許、false禁止。默認(rèn)為false禁止
        private int[] mDirectDownloadNetworkType;
        private boolean mIsUseTextureView = false;// 可選參數(shù),設(shè)置是否使用texture播放視頻:true使用、false不使用。默認(rèn)為false不使用(使用的是surface)
        private boolean mIsSupportMultiProcess = false;// 可選參數(shù),設(shè)置是否支持多進(jìn)程:true支持、false不支持。默認(rèn)為false不支持
        private IHttpStack mHttpStack;//可選參數(shù),設(shè)置外部網(wǎng)絡(luò)請求,默認(rèn)為urlconnection
        private boolean mIsAsyncInit = false;//是否異步初始化sdk
        private TTCustomController mCustomController;//可選參數(shù),可以設(shè)置隱私信息控制開關(guān)
    }

二、加載廣告

創(chuàng)建廣告插槽。

  • 構(gòu)建TTAdManager對象
    TTAdManager對象為整個SDK的入口接口,可用于廣告獲取、權(quán)限請求、版本號獲取
TTAdManager ttAdManager = TTAdManagerHolder.get();
  • 申請部分權(quán)限 (建議每次廣告對象加載之后都需要申請一次 ps:開屏視頻不需要)
TTAdManagerHolder.get().requestPermissionIfNecessary(this);
  • 創(chuàng)建TTAdNative對象(用于調(diào)用廣告請求接口)
TTAdNative mTTAdNative = ttAdManager.createAdNative(getApplicationContext());
  • 構(gòu)建AdSlot對象(廣告插槽),具體構(gòu)建參數(shù)根據(jù)文檔來。
     AdSlot adSlot = new AdSlot.Builder()
             .setCodeId("廣告位id") //必選參數(shù) 設(shè)置您的CodeId
             .setSupportDeepLink(true)
             .setAdCount(1) //請求廣告數(shù)量為1到3條
             .setExpressViewAcceptedSize(expressViewWidth,expressViewHeight) //期望模板廣告view的size,單位dp
             .setImageAcceptedSize(350 ,500 )//這個參數(shù)設(shè)置即可,不影響模板廣告的size
             .build();

在創(chuàng)建廣告插槽的時候有一個必選參數(shù)廣告位id,那么這個值是從哪里來的,又有什么作用呢?

廣告類型

想要了解廣告位id從哪里來的,我們首先需要打開穿山甲廣告的管理后臺:

創(chuàng)建新的應(yīng)用:

建議為測試集成完畢后再把應(yīng)用及對應(yīng)的代碼位改成正式狀態(tài)。
應(yīng)用ID 是對應(yīng)demo中的APPID。

創(chuàng)建新的代碼位:

廣告位ID 對應(yīng)demo中的CodeId。就是一個標(biāo)識用來加載不同種類的廣告類型。
應(yīng)用ID和代碼位ID是對應(yīng)關(guān)系 一個應(yīng)用可以對應(yīng)多個代碼位ID。
注意:新建的廣告CodeId,要等一會兒使用,否則就會出現(xiàn)ID無效。

點(diǎn)擊新創(chuàng)建的應(yīng)用的新建代碼位:

代碼位

可以看到有多種樣式的廣告進(jìn)行選擇。

例如我想要創(chuàng)建一個banner廣告,則進(jìn)入bannner廣告創(chuàng)建頁面。

可以看到對應(yīng)的選項(xiàng)。

原生、自渲染和模板渲染的區(qū)別
  • 自渲染和原生渲染(已經(jīng)被廢棄了):
    現(xiàn)在已經(jīng)被廢棄了,簡單來說,就是穿山甲返回廣告的子元素,如標(biāo)題,描述,圖片等,你自己拼裝成自己喜歡的界面展示。
  • 模板渲染廣告:
    目前申請的廣告樣式只有這一類,廣告用webview(網(wǎng)頁)展示。接入者在穿山甲后臺,選擇自己需要的樣式進(jìn)行顯示就可以,如:上圖下文,左圖右文等多種形式。也就是穿山甲會直接返回一個view 不支持獲取view的信息 開發(fā)者直接展示view即可。

三、展示廣告

開屏廣告

開屏廣告建議為用戶在進(jìn)入 App 時展示的全屏廣告。開屏廣告為一個 View,寬高默認(rèn)為 match_parent,注意開屏廣告 view:width >=70%屏幕寬;height >=50%屏幕高 ,否則會影響計(jì)費(fèi)。


 TTAdNative adNative = TTAdManagerHolder.INSTANCE.get().createAdNative(this);

        AdSlot adSlot = new AdSlot.Builder()
                .setCodeId(CodeId)
                .setSupportDeepLink(true)
                .setImageAcceptedSize(DisplayUtils.getScreenWidth(this), DisplayUtils.getScreenHeight(this))
                .build();
        //加載
        adNative.loadSplashAd(adSlot, new TTAdNative.SplashAdListener() {
            @Override
            public void onError(int code, String message) {
                Log.d(TAG, "開屏廣告請求失敗" + message);
                dumpNextPage();
            }

            @Override
            public void onTimeout() {
                Log.d(TAG, "開屏廣告請求超時");
                dumpNextPage();
            }

            @Override
            public void onSplashAdLoad(TTSplashAd ad) {
                Log.d(TAG, "開屏廣告請求成功");
                if (ad == null) {
                    dumpNextPage();
                    return;
                }
                //獲取SplashView
                View view = ad.getSplashView();
                if (view != null && videoContainer != null && !LaunchActivity.this.isFinishing()) {
                    videoContainer.removeAllViews();
                    //把SplashView 添加到ViewGroup中,注意開屏廣告view:width >=70%屏幕寬;height >=50%屏幕高
                    videoContainer.addView(view);
                    //設(shè)置不開啟開屏廣告倒計(jì)時功能以及不顯示跳過按鈕,如果這么設(shè)置,您需要自定義倒計(jì)時邏輯
                    //ad.setNotAllowSdkCountdown();
                } else {
                    dumpNextPage();
                }

                //設(shè)置SplashView的交互監(jiān)聽器
                ad.setSplashInteractionListener(new TTSplashAd.AdInteractionListener() {
                    @Override
                    public void onAdClicked(View view, int type) {
                        Log.d(TAG, "onAdClicked開屏廣告點(diǎn)擊");
                    }

                    @Override
                    public void onAdShow(View view, int type) {
                        Log.d(TAG, "onAdShow開屏廣告展示");
                    }

                    @Override
                    public void onAdSkip() {
                        Log.d(TAG, "onAdSkip開屏廣告跳過");
                        dumpNextPage();
                    }

                    @Override
                    public void onAdTimeOver() {
                        Log.d(TAG, "onAdTimeOver開屏廣告倒計(jì)時結(jié)束");
                        dumpNextPage();
                    }
                });
                //廣告交互類型未下載廣告,需要設(shè)置廣告下載監(jiān)聽
                if (ad.getInteractionType() == TTAdConstant.INTERACTION_TYPE_DOWNLOAD) {
                    ad.setDownloadListener(new TTAppDownloadListener() {
                        boolean hasShow = false;

                        @Override
                        public void onIdle() {
                        }

                        @Override
                        public void onDownloadActive(long totalBytes, long currBytes, String fileName, String appName) {
                            if (!hasShow) {
                                Log.d(TAG, "開屏廣告下載中");
                                hasShow = true;
                            }
                        }

                        @Override
                        public void onDownloadPaused(long totalBytes, long currBytes, String fileName, String appName) {
                            Log.d(TAG, "開屏廣告下載暫停");
                        }

                        @Override
                        public void onDownloadFailed(long totalBytes, long currBytes, String fileName, String appName) {
                            Log.d(TAG, "開屏廣告下載失敗");
                        }

                        @Override
                        public void onDownloadFinished(long totalBytes, String fileName, String appName) {
                            Log.d(TAG, "開屏廣告下載完成");
                        }

                        @Override
                        public void onInstalled(String fileName, String appName) {
                            Log.d(TAG, "開屏廣告安裝完成");
                        }
                    });
                }
            }
        }, AD_TIME_OUT);
信息流廣告

信息流廣告即app推薦頁/詳情頁中的原生圖文及視頻廣告,主要特點(diǎn)是精準(zhǔn)算法推薦、原生體驗(yàn)對用戶干擾低。

    /**
     * 加載feed廣告
     */
    private fun loadListAd() {
        val mTTAdNative = TTAdManagerHolder.get().createAdNative(this)
        TTAdManagerHolder.get().requestPermissionIfNecessary(this)
        //創(chuàng)建feed廣告請求類型參數(shù)AdSlot,具體參數(shù)含義參考文檔
        val adSlot = AdSlot.Builder()
            .setCodeId("945230381")
            .setSupportDeepLink(true)
            .setExpressViewAcceptedSize(250f, 300f) //期望模板廣告view的size,單位dp
            .setAdCount(3) //請求廣告數(shù)量為1到3條
            .build()
        //step5:請求廣告,調(diào)用feed廣告異步請求接口,加載到廣告后,拿到廣告素材自定義渲染
        mTTAdNative.loadNativeExpressAd(adSlot, object : TTAdNative.NativeExpressAdListener {
            override fun onError(code: Int, message: String) {
                Log.e("loadFeedAd", "code: : $code  message :$message")
            }

            override fun onNativeExpressAdLoad(ads: List<TTNativeExpressAd>?) {
                if (ads == null || ads.isEmpty()) {
                    Log.i("loadFeedAd", "on FeedAdLoaded: ad is null!")

                    return
                }
                Log.i("loadFeedAd", "FeedAdLoaded: ad is success===============" + ads.size)
                bindAdListener(ads)
            }
        })
    }

    private fun bindAdListener(ads: List<TTNativeExpressAd>) {
        for (ad in ads) {
            ad.setExpressInteractionListener(object :
                TTNativeExpressAd.ExpressAdInteractionListener {
                override fun onAdClicked(view: View, type: Int) {
                    Log.i("loadFeedAd", "廣告被點(diǎn)擊")
                }

                override fun onAdShow(view: View, type: Int) {
                    Log.i("loadFeedAd", "廣告展示")
                }

                override fun onRenderFail(view: View, msg: String, code: Int) {
                    Log.i("loadFeedAd", "$msg code:$code")
                }

                override fun onRenderSuccess(view: View, width: Float, height: Float) {
                    //返回view的寬高 單位 dp
                    Log.i("loadFeedAd", "渲染成功")
                }
            })
            ad.render()
        }
    }

注:模板類型的代碼位在設(shè)置AdSlot廣告對象的時候一定要設(shè)置該方法setExpressViewAcceptedSize

注:在廣告加載展示完畢后 在Activity的onDestroy方法中把廣告對象置為null

banner

Banner廣告可以在您設(shè)定刷新時間后自動刷新。也就是說,即使用戶停留在同一個屏幕上,他們也會 每隔一段時間就看到新的Banner廣告。

        val mTTAdNative = TTAdManagerHolder.get().createAdNative(this)
        TTAdManagerHolder.get().requestPermissionIfNecessary(this)
        val adSlot = AdSlot.Builder()
            .setCodeId("945230387")
            .setSupportDeepLink(true)
            .setExpressViewAcceptedSize(
                150f,
                300f
            ) //期望模板廣告view的size,單位dp
            .setAdCount(3) //請求廣告數(shù)量為1到3條
            .setNativeAdType(AdSlot.TYPE_BANNER)
            .build()

        mTTAdNative.loadBannerExpressAd(adSlot, object : TTAdNative.NativeExpressAdListener {
            override fun onNativeExpressAdLoad(ads: MutableList<TTNativeExpressAd>?) {
                if (ads == null || ads.isEmpty()) {
                    Log.i("loadFeedAd", "on FeedAdLoaded: ad is null!")
                    return
                }
                Log.i("loadFeedAd", "FeedAdLoaded: ad is success===============" + ads.size)
                bindAdListener(ads)
            }

            override fun onError(code: Int, message: String) {
                Log.i("loadFeedAd", "code: :$code  message :$message")
            }
        })

四、注意事項(xiàng)

  1. 為何廣告轉(zhuǎn)化率低?
    發(fā)布前,一定要測試整個廣告的展示,下載,安裝,激活流程。如果廣告能展示就發(fā)布了,完全沒測試廣告后續(xù)流程,就會導(dǎo)致廣告的CPM非常低。廣告cpm依賴廣告展示后的后續(xù)轉(zhuǎn)化,如:點(diǎn)擊,下載,安裝,激活,注冊,充值等。

  2. 存儲權(quán)限,imei權(quán)限,定位權(quán)限是必須的嗎?
    3個權(quán)限都不是必須的,但是如果有的話,大大提高廣告的Ecpm。
    有了存儲權(quán)限,就可以推下載類的廣告;
    有了imei權(quán)限,就能跟蹤后期轉(zhuǎn)化;
    有了定位權(quán)限,就可以推更加精準(zhǔn)的廣告。

  3. 如何屏蔽競品廣告?
    在穿山甲后臺可設(shè)置。

穿山甲(巨量引擎)廣告接入
Android端穿山甲SDK集成
穿山甲廣告使用秘籍

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容