https://blog.csdn.net/unreliable_narrator/article/details/106637700
一、SDK接入
參考官方接入文檔,基於穿山甲版本號: 3.1.0.0
導入 aar 及 SDK 依賴的 jar 包
將本 SDK 壓縮包內的 open_ad_sdk.aar 復制到 Application Module/libs 文件夾(沒有的話須手動創建), 並將以下代碼添加到您 app 的
repositories {
flatDir {
dirs 'libs'
}
}
depedencies {
compile(name: 'open_ad_sdk', ext: ‘aar')
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
添加權限
穿山甲SDK建議您添加下述權限,並建議在您的隱私協議中向開發者聲明穿山甲SDK會獲取下述權限並應用於廣告投放。
<!--必要權限-->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!--可選權限-->
<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"/>
<!--可選,穿山甲提供“獲取地理位置權限”和“不給予地理位置權限,開發者傳入地理位置參數”兩種方式上報用戶位置,兩種方式均可不選,添加位置權限或參數將幫助投放定位廣告-->
<!--請注意:無論通過何種方式提供給穿山甲用戶地理位置,均需向用戶聲明地理位置權限將應用於穿山甲廣告投放,穿山甲不強制獲取地理位置信息-->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!-- 如果有視頻相關的廣告且使用textureView播放,請務必添加,否則黑屏 -->
<uses-permission android:name="android.permission.WAKE_LOCK" />
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
注意:穿山甲SDK不強制獲取以上權限,即使沒有獲取可選權限SDK也能正常運行;獲取以上權限將幫助穿山甲優化投放廣告精准度和用戶的交互體驗,提高eCPM。
為獲取更好的廣告推薦效果,以及提高激勵視頻廣告、下載類廣告等填充率,建議在廣告請求前,合適的時機調用 SDK 提供的方法,如在用戶第一次啟動您的 app 后的主界面時調用如下方法:
TTAdManager接口中的方法,context可以是Activity或Application
void requestPermissionIfNecessary(Context context);
- 1
- 2
- 3
適配 Android7.0 及以上
如果您的應用需要在 Android7.0 及以上環境運行,請在 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>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
在 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>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
為了適配下載和安裝相關功能,在工程中引用的包 com.android.support:support-v4:24.2.0
使用24.2.0以及以上版本。
- 1
- 2
provider 配置
注意:單進程或多進程都必須配置
<provider
android:name="com.bytedance.sdk.openadsdk.multipro.TTMultiProvider"
android:authorities="${applicationId}.TTMultiProvider"
android:exported="false" />
- 1
- 2
- 3
- 4
代碼混淆配置
如果您需要使用 proguard 混淆代碼,需確保不要混淆 SDK 的代碼。 請在 proguard.cfg 文件(或其他混淆文件)尾部添加如下配置:
-keep class com.bytedance.sdk.openadsdk.** { *; }
-keep public interface com.bytedance.sdk.openadsdk.downloadnew.** {*;}
-keep class com.pgl.sys.ces.* {*;}
- 1
- 2
- 3
- 4
注意
-
SDK 代碼被混淆后會導致廣告無法展現或者其它異常。
-
本 SDK 最低支持 Android4.0 (API Level 14) 及以上版本。
-
targetSdkVersion API 23及以上,需要動態獲取權限,所以請確保調用本SDK的任何接口前,已經申請到了SDK要求的所有權限,否則SDK部分特性可能受限。
-
SDK中使用的so文件支持五種架構:x86,x86_64,armeabi,armeabi-v7a,arm64-v8a 如果您應用中支持的架構超出這 五種,請在build.gradle中使用abiFilters選擇支持的架構。
ndk { // 設置支持的 SO 庫構架,注意這里要根據你的實際情況來設置
abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64', 'armeabi'
}
- 1
- 2
- 3
SDK 初始化配置
開發者需要在 Application#onCreate()方法中調用以下代碼來初始化穿山甲 sdk。 目前 sdk 已支持多進程,必須在所有進程都初始化!
public class DemoApplication extends Application {
public static String PROCESS_NAME_XXXX = "process_name_xxxx";
@Override
public void onCreate() {
super.onCreate();
//強烈建議在應用對應的Application#onCreate()方法中調用,避免出現content為null的異常
TTAdSdk.init(context,
new TTAdConfig.Builder()
.appId("5001121")
.useTextureView(false) //使用TextureView控件播放視頻,默認為SurfaceView,當有SurfaceView沖突的場景,可以使用TextureView
.appName("APP測試媒體")
.titleBarTheme(TTAdConstant.TITLE_BAR_THEME_DARK)
.allowShowNotify(true) //是否允許sdk展示通知欄提示
.allowShowPageWhenScreenLock(true) //是否在鎖屏場景支持展示廣告落地頁
.debug(true) //測試階段打開,可以通過日志排查問題,上線時去除該調用
.directDownloadNetworkType(TTAdConstant.NETWORK_STATE_WIFI, TTAdConstant.NETWORK_STATE_4G) //允許直接下載的網絡狀態集合
.supportMultiProcess(false) //是否支持多進程,true支持
//.httpStack(new MyOkStack3())//自定義網絡庫,demo中給出了okhttp3版本的樣例,其余請自行開發或者咨詢工作人員。
.build());
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
初始化接口說明
/**
*穿山甲sdk初始化入口
*
* @param context 必須是application context
* @param config 初始化配置信息,必要參數
* @return TTAdManager實例
*/
public static TTAdManager init(Context context, TTAdConfig config);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
初始化配置參數說明:
public static class TTAdConfig.Builder {
private String mAppId;// 必選參數,設置應用的AppId
private String mAppName;// 必選參數,設置應用名稱
private boolean mIsPaid = false;// 可選參數,設置是否為計費用戶:true計費用戶、false非計費用戶。默認為false非計費用戶
private int mGender = TTAdConstant.GENDER_UNKNOWN;// 可選參數,設置用戶性別。默認為未知TTAdConstant#GENDER_UNKNOWN
private int mAge;// 可選參數,設置用戶年齡 **須大於0**
private String mKeywords;// 可選參數,設置用戶畫像的關鍵詞列表 **不能超過為1000個字符**
private String mData;// 可選參數,設置額外的用戶信息 **不能超過為1000個字符**
private int mTitleBarTheme = TTAdConstant.TITLE_BAR_THEME_LIGHT;// 可選參數,設置落地頁主題,默認為TTAdConstant#TITLE_BAR_THEME_LIGHT
private boolean mAllowShowNotify = true;// 可選參數,設置是否允許SDK彈出通知:true允許、false禁止。默認為true允許
private boolean mIsDebug = false;// 可選參數,是否打開debug調試信息輸出:true打開、false關閉。默認false關閉
private boolean mAllowShowPageWhenScreenLock = false;// 可選參數,設置是否允許落地頁出現在鎖屏上面:true允許、false禁止。默認為false禁止
private int[] mDirectDownloadNetworkType;
private boolean mIsUseTextureView = false;// 可選參數,設置是否使用texture播放視頻:true使用、false不使用。默認為false不使用(使用的是surface)
private boolean mIsSupportMultiProcess = false;// 可選參數,設置是否支持多進程:true支持、false不支持。默認為false不支持
private IHttpStack mHttpStack;//可選參數,設置外部網絡請求,默認為urlconnection
private boolean mIsAsyncInit = false;//是否異步初始化sdk
private TTCustomController mCustomController;//可選參數,可以設置隱私信息控制開關
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
二、加載廣告
創建廣告插槽。
-
構建TTAdManager對象
TTAdManager對象為整個SDK的入口接口,可用於廣告獲取、權限請求、版本號獲取
TTAdManager ttAdManager = TTAdManagerHolder.get(); -
申請部分權限 (建議每次廣告對象加載之后都需要申請一次 ps:開屏視頻不需要)
TTAdManagerHolder.get().requestPermissionIfNecessary(this); -
創建TTAdNative對象(用於調用廣告請求接口)
TTAdNative mTTAdNative = ttAdManager.createAdNative(getApplicationContext()); -
構建AdSlot對象(廣告插槽),具體構建參數根據文檔來。
AdSlot adSlot = new AdSlot.Builder()
.setCodeId("廣告位id") //必選參數 設置您的CodeId
.setSupportDeepLink(true)
.setAdCount(1) //請求廣告數量為1到3條
.setExpressViewAcceptedSize(expressViewWidth,expressViewHeight) //期望模板廣告view的size,單位dp
.setImageAcceptedSize(350 ,500 )//這個參數設置即可,不影響模板廣告的size
.build();
- 1
- 2
- 3
- 4
- 5
- 6
- 7
在創建廣告插槽的時候有一個必選參數廣告位id,那么這個值是從哪里來的,又有什么作用呢?
廣告類型
想要了解廣告位id從哪里來的,我們首先需要打開穿山甲廣告的管理后台:
創建新的應用:
建議為測試集成完畢后再把應用及對應的代碼位改成正式狀態。
應用ID 是對應demo中的APPID。
創建新的代碼位:
廣告位ID 對應demo中的CodeId。就是一個標識用來加載不同種類的廣告類型。
應用ID和代碼位ID是對應關系 一個應用可以對應多個代碼位ID。
注意:新建的廣告CodeId,要等一會兒使用,否則就會出現ID無效。
點擊新創建的應用的新建代碼位:
可以看到有多種樣式的廣告進行選擇。
例如我想要創建一個banner廣告,則進入bannner廣告創建頁面。
可以看到對應的選項。
原生、自渲染和模板渲染的區別
- 自渲染和原生渲染(已經被廢棄了):
現在已經被廢棄了,簡單來說,就是穿山甲返回廣告的子元素,如標題,描述,圖片等,你自己拼裝成自己喜歡的界面展示。 - 模板渲染廣告:
目前申請的廣告樣式只有這一類,廣告用webview(網頁)展示。接入者在穿山甲后台,選擇自己需要的樣式進行顯示就可以,如:上圖下文,左圖右文等多種形式。也就是穿山甲會直接返回一個view 不支持獲取view的信息 開發者直接展示view即可。
三、展示廣告
開屏廣告
開屏廣告建議為用戶在進入 App 時展示的全屏廣告。開屏廣告為一個 View,寬高默認為 match_parent,注意開屏廣告 view:width >=70%屏幕寬;height >=50%屏幕高 ,否則會影響計費。
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);
//設置不開啟開屏廣告倒計時功能以及不顯示跳過按鈕,如果這么設置,您需要自定義倒計時邏輯
//ad.setNotAllowSdkCountdown();
} else {
dumpNextPage();
}
//設置SplashView的交互監聽器
ad.setSplashInteractionListener(new TTSplashAd.AdInteractionListener() {
@Override
public void onAdClicked(View view, int type) {
Log.d(TAG, "onAdClicked開屏廣告點擊");
}
@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開屏廣告倒計時結束");
dumpNextPage();
}
});
//廣告交互類型未下載廣告,需要設置廣告下載監聽
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);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
信息流廣告
信息流廣告即app推薦頁/詳情頁中的原生圖文及視頻廣告,主要特點是精准算法推薦、原生體驗對用戶干擾低。
/**
* 加載feed廣告
*/
private fun loadListAd() {
val mTTAdNative = TTAdManagerHolder.get().createAdNative(this)
TTAdManagerHolder.get().requestPermissionIfNecessary(this)
//創建feed廣告請求類型參數AdSlot,具體參數含義參考文檔
val adSlot = AdSlot.Builder()
.setCodeId("945230381")
.setSupportDeepLink(true)
.setExpressViewAcceptedSize(250f, 300f) //期望模板廣告view的size,單位dp
.setAdCount(3) //請求廣告數量為1到3條
.build()
//step5:請求廣告,調用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", "廣告被點擊")
}
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()
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
注:模板類型的代碼位在設置AdSlot廣告對象的時候一定要設置該方法setExpressViewAcceptedSize
注:在廣告加載展示完畢后 在Activity的onDestroy方法中把廣告對象置為null
banner
Banner廣告可以在您設定刷新時間后自動刷新。也就是說,即使用戶停留在同一個屏幕上,他們也會 每隔一段時間就看到新的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) //請求廣告數量為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")
}
})
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
四、注意事項
-
為何廣告轉化率低?
發布前,一定要測試整個廣告的展示,下載,安裝,激活流程。如果廣告能展示就發布了,完全沒測試廣告后續流程,就會導致廣告的CPM非常低。廣告cpm依賴廣告展示后的后續轉化,如:點擊,下載,安裝,激活,注冊,充值等。 -
存儲權限,imei權限,定位權限是必須的嗎?
3個權限都不是必須的,但是如果有的話,大大提高廣告的Ecpm。
有了存儲權限,就可以推下載類的廣告;
有了imei權限,就能跟蹤后期轉化;
有了定位權限,就可以推更加精准的廣告。 -
如何屏蔽競品廣告?
在穿山甲后台可設置。