| 文档版本 | 修订日期 | 修订说明 |
|---|---|---|
| v1.0.0.0 | 2020-04-23 | 创建文档,支持Banner,信息流广告,插屏广告,全屏视频广告,激励视频广告,支持Mintegral Admob Pangle GDT |
| v2.0.0.0 | 2020-07-02 | 支持百度SDK、UnitySDK , 已知问题优化 |
| v2.0.0.1 | 2020-08-19 | 内部版本 |
| v2.0.0.2 | 2020-08-20 | 新增Unity close回调函数处理,优化pangle banner展示 |
| v2.1.0.0 | 2020-07-02 | 支持第三方广告SDK测试功能 |
| v2.2.0.0 | 2020-09-10 | 支持Pangle 普通激励和全屏视频广告;广告位由CodeId更名为AdUnitId;优化弱网环境播放 |
| v2.2.0.1 | 2020-09-27 | 修复GDT splash 已知bug,优化文档demo说明 |
| v2.3.0.0 | 2020-10-16 | 支持快手SDK、SigmobSDK ,已知问题优化优化, 文档demo说明 |
@[toc]
请在Mobrain平台上创建好应用ID和广告位ID。
以下代码添加到您app的build.gradle中:
repositories {
flatDir {
dirs 'libs'
}
}
depedencies {
//mediation_ad_sdk adapter
implementation(name: 'admob_adapter', ext: 'aar')
implementation(name: 'gdt_adapter', ext: 'aar')
implementation(name: 'unity_adapter', ext: 'aar')
implementation(name: 'baiduMobAds_adapter', ext: 'aar')
implementation(name: 'ks_adapter', ext: 'aar')
implementation(name: 'sigmob_adapter', ext: 'aar')
//mediation_ad_sdk
implementation(name: 'mediation_ad_sdk', ext: 'aar')
//Baidu
implementation(name: 'Baidu_MobAds_SDK_v5.85', ext: 'aar')
//unity
implementation(name: 'unity-ads-android-3.4.2', ext: 'aar')
//pangle
implementation(name: 'open_ad_sdk_v2.9.5.8', ext: 'aar')
//GDT
implementation(name: 'GDTSDK.unionNormal.4.174.1044', ext: 'aar')
//admob
implementation 'com.google.android.gms:play-services-ads:17.2.0'
//ks 快手
implementation(name: 'ks_adsdk-2.6.7', ext: 'aar')
//sigmob
implementation(name: 'windAd-2.21.0', ext: 'aar')
}| SDK名称 | SDK版本 |
|---|---|
| Pangle SDK | >= open_ad_sdk_v3.3.0.0 |
| Admob SDK | <= com.google.android.gms:play-services-ads:17.2.0(暂不支持Androidx版本) |
| GDT SDK | >= GDTSDK.unionNormal.4.174.1044 |
| Unity SDK | >= unity-ads-android-3.4.2 |
| Baidu SDK | >= Baidu_MobAds_SDK_v5.85 |
| KS SDK | >= ks_adsdk-2.6.7 |
| Sigmob SDK | >= windAd-2.21.0 |
| SDK名称 | 信息流/原生广告 | Banner广告 | 插屏广告 | 开屏广告 | 激励视频 | 全屏视频 |
|---|---|---|---|---|---|---|
| Pangle SDK | ☑️ | ☑️ | ☑️ | ☑️ | ☑️ | ☑️ |
| Admob SDK | ☑️ | ☑️ | ☑️ | 不支持 | ☑️ | ☑️ |
| GDT SDK | ☑️ | ☑️ | ☑️ | ☑️ | ☑️ | ☑️ |
| Unity SDK | 不支持 | ☑️ | 不支持 | 不支持 | ☑️ | ☑️ |
| Baidu SDK | ☑️ | ☑️ | ☑️ | 不支持 | ☑️ | ☑️ |
| KS SDK | ☑️ | 不支持 | 不支持 | 不支持 | ☑️ | ☑️ |
| Sigmob 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.READ_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.CHANGE_WIFI_STATE" />
<!--可选,Mobrain SDK提供“获取地理位置权限”和“不给予地理位置权限,开发者传入地理位置参数”两种方式上报用户位置,两种方式均可不选,添加位置权限或参数将帮助投放定位广告-->
<!--请注意:无论通过何种方式提供给穿山甲用户地理位置,均需向用户声明地理位置权限将应用于穿山甲广告投放,穿山甲不强制获取地理位置信息-->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!-- 如果有视频相关的广告且使用textureView播放,请务必添加,否则黑屏 -->
<uses-permission android:name="android.permission.WAKE_LOCK" />注意: Mobrain SDK不强制获取以上权限,即使没有获取可选权限SDK也能正常运行;获取以上权限将帮助穿山甲优化投放广告精准度和用户的交互体验,提高eCPM。
//建议在广告请求前,合适的时机调用SDK提供的方法(申请权限)
//TTAdsSdk接口中的方法,context可以是Activity或Application
(app中没有)void requestPermissionIfNecessary(Context context);如果您的应用需要在Anroid7.0及以上环境运行,请在AndroidManifest中添加如下代码:
<!-- Panle SDK TTFileProvider -->
<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>
<!-- GDT targetSDKVersion >= 24时才需要添加这个provider。provider的authorities属性的值为${applicationId}.fileprovider,请开发者根据自己的${applicationId}来设置这个值,例如本例中applicationId为"com.qq.e.union.demo"。 -->
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/gdt_file_path" />
</provider>
<!-- baidu -->
<provider
android:name="com.baidu.mobads.openad.BdFileProvider"
android:authorities="${applicationId}.bd.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/bd_file_paths" />
</provider>在res/xml目录下,新建如下四个xml文件 pangle_file_paths.xml,在该文件中添加如下代码:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<!--为了适配所有路径可以设置 path = "." -->
<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>gdt_file_path.xml
<paths>
<!-- 这个下载路径也不可以修改,必须为com_qq_e_download -->
<external-cache-path
name="gdt_sdk_download_path1"
path="com_qq_e_download" />
<cache-path
name="gdt_sdk_download_path2"
path="com_qq_e_download" />
</paths>bd_file_paths.xml
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-files-path name="bdpath" path="bddownload/" />
<external-path name="bdpathsd" path="bddownload/" />
</paths>sigmob_provider_paths.xml
<paths>
<!-- 这个下载路径不可以修改,SigDownload -->
<external-cache-path
name="SigMob_root"
path="SigDownload" />
<external-path
name="SigMob_root_external"
path="." />
<root-path
name="SigMob_root"
path="." />
</paths>为了适配下载和安装相关功能,在工程中引用的包 com.android.support:support-v4:24.2.0 使用24.2.0以及以上版本。
注意:必须配置该Provider
<provider
android:name="com.bytedance.sdk.openadsdk.multipro.TTMultiProvider"
android:authorities="${applicationId}.TTMultiProvider"
android:exported="false" />admob 广告的provider配置以及APPLICATION_ID配置,APPLICATION_ID需要到Admob后台申请
<provider
android:name="com.google.android.gms.ads.MobileAdsInitProvider"
android:authorities="${applicationId}.mobileadsinitprovider"
tools:replace="android:authorities" />
<!-- Sample AdMob App ID: ca-app-pub-3940256099942544~3347511713 -->
<meta-data
android:name="com.google.android.gms.ads.APPLICATION_ID"
android:value="ca-app-pub-3940256099942544~3347511713" />
<!--This meta-data tag is required to use Google Play Services.-->sigmob
<provider
android:name="com.sigmob.sdk.SigmobFileProvider"
android:authorities="${applicationId}.sigprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/sigmob_provider_paths" />
</provider> <!-- GDT start================== -->
<activity
android:name="com.qq.e.ads.PortraitADActivity"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
android:screenOrientation="portrait" />
<activity
android:name="com.qq.e.ads.LandscapeADActivity"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
android:screenOrientation="landscape" />
<!-- 声明SDK所需要的组件 -->
<service
android:name="com.qq.e.comm.DownloadService"
android:exported="false" />
<!-- 请开发者注意字母的大小写,ADActivity,而不是AdActivity -->
<activity
android:name="com.qq.e.ads.ADActivity"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize" />
<!-- GDT end================== -->
<!-- baidu start================== -->
<activity
android:name="com.baidu.mobads.AppActivity"
android:configChanges="keyboard|keyboardHidden|orientation"
android:theme="@android:style/Theme.Translucent.NoTitleBar" />
<!-- baidu end================== -->
<!-- sigmob end================== -->
<activity
android:name="com.sigmob.sdk.base.common.AdActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:theme="@android:style/Theme.DeviceDefault" />
<!-- sigmob end================== -->本SDK可运行于Android4.0 (API Level 14) 及以上版本。
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="29" />如果开发者声明targetSdkVersion到API 23以上,请确保调用本SDK的任何接口前,已经申请到了SDK要求的所有权限,否则SDK部分特性可能受限。
如果您需要使用proguard混淆代码,需确保不要混淆SDK的代码。 请在proguard.cfg文件(或其他混淆文件)尾部添加如下配置:
#pangle
-keep class com.bytedance.sdk.openadsdk.** { *; }
-keep public interface com.bytedance.sdk.openadsdk.downloadnew.** {*;}
-keep class com.pgl.sys.ces.* {*;}
//聚合混淆
-keep class com.bytedance.msdk.adapter.**{ public *; }
-keep class com.bytedance.msdk.api.** {
public *;
}
-keep class com.bytedance.msdk.base.TTBaseAd{*;}
-keep class com.bytedance.msdk.adapter.TTAbsAdLoaderAdapter{
public *;
protected <fields>;
}
# baidu sdk 不接入baidu sdk可以不引入
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
-keep class com.baidu.mobads.** { *; }
-keep class com.baidu.mobad.** { *; }
-keep class com.bun.miitmdid.core.** {*;}
#ks 快手 不接入ks sdk可以不引入
-keep class com.kwad.sdk.** { *;}
-keep class com.ksad.download.** { *;}
-keep class com.kwai.filedownloader.** { *;}
#sigmob 不接入sigmob sdk可以不引入
-dontwarn android.support.v4.**
-keep class android.support.v4.** { *; }
-keep interface android.support.v4.** { *; }
-keep public class * extends android.support.v4.**
-keep class sun.misc.Unsafe { *; }
-dontwarn com.sigmob.**
-keep class com.sigmob.**.**{*;}
注意: 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’ } packagingOptions { doNotStrip “/armeabi-v7a/.so” doNotStrip “/x86/.so” doNotStrip “/arm64-v8a/.so” doNotStrip “/x86_64/.so” doNotStrip “armeabi.so” }
开发者需要在Application#onCreate()方法中调用以下代码来初始化adMediationsdk。
public class App extends Application {
@Override
public void onCreate() {
super.onCreate();
TTAdManagerHolder.init(this);
}
} /**
* sdk初始化入口
*
* @param context 必须是application context
* @param config 初始化配置信息,必要参数
*/
public static void initialize(Context context, TTAdConfig config) public static class TTAdConfig{
private String mAppId;// 必选参数,设置应用的AppId
private String mAppName;// 必选参数,设置应用名称
private boolean mIsDebug = false;// 可选参数,是否打开debug调试信息输出:true打开、false关闭。默认false关闭
}本SDK支持用户自定义下载删除弹窗、非Wifi下载提示弹窗的主题和落地页titleBar的主题。
用户可在styles.xml里覆盖下载删除弹窗、非Wifi下载提示弹窗的主题 (可选:可以不进行配置)。
<!—配置下载删除弹窗的主题 默认为Theme.DeviceDefault.Light.Dialog" —>
<style name="Theme.Dialog.TTDownload" parent="Theme.AppCompat.Light.Dialog">
<item name="windowNoTitle">android:attr/windowNoTitle</item>
<item name="android:windowBackground">@color/white</item>
</style>
通过TTAdConfig可设置落地页的主题,目前支持落地页无titleBar(TITLE_BAR_THEME_NO_TITLE_BAR)、titleBar亮色主题(TTAdConstant.TITLE_BAR_THEME_LIGHT),titleBar暗色主题(TTAdConstant.TITLE_BAR_THEME_DARK)三种。
private static TTAdConfig buildConfig() {
return new TTAdConfig.Builder()
.appId("5001121")
.appName("APP测试媒体")
.isPanglePaid(false)//是否为计费用户(穿山甲SDK相关配置)
.openDebugLog(true) //测试阶段打开,可以通过日志排查问题,上线时去除该调用
.usePangleTextureView(true) //使用TextureView控件播放视频,默认为SurfaceView,当有SurfaceView冲突的场景,可以使用TextureView
.setPangleTitleBarTheme(TTAdConstant.TITLE_BAR_THEME_DARK) //(穿山甲SDK相关配置)
.allowPangleShowNotify(true) //是否允许sdk展示通知栏提示 (穿山甲SDK相关配置)
.allowPangleShowPageWhenScreenLock(true) //是否在锁屏场景支持展示广告落地页 (穿山甲SDK相关配置)
.setPangleDirectDownloadNetworkType(TTAdConstant.NETWORK_STATE_WIFI, TTAdConstant.NETWORK_STATE_3G) //允许直接下载的网络状态集合 (穿山甲SDK相关配置)
.needPangleClearTaskReset()//特殊机型过滤,部分机型出现包解析失败问题(大部分是三星)。参数取android.os.Build.MODEL (穿山甲SDK相关配置)
.build();
}注:“原生信息流广告”,“Banner广告”,“插屏广告”,“全屏视频广告”,“激励视频广告”(除了开屏广告),需要再config配置下发之后才能进行广告加载
config配置相关方法 相关方法在TTAdsSdk类中
/**
* 注册config回调 ,当config拉取成功执行回调
*
* @param configCallback
*/
public static void registerConfigCallback(SettingConfigCallback configCallback) {
}
/**
* 判断当前是否存在config配置信息
*
* @return
*/
public static boolean configLoadSuccess() {
}
/**
* 移除config回调
*
* @param configCallback
*/
public static void unregisterConfigCallback(SettingConfigCallback configCallback) {
}开发者加载广告时使用方法如下:
/**
* config回调
*/
private TTAdsSdk.SettingConfigCallback mSettingConfigCallback = new TTAdsSdk.SettingConfigCallback() {
@Override
public void configLoad() {
Log.e(TAG, "load ad 在config 回调中加载广告");
loadAd(); //执行广告加载
}
};
private void loadAdWithCallback() {
/**
* 判断当前是否存在config 配置 ,如果存在直接加载广告 ,如果不存在则注册config加载回调
*/
if (TTAdsSdk.configLoadSuccess()) {
Log.e(TAG, "load ad 当前config配置存在,直接加载广告");
loadAd();
} else {
Log.e(TAG, "load ad 当前config配置不存在,正在请求config配置....");
TTAdsSdk.registerConfigCallback(mSettingConfigCallback); //不能使用内部类,否则在ondestory中无法移除该回调
}
}
@Override
protected void onDestroy() {
super.onDestroy();
//注销config回调
TTAdsSdk.unregisterConfigCallback(mSettingConfigCallback);
}AdSlot对象为加载广告时需要设置的广告信息,在加载各种广告时使用。
构建方法:
AdSlot adSlot = new AdSlot.Builder()
// 必选参数 设置广告图片的最大尺寸及期望的图片宽高比,单位Px
// 注:必填字段,期望的图片尺寸,返回尺寸可能有差异(模板广告需要设置期望个性化模板广告的大小,单位px,代码位是否属于个性化模板广告)
.setImageAdSize(640, 320)
// 可选参数 设置是否支持deeplink
.setSupportDeepLink(true)
// 可选参数,针对信息流广告设置每次请求的广告返回个数,最多支持3个
.setAdCount(2)
//激励视频奖励的名称,针对激励视频参数
.setRewardName("金币")
//激励视频奖励个数
.setRewardAmount(3)
//用户ID,使用激励视频必传参数
//表来标识应用侧唯一用户;若非服务器回调模式或不需sdk透传,可设置为空字符串
.setUserID("user123")
//设置期望视频播放的方向,为TTAdConstant.HORIZONTAL或TTAdConstant.VERTICAL
.setOrientation(orientation)
.build();SDK为接入方提供了可自定义布局的信息流广告,包含大图、小图、组图和视频以及模板等五种基本样式类型(具体的布局摆放可自行定义),及电话拨打、应用下载、跳转到落地页、跳转到浏览器四种交互类型。下面是SDK信息对象TTNativeAd的具体字段说明
下面对TTNativeAd类进行详细说明
public interface TTNativeAd {
/**
* 广告标题
*
* @return
*/
String getTitle();
/**
* 广告内容描述
*
* @return
*/
String getDescription();
/**
* 广告Icon
*
* @return
*/
String getIconUrl();
/**
* 大图URL
*
* @return
*/
String getImageUrl();
/**
* 大图的宽
*
* @return
*/
int getImageWidth();
/**
* 大图的高
*
* @return
*/
int getImageHeight();
/**
* 广告按钮文案
*
* @return
*/
String getActionText();
/**
* 下载类型广告包名
*
* @return
*/
String getPackageName();
/**
* 获取原生view
*/
View getExpressView();
/**
* 广告的下载apk对应的星级
*
* @return
*/
double getStarRating();
/**
* 广告图片
*
* @return
*/
List<String> getImageList();
/**
* 广告来源,一般是广告主名称
*
* @return
*/
String getSource();
/**
* 设置在原生模板广告中使用网盟中dislike
*
* @param activity 创建dislike的context
* @param dislikeCallback dislike选择结果回调
*/
void setDislikeCallback(Activity activity, TTDislikeCallback dislikeCallback);
/**
* 得到dislike dialog 穿山甲SDK使用 原生广告
*
* @param activity 建议传当前activity,否则可能会影响dislike对话框弹出
* @return
*/
TTAdDislike getDislikeDialog(Activity activity);
/**
* 注册点击回调
*
* @param nativeAdListener
*/
void setTTNativeAdListener(TTNativeAdListener nativeAdListener);
/**
* 注册视频回调事件
*
* @param videoListener
*/
void setTTVideoListener(TTVideoListener videoListener);
/**
* 注册事件,计费点
*
* @param container
* @param clickViews
* @param creativeViews
*/
void registerView(@NonNull ViewGroup container, @NonNull List<View> clickViews, @Nullable List<View> creativeViews, TTViewBinder viewBinder);
/**
* 解注册
*/
void unregisterView();
/**
* 动态布局渲染时调用的接口,原生广告该接口无效
*/
void render();
/**
* 广告展示类型,大图,小图,组图,视频
*
* @return
*/
int getAdImageMode();
/**
* 广告交互类型
*
* @return
*/
int getInteractionType();
/**
* 用于判断当前广告是否为模板广告
*
* @return
*/
boolean isExpressAd();
/**
* 是否需要dislike 按钮
*
* @return
*/
boolean hasDislike();
/**
* 暂停
*/
void onPause();
/**
* onResume
*/
void resume();
/**
* 释放资源
*/
void destroy();
}加载信息流广告需要通过TTUnifiedNativeAd类来实现 接入方可调用TTUnifiedNativeAd.loadAd(AdSlot adSlot, TTNativeAdLoadCallback callback)方法异步加载信息流广告,adSlot为用户请求的信息,callback为加载成功、失败的回调监听器。示例如下:
| 函数名称 | 说明 |
|---|---|
| TTUnifiedNativeAd(Context context, String adUnitId) | 创建TTUnifiedNativeAd,其中context传Activity ,adUnitId 为广告位Id,需要从平台申请 |
| loadAd(AdSlot adSlot, TTNativeAdLoadCallback callback) | 调用该方法加载信息流广告,adSlot 请求的配置信息,TTNativeAdLoadCallback 信息流加载成功失败的回调函数 |
| destroy() | 销毁资源的函数,建议在界面(Activity)销毁时调用 |
简单代码示例如下(详见demo FeedListActivity)
注:每次加载信息流广告的时候需要新建一个TTUnifiedNativeAd,否则可能会出现广告填充问题( 例如:mTTAdNative = new TTUnifiedNativeAd(this, mAdUnitId);)
//step1:创建TTUnifiedNativeAd对象,传递Context对象和广告位ID即mAdUnitId
TTUnifiedNativeAd mTTAdNative;
//....省略其他代码 具体详见demo
/**
* config回调
*/
private TTAdsSdk.SettingConfigCallback mSettingConfigCallback = new TTAdsSdk.SettingConfigCallback() {
@Override
public void configLoad() {
Log.e(TAG, "load ad 在config 回调中加载广告");
loadListAd();
}
};
/**
* 加载feed广告
*/
private void loadListAdWithCallback() {
/**
* 判断当前是否存在config 配置 ,如果存在直接加载广告 ,如果不存在则注册config加载回调
*/
if (TTAdsSdk.configLoadSuccess()) {
Log.e(TAG, "load ad 当前config配置存在,直接加载广告");
loadListAd();
} else {
Log.e(TAG, "load ad 当前config配置不存在,正在请求config配置....");
TTAdsSdk.registerConfigCallback(mSettingConfigCallback); //不能使用内部类,否则在ondestory中无法移除该回调
}
}
/**
* 加载feed广告
*/
private void loadListAd() {
mTTAdNative = new TTUnifiedNativeAd(this, mAdUnitId);
//step2:创建feed广告请求类型参数AdSlot,具体参数含义参考文档
AdSlot adSlot = new AdSlot.Builder()
.setSupportDeepLink(true)
.setImageAdSize(640, 320)//注:必填字段,期望的图片尺寸,返回尺寸可能有差异
.setAdCount(3) //请求广告数量为1到3条
.build();
//step3:请求广告,调用feed广告异步请求接口,加载到广告后,拿到广告素材自定义渲染
mTTAdNative.loadAd(adSlot, new TTNativeAdLoadCallback() {
@Override
public void onAdLoaded(List<TTNativeAd> ads) {
if (ads == null || ads.isEmpty()) {
TToast.show(FeedListActivity.this, "on FeedAdLoaded: ad is null!");
return;
}
//广告加载成功 ads
}
@Override
public void onAdLoadedFial(AdError adError) {
//广告加载失败
}
});
@Override
protected void onDestroy() {
super.onDestroy();
//注销config回调
TTAdsSdk.unregisterConfigCallback(mSettingConfigCallback);
if (mAds != null) {
for (TTNativeAd ad : mAds) {
ad.destroy();
}
}
mAds = null;
}
//针对广点通的信息流声音单独配置
GDTExtraOption gdtExtraOption = new GDTExtraOption.Builder()
.setGDTAutoPlayMuted(true)//自动播放是否静音,默认true
.setGDTDetailPageMuted(true)//详情页是否静音,默认值为false,即有声播放;
.setGDTEnableDetailPage(true)//是否能跳转详情页,默认true
.setGDTEnableUserControl(false)//是否能控制是否暂停与播放,默认false
.setGDTMaxVideoDuration(15)//视频最大长度,单位:秒 此设置会影响广告填充,请谨慎设置
.setGDTMinVideoDuration(5)//视频最小长度,单位:秒 此设置会影响广告填充,请谨慎设置
// VideoOption.AutoPlayPolicy.WIFI表示只在WiFi下自动播放;
// VideoOption.AutoPlayPolicy.ALWAYS表示始终自动播放,不区分当前网络;
// VideoOption.AutoPlayPolicy.NEVER表示始终都不自动播放,不区分当前网络,但在WiFi时会预下载视频资源;
// 默认为始终自动播放;模板渲染视频、插屏视频、自渲染视频都可使用
.setAutoPlayPolicy(GDTExtraOption.AutoPlayPolicy.WIFI)//自动播放策略--
.build();
//针对百度SDK信息流设置
BaiduExtraOptions baiduExtraOptions = new BaiduExtraOptions.Builder()
.setGDTExtraOption(BaiduExtraOptions.DOWNLOAD_APP_CONFIRM_ALWAYS)
.setCacheVideoOnlyWifi(true).build();
//视频声音控制
TTVideoOption videoOption = new TTVideoOption.Builder()
.setMuted(true) //所有类型生效,除GDT
.setAdmobAppVolume(0f)//针对admob声音配置,与setMuted配合使用,范围[0-1]
.setGDTExtraOption(gdtExtraOption)//GDT单独配置
.setBaiduExtraOption(baiduExtraOptions)//百度SDK配置
.build();
//创建feed广告请求类型参数AdSlot,具体参数含义参考文档
AdSlot adSlot = new AdSlot.Builder()
.setTTVideoOption(videoOption)//视频声音相关的配置
.setAdStyleType(mAdStyle)//必传,表示请求的模板广告还是原生广告
.setSupportDeepLink(true)
.setImageAdSize(640, 320)
.setAdCount(3) //请求广告数量为1到3条
.build();信息流视频声音的配置需要通过TTVideoOption类来实现,其构建方法具体含义如下:
public static final class Builder {
private boolean mMuted = true; //视频类是否静音
private float mAdmobAppVolume;// admob 声音大小的设置 范围[0-1]
private GDTExtraOption mGDTExtraOption; //广点通信息流和自渲染2.0 以及 插屏2.0 视频配置项
public Builder() {
}
/**
* 广点通广告的自渲染2.0 和 插屏2.0 视频额外配置项
* @param gdtExtraOption
*/
public Builder setGDTExtraOption(GDTExtraOption gdtExtraOption) {
mGDTExtraOption = gdtExtraOption;
return this;
}
/**
* Admob 声音大小设置,范围:[0-1]
* the volume as a float from 0 (muted) to 1 (full media volume)
* @param volume
*/
public Builder setAdmobAppVolume(float volume) {
if (volume > 1) {
volume = 1;
} else if (volume < 0) {
volume = 0;
}
this.mAdmobAppVolume = volume;
return this;
}
/**
* 设置视频类广告是否静音 , true 静音 , false 非静音
* @param mMuted
* @return
*/
public final Builder setMuted(boolean mMuted) {
this.mMuted = mMuted;
return this;
}
public final TTVideoOption build() {
return new TTVideoOption(this);
}
}其中GDTExtraOption类为广点通GDT的个性配置,仅对广点通信息流广告生效,对于setMuted(boolean mMuted)方法,对除广点通外的信息流广告生效,其中穿山甲SDK需要在云端单独配置。 #### 2.4.3 原生信息流视频广告回调 如果需要额外的视频回调操作,如视频加载状态,暂停播放,续播等操作可以实现VideoAdListener接口(注意并非所有视频回调函数都会执行)
//视频广告设置播放状态回调(可选)
ad.setTTVideoListener(new TTVideoListener() {
@Override
public void onVideoStart() {
TToast.show(mContext, "广告视频开始播放");
}
@Override
public void onVideoPause() {
TToast.show(mContext, "广告视频暂停");
}
@Override
public void onVideoResume() {
TToast.show(mContext, "广告视频继续播放");
}
@Override
public void onVideoCompleted() {
TToast.show(mContext, "广告被点击");
}
@Override
public void onVideoError(AdError adError) {
TToast.show(mContext, "广告视频播放出错");
}
});目前Mobrain SDK 包含原生信息流和模板信息流两大类,这是两种不同类型的广告展示方式,需要分别处理,以下是原生广告和模板广告的处理方式,详见demo中的FeedListActivity类
布局文件:
<?xml version="1.0" encoding="utf-8"?>
<!-- 必须使用SDK提供的TTNativeAdView布局作为广告的父View ,否则将会影响广告点击计费 -->
<com.bytedance.sdk.api.format.TTNativeAdView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:ignore="HardcodedText">
<include
android:id="@+id/icon_source_layout"
layout="@layout/listitem_ad_icon_source_layout" />
<TextView
android:id="@+id/tv_listitem_ad_desc"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/icon_source_layout"
android:textSize="18sp" />
<!--使用SDK提供的视频容器布局-->
<com.bytedance.sdk.api.format.TTMediaView
android:id="@+id/iv_listitem_video"
android:layout_width="match_parent"
android:layout_height="200dp"
android:layout_below="@id/tv_listitem_ad_desc"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:background="@android:color/background_dark"
android:scaleType="centerCrop" />
<!-- title+creativeBtn layout -->
<include
android:id="@+id/ad_title_creative_btn_layout"
layout="@layout/listitem_ad_title_creative_btn_layout"
android:layout_width="match_parent"
android:layout_height="45dp"
android:layout_below="@+id/iv_listitem_video"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp" />
</RelativeLayout>
</com.bytedance.sdk.api.format.TTNativeAdView>上述布局文件有两点需要注意的,在展示广告View时,广告元素如title,下载button等相关的控件,它们的父类必须是SDK提供的 com.bytedance.sdk.api.format.TTNativeAdView 布局作为广告的父View ,否则将会影响广告点击计费事件。同时在展示视频类广告View时,视频类容器也需要使用SDK提供的 com.bytedance.sdk.api.format.TTMediaView , 否则可能会影响展示或者展示计费事件。下面演示通过代码来使用上述布局文件来展示信息流广告View
private View getVideoView(View convertView, ViewGroup parent, @NonNull final TTNativeAd ad) {
final VideoAdViewHolder adViewHolder;
TTViewBinder viewBinder;
try {
if (convertView == null) {
convertView = LayoutInflater.from(mContext).inflate(R.layout.listitem_ad_large_video, parent, false);
adViewHolder = new VideoAdViewHolder();
adViewHolder.mTitle = (TextView) convertView.findViewById(R.id.tv_listitem_ad_title);
adViewHolder.mDescription = (TextView) convertView.findViewById(R.id.tv_listitem_ad_desc);
adViewHolder.mSource = (TextView) convertView.findViewById(R.id.tv_listitem_ad_source);
adViewHolder.videoView = (FrameLayout) convertView.findViewById(R.id.iv_listitem_video);
adViewHolder.mIcon = (ImageView) convertView.findViewById(R.id.iv_listitem_icon);
adViewHolder.mDislike = (ImageView) convertView.findViewById(R.id.iv_listitem_dislike);
adViewHolder.mCreativeButton = (Button) convertView.findViewById(R.id.btn_listitem_creative);
//TTViewBinder 是必须类,需要开发者在确定好View之后把Id设置给TTViewBinder类,并在注册事件时传递给SDK
viewBinder = new TTViewBinder.Builder(R.layout.listitem_ad_large_video).
titleId(R.id.tv_listitem_ad_title).
sourceId(R.id.tv_listitem_ad_source).
decriptionTextId(R.id.tv_listitem_ad_desc).
mediaViewIdId(R.id.iv_listitem_video).
callToActionId(R.id.btn_listitem_creative).
iconImageId(R.id.iv_listitem_icon).build();
adViewHolder.viewBinder = viewBinder;
convertView.setTag(adViewHolder);
} else {
adViewHolder = (VideoAdViewHolder) convertView.getTag();
viewBinder = adViewHolder.viewBinder;
}
//绑定广告数据、设置交互回调,同时传递viewBinder对象
bindData(convertView, adViewHolder, ad, viewBinder);
} catch (Exception e) {
e.printStackTrace();
}
return convertView;
}注意点: 在开发者自行确定好信息流View的布局及其控件ID后,需要将与广告元素相关的ID设置给SDK提供的TTViewBinder类,该类说明如下:
public final static class Builder {
/**
* 广告View的布局文件ID
*/
private final int layoutId;
/**
* 广告标题对应控件的ID
*/
private int titleId;
/**
* 广告描述对应控件的ID
*/
private int decriptionTextId;
/**
* 广告创意按钮(如下载,查看详情等)对应控件的ID
*/
private int callToActionId;
/**
* 广告Icon对应的控件ID
*/
private int iconImageId;
/**
* 广告大图对应控件的ID
*/
private int mainImageId;
/**
* 广告视频对于控件的ID(视频类才需要传递)
*/
private int mediaViewId;
/**
* 广告来源对于控件的ID
*/
private int sourceId;
}模板广告的展示相对于原生信息流简单很多,布局文件如下:
<?xml version="1.0" encoding="utf-8"?>
<com.bytedance.sdk.api.format.TTNativeAdView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<FrameLayout
android:id="@+id/iv_listitem_express"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center" />
</com.bytedance.sdk.api.format.TTNativeAdView>同样需要注意的时广告view的父类仍然必须是 com.bytedance.sdk.api.format.TTNativeAdView ,下面演示了如果在代码中处理模板广告,更多详细代码请见FeedListActivity
//渲染模板广告
@SuppressWarnings("RedundantCast")
private View getExpressAdView(View convertView, ViewGroup parent, @NonNull final TTNativeAd ad){
final ExpressAdViewHolder adViewHolder;
try {
if (convertView == null) {
convertView = LayoutInflater.from(mContext).inflate(R.layout.listitem_ad_native_express, parent, false);
adViewHolder = new ExpressAdViewHolder();
adViewHolder.mAdContainerView = (FrameLayout) convertView.findViewById(R.id.iv_listitem_express);
convertView.setTag(adViewHolder);
} else {
adViewHolder = (ExpressAdViewHolder) convertView.getTag();
}
//判断是否存在dislike按钮
if (ad.hasDislike()) {
ad.setDislikeCallback((Activity) mContext, new TTDislikeCallback() {
@Override
public void onSelected(int position, String value) {
TToast.show(mContext, "点击 " + value);
//用户选择不喜欢原因后,移除广告展示
mData.remove(ad);
sumCount--;
notifyDataSetChanged();
}
@Override
public void onCancel() {
TToast.show(mContext, "dislike 点击了取消");
}
});
}
//设置点击展示回调监听
ad.setTTNativeAdListener(new TTNativeExpressAdListener() {
@Override
public void onAdClick() {
TToast.show(mContext, "模板广告被点击");
}
@Override
public void onAdShow() {
TToast.show(mContext, "模板广告show");
}
@Override
public void onRenderFail(View view, String msg, int code) {
TToast.show(mContext, "模板广告渲染失败code=" + code + ",msg=" + msg);
}
@Override
public void onRenderSuccess(View view, float width, float height) {
TToast.show(mContext, "模板广告渲染成功:width=" + width + ",height=" + height);
//回调渲染成功后将模板布局添加的父View中
if (adViewHolder.mAdContainerView != null) {
//获取视频播放view,该view SDK内部渲染,在媒体平台可配置视频是否自动播放等设置。
int sWidth;
int sHeight;
final View video = ad.getExpressView();
//如果返回的size是TTAdSize.FULL_WIDTH和 height == TTAdSize.AUTO_HEIGHT
//广告view的布局直接设置为如下值
if (width == TTAdSize.FULL_WIDTH && height == TTAdSize.AUTO_HEIGHT) {
sWidth = FrameLayout.LayoutParams.MATCH_PARENT;
sHeight = FrameLayout.LayoutParams.WRAP_CONTENT;
} else {
//传回来的值,开发者可自行调整View大小
sWidth = UIUtils.getScreenWidth(mContext);
sHeight = (int) ((sWidth * height) / width);
}
if (video != null) {
if (video.getParent() == null) {
FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(sWidth, sHeight);
adViewHolder.mAdContainerView.removeAllViews();
adViewHolder.mAdContainerView.addView(video, layoutParams);
}
}
}
}
});
//调用渲染模板布局的方法
ad.render();
} catch (Exception e) {
e.printStackTrace();
}
return convertView;
}在设置完监听事件后,需要调用render()方法对模板广告进行渲染,渲染成功会回调onRenderSuccess方法,渲染失败则会回调onRenderFail方法。
在加载到信息流广告后,接入方需要注册在信息流广告中可以点击的View,即TTNativeAd.registerViewForInteraction()方法,以实现广告的功能交互及计费。包含图文点击区域的注册和附加创意按钮点击区域的注册。对于落地页广告,用户点击图文广告区域会跳转到相应的落地页,点击附加创意区域会进行电话拨打、应用下载等操作,注意模板类信息流广告并不需要调用注册方法。 注册点击View示例的示例代码如下,该示例片段在FeedListActivity中调用。
private void bindData(View convertView, final AdViewHolder adViewHolder, final TTNativeAd ad, TTViewBinder viewBinder) {
//设置dislike弹窗,如果有
if (ad.hasDislike()) {
final TTAdDislike ttAdDislike = ad.getDislikeDialog((Activity) mContext);
adViewHolder.mDislike.setVisibility(View.VISIBLE);
adViewHolder.mDislike.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//使用接口来展示
ttAdDislike.showDislikeDialog();
ttAdDislike.setDislikeCallback(new TTDislikeCallback() {
@Override
public void onSelected(int position, String value) {
TToast.show(mContext, "点击 " + value);
//用户选择不喜欢原因后,移除广告展示
mData.remove(ad);
sumCount--;//总数也要减少
notifyDataSetChanged();
}
@Override
public void onCancel() {
TToast.show(mContext, "dislike 点击了取消");
}
});
}
});
} else {
if (adViewHolder.mDislike != null)
adViewHolder.mDislike.setVisibility(View.GONE);
}
//设置事件回调
ad.setTTNativeAdListener(mTTNativeAdListener);
//可以被点击的view, 也可以把convertView放进来意味item可被点击
List<View> clickViewList = new ArrayList<>();
clickViewList.add(convertView);
clickViewList.add(adViewHolder.mSource);
clickViewList.add(adViewHolder.mTitle);
clickViewList.add(adViewHolder.mDescription);
clickViewList.add(adViewHolder.mIcon);
//触发创意广告的view(点击下载或拨打电话)
List<View> creativeViewList = new ArrayList<>();
creativeViewList.add(adViewHolder.mCreativeButton);
//重要! 这个涉及到广告计费,必须正确调用。convertView必须使用ViewGroup,必须传递viewBinder
ad.registerView((ViewGroup) convertView, clickViewList, creativeViewList, viewBinder);
//省略其他代码
}在原生信息类中必须需要调用registerView方法进行事件注册,否则将影响广告计费
原生信息流广告使用的监听回调接口是 com.bytedance.sdk.api.nativeAd.TTNativeAdListener 模板信息流广告注册监听回调接口是 com.bytedance.sdk.api.nativeAd.TTNativeExpressAdListener 他们的具体介绍如下:
TTNativeAdListener 如下:
public interface TTNativeAdListener {
/**
* 点击回调事件
*/
void onAdClick();
/**
* 展示回调事件
*/
void onAdShow();
}TTNativeExpressAdListener 如下:
public interface TTNativeExpressAdListener extends TTNativeAdListener {
/**
* 点击回调事件
*/
void onAdClick();
/**
* 展示回调事件
*/
void onAdShow();
/**
* 模板渲染失败
* @param view
*/
void onRenderFail(View view, String msg, int code);
/**
* 模板渲染成功
* @param view
* @param width 返回view的宽 ,开发者可以根据返回的宽高进行比例适配
* @param height 返回view的高 ,开发者可以根据返回的宽高进行比例适配
*/
void onRenderSuccess(View view, float width, float height);
}SDK为接入方提供了Banner类型的广告,Banner广告为一张图片的View(TTBannerAd.getBannerView),此View的宽高默认为match_parent,用户可以自行定义宽高或通过设置父布局的宽高的方式来限定Banner广告的大小(注:Banner广告的宽高请尽量与adSlot中设置的宽高比例接近,以避免过多非等比例的拉伸)。
Banner广告可支持的多种尺寸比例,具体如下(com.bytedance.sdk.api.TTAdSize):
public static final int BANNER_320_50 = 1;
public static final int BANNER_320_100 = 2;
public static final int BANNER_300_250 = 3;
public static final int BANNER_468_60 = 4;
public static final int BANNER_728_90 = 5;
public static final int BANNER_CUSTOME = 6; //自定义大小请求banner广告需要通过TTBannerView类来实现,该类具体调用接口如下:
| 方法名 | 说明 |
|---|---|
| TTBannerView(Context context, String adUnitId) | 构造方法,传入上下文context,rit广告位ID,开发平台申请后填入 |
| loadAd(AdSlot adSlot, TTAdBannerLoadCallBack adBannerLoadCallBack) | 加载广告,adSlot相关配置参数,adBannerLoadCallBack 加载回调监听 |
| setTTAdBannerListener(TTAdBannerListener adBannerListener) | 交互回调监听事件 |
| setRefreshTime(int refreshTime) | 设置banner轮播刷新事件 |
| View getBannerView() | 获取banner 广告View |
| destroy() | 资源回收方法 |
接入方可通过调用TTBannerView.loadAd(AdSlot adSlot, TTAdBannerLoadCallBack adBannerLoadCallBack)方法来异步加载Banner广告,adSlot为请求的信息,TTAdBannerLoadCallBack为Banner广告加载成功、失败的回调,在UI线程回调,详细代码见demo中的BannerActivity
注:每次加载banner的时候需要新建一个TTBannerView,否则可能会出现广告填充问题( 例如:mTTBannerView = new TTBannerView(this, adUnitId);)
/**
* config回调
*/
private TTAdsSdk.SettingConfigCallback mSettingConfigCallback = new TTAdsSdk.SettingConfigCallback() {
@Override
public void configLoad() {
Log.e(TAG, "load ad 在config 回调中加载广告");
loadBannerAd();
}
};
/**
* 加载广告
*/
private void loadAdWithCallback() {
/**
* 判断当前是否存在config 配置 ,如果存在直接加载广告 ,如果不存在则注册config加载回调
*/
if (TTAdsSdk.configLoadSuccess()) {
Log.e(TAG, "load ad 当前config配置存在,直接加载广告");
loadBannerAd();
} else {
Log.e(TAG, "load ad 当前config配置不存在,正在请求config配置....");
TTAdsSdk.registerConfigCallback(mSettingConfigCallback); //不能使用内部类,否则在ondestory中无法移除该回调
}
}
private void loadBannerAd(String adUnitId) {
mTTBannerView = new TTBannerView(this, adUnitId);
mTTBannerView.setRefreshTime(30);//设置轮播时间30S
mTTBannerView.setAllowShowCloseBtn(true);//如果广告本身允许展示关闭按钮,这里设置为true 就是展示
mTTBannerView.setTTAdBannerListener(ttAdBannerListener);
//step4:创建广告请求参数AdSlot,具体参数含义参考文档
AdSlot adSlot = new AdSlot.Builder()
.setSupportDeepLink(true)
.setBannerSize(TTAdSize.BANNER_320_50)
//.setBannerSize(300,600) 使用TTAdSize.BANNER_CUSTOME可以调用setAdSize设置大小
.build();
//step5:请求广告,对请求回调的广告作渲染处理
mTTBannerView.loadAd(adSlot, new TTAdBannerLoadCallBack() {
@Override
public void onAdFailedToLoad(AdError adError) {
mBannerContainer.removeAllViews();
}
@Override
public void onAdLoaded() {
mBannerContainer.removeAllViews();
if (mTTBannerView != null) {
//横幅广告容器的尺寸必须至少与横幅广告一样大。如果您的容器留有内边距,实际上将会减小容器大小。如果容器无法容纳横幅广告,则横幅广告不会展示
View view = mTTBannerView.getBannerView();
if (view != null)
mBannerContainer.addView(view);
}
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
//注销config回调
TTAdsSdk.unregisterConfigCallback(mSettingConfigCallback);
if (mTTBannerView != null) {
mTTBannerView.destroy();
}
}mTTBannerView.setTTAdBannerListener(ttAdBannerListener);
public interface TTAdBannerListener {
/**
* 当广告打开浮层时调用,如打开内置浏览器、内容展示浮层,一般发生在点击之后
* 常常在onAdLeftApplication之前调用,不能保证每次都回调
*/
void onAdOpened();
/**
* 此方法会在用户点击打开其他应用(例如 Google Play)时
* 于 onAdOpened() 之后调用,从而在后台运行当前应用,不能保证每次都回调
*/
void onAdLeftApplication();
/**
* 关闭广告
*/
void onAdClosed();
/**
* 广告被点击,肯定有回调
*/
void onAdClicked();
/**
* 广告展示,肯定有回调
*/
void onAdShow();
}具体示例详见Demo中的BannerActivity。
SDK为接入方提供了开屏广告,开屏广告建议为用户在进入App时展示的全屏广告。开屏广告为一个View,宽高默认为match_parent,注意开屏广告view:width >=70%屏幕宽;height >=50%屏幕高,否则会影响计费。
开屏广告可支持的尺寸:图片尺寸传入与展示区域大小保持一致,避免素材变形
开屏广告场景也支持个性化模板广告,开发者需要在穿山甲平台申请支持该特性的广告位id,且在构造AdSlot对象时,调用setExpressViewAcceptedSize传入期望的模板广告尺寸大小,详见demo示例。
开屏广告需要通过TTSplashAd类来加载和展示,具体接口如下:
| 函数名称 | 函数说明 |
|---|---|
| TTSplashAd(Activity activity, String adUnitId) | 构造函数,传入acitivty参数和广告位ID |
| loadAd(AdSlot adSlot, TTSplashAdLoadCallback splashAdLoadCallback, int loadTimeOut) | 加载开屏广告,参数:adSlot 请求配置参数,splashAdLoadCallback加载成功失败回调 ,loadTimeOut加载超时时间 |
| setTTAdSplashListener(TTSplashAdListener splashListener) | 设置开屏广告交互事件 |
| showAd(ViewGroup containerView) | 展示开屏广告,传入父级容器containerView |
| Destroy() | 资源回收销毁函数 |
接入方可调用TTSplashAd.loadAd(AdSlot adSlot, TTSplashAdLoadCallback splashAdLoadCallback, int loadTimeOut)异步加载开屏广告。adslot为请求广告的信息,splashAdLoadCallback为广告加载状态的回调,loadTimeOut为加载开屏广告允许的最长时间(注:建议timeOut > 3000ms)。调用示例如下:
注:每次加载开屏广告的时候需要新建一个TTSplashAd,否则可能会出现广告填充问题( 例如:mTTSplashAd = new TTSplashAd(this, “801121974”);)
mTTSplashAd = new TTSplashAd(this, "801121974");
mTTSplashAd.setTTAdSplashListener(mSplashAdListener);
//step3:创建开屏广告请求参数AdSlot,具体参数含义参考文档
AdSlot adSlot = new AdSlot.Builder()
.setSupportDeepLink(true)
.setImageAdSize(1080, 1920)
.build();
//step4:请求广告,调用开屏广告异步请求接口,对请求回调的广告作渲染处理
mTTSplashAd.loadAd(adSlot, new TTSplashAdLoadCallback() {
@Override
public void onSplashAdLoadFail(AdError adError) {
Log.d(TAG, adError.message);
mHasLoaded = true;
goToMainActivity();
}
@Override
public void onSplashAdLoadSuccess() {
if (mTTSplashAd != null) {
mTTSplashAd.showAd(mSplashContainer);
}
}
@Override
public void onAdLoadTimeout() {
mHasLoaded = true;
goToMainActivity();
}
}, AD_TIME_OUT);开屏广告交互事件回调监听如下:
public interface TTSplashAdListener{
/**
* Splash广告的点击回调
*/
void onAdClicked();
/**
* Splash广告的展示回调
*/
void onAdShow();
/**
* 点击跳过时回调
*/
void onAdSkip();
/**
* 广告关闭时调用,可能是用户关闭或者展示时间到。
* 此时一般需要跳过开屏的 Activity,进入应用内容页面
* 广告播放时间结束 --》onAdDismissed(GDT)
*/
void onAdDismiss();
}加载开屏广告具体示例详见Demo中的SplashActivity。
本SDK为接入方提供插屏广告,该广告的效果为在activity之上弹出一个dialog。使用场景包括但不限于: 1、进入时展开:用户进入app首页或者用户进入详情页,弹出插屏广告; 2、滑到底部展开:用户在详情页浏览,浏览到最底部,弹出插屏广告; 3、回滑时展开:用户滑动返回上一页面,弹出插屏广告;
注意:这里针对穿山甲SDK的插屏广告尺寸支持: 1:1, 3:2, 2:3 ,可在请求传参过程中,需要按照比例的实际尺寸请求,比如1:1的尺寸,可以请求600x600。Admob 和 Mintegral 仅支持全屏插屏 ,GDT 支持不同比例插屏需要在GDT管理后台设置。
加载插屏广告需要通过TTInterstitialAd类,主要方法说明如下:
| 函数名称 | 函数说明 |
|---|---|
| TTInterstitialAd(Activity activity, String adUnitId) | 构造函数,传入activity和广告位ID |
| loadAd(AdSlot adSlot, TTInterstitialAdLoadCallback interstitialAdLoadCallback) | 加载广告,adslot请求配置参数,TTInterstitialAdLoadCallback 加载成功失败回调 |
| setTTAdInterstitialListener(TTInterstitialAdListener adInterstitialListener) | 设置插屏广告的交互监听器 |
| isReady() | 判断广告是否已准备好,一般在show之前调用 |
| showAd(Activity activity) | 展示插屏广告,参数传入Activity |
| boolean isReady() | 判断插屏广告是否已准备好,一般在show之前调用 |
| destroy() | 广告展示完成后销毁并回收资源 |
接入方可调用mInterstitialAd.loadAd(AdSlot adSlot, TTInterstitialAdLoadCallback interstitialAdLoadCallback)异步加载插屏广告,adslot为请求广告的信息,interstitialAdLoadCallback为广告加载成功或失败的回调。具体示例如下:
注:每次加载插屏广告的时候需要新建一个TTInterstitialAd,否则可能会出现广告填充问题( 例如:mInterstitialAd = new TTInterstitialAd(this, adUnitId);)
private TTAdsSdk.SettingConfigCallback mSettingConfigCallback = new TTAdsSdk.SettingConfigCallback() {
@Override
public void configLoad() {
Log.e(TAG, "load ad 在config 回调中加载广告");
loadInteractionAd();
}
};
/**
* 加载插屏广告
*/
private void loadAdWithCallback(){
/**
* 判断当前是否存在config 配置 ,如果存在直接加载广告 ,如果不存在则注册config加载回调
*/
if (TTAdsSdk.configLoadSuccess()) {
Log.e(TAG, "load ad 当前config配置存在,直接加载广告");
loadInteractionAd();
} else {
Log.e(TAG, "load ad 当前config配置不存在,正在请求config配置....");
TTAdsSdk.registerConfigCallback(mSettingConfigCallback);
}
}
private void loadInteractionAd(final String adUnitId) {
//Context 必须传activity
mInterstitialAd = new TTInterstitialAd(this, adUnitId);
//创建插屏广告请求参数AdSlot,具体参数含义参考文档
AdSlot adSlot = new AdSlot.Builder()
.setSupportDeepLink(true)
.setImageAdSize(600, 600) //根据广告平台选择的尺寸(目前该比例规格仅对穿山甲SDK生效,插屏广告支持的广告尺寸: 1:1, 3:2, 2:3)
.build();
//请求广告,调用插屏广告异步请求接口
mInterstitialAd.loadAd(adSlot, new TTInterstitialAdLoadCallback() {
@Override
public void onInterstitialLoadFail(AdError adError) {
isLoadSuccess = false;
}
@Override
public void onInterstitialLoad() {
isLoadSuccess = true;
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
//注销config回调
TTAdsSdk.unregisterConfigCallback(mSettingConfigCallback);
if (mInterstitialAd != null) {
mInterstitialAd.destroy();
}
}在展示插屏广告之前可先调用 isRead() 判断广告是否已准备好再调用show方法展示广告
if (isLoadSuccess && mInterstitialAd != null && mInterstitialAd.isReady()) {
//设置监听器
mInterstitialAd.setTTAdInterstitialListener(interstitialListener);
mInterstitialAd.showAd(this);
}详细代码示例见demo的InterstitialActivity类 #### 2.7.4 设置插屏广告交互监听器 插屏广告的交互回调监听是TTInterstitialAdListener,具体回调方法如下:
public interface TTInterstitialAdListener{
/**
* 广告展示
*/
void onInterstitialShow();
/**
* 广告被点击
*/
void onInterstitialAdClick();
/**
* 关闭广告
*/
void onInterstitialClosed();
/**
* 当广告打开浮层时调用,如打开内置浏览器、内容展示浮层,一般发生在点击之后
* 常常在onAdLeftApplication之前调用,并非百分百回调,穿山甲SDK不支持
*/
void onAdOpened();
/**
* 此方法会在用户点击打开其他应用(例如 Google Play)时
* 于 onAdOpened() 之后调用,从而在后台运行当前应用。
* 并非百分百回调,穿山甲SDK不支持
*/
void onAdLeftApplication();
}加载及展示插屏广告具体示例详见Demo中的InteractionActivity。
本SDK为接入方提供激励视频广告,该广告的效果为观看完毕视频广告,发放奖励给用户。使用场景包括但不限于: 1、游戏等应用内观看视频广告获得游戏内金币等:用户必须观看完整视频才能获取奖励; 2、积分类应用接入; 支持的广告尺寸: 全屏横屏播放和竖屏,默认横屏
请求激励视频需要调用TTRewardAd的相关方法,说明如下:
| 函数名称 | 函数说明 |
|---|---|
| TTRewardAd(Context context, String ritId) | 构造方法,参数:Activity ,adUnitId,广告位Id |
| loadRewardAd(AdSlot adSlot, TTRewardedAdLoadCallback listener) | AdSlot请求配置信息,加载监听回调TTRewardedAdLoadCallback |
| showRewardAd(Activity activity, TTRewardedAdListener adRewardedListener) | 展示全屏广告,交互监听TTRewardedAdListener |
| isReady() | 判断广告是否已准备好,一般在show之前调用 |
| destroy() | 资源回收与销毁 |
接入方可调用loadRewardAd(AdSlot adSlot, @NonNull TTRewardedAdLoadCallback listener)异步加载激励视频广告,adslot为请求广告的信息,RewardVideoAdListener为广告加载成功或失败的回调,回调均在主线程执行。
注:每次加载激励视频广告的时候需要新建一个TTRewardAd,否则可能会出现广告填充问题( 例如:mttRewardAd = new TTRewardAd(this, “901121543”);)
/**
* config回调
*/
private TTAdsSdk.SettingConfigCallback mSettingConfigCallback = new TTAdsSdk.SettingConfigCallback() {
@Override
public void configLoad() {
Log.e(TAG, "load ad 在config 回调中加载广告");
loadAd(adUnitId, orientation);
}
};
/**
* 加载广告
*/
private void laodAdWithCallback(final String adUnitId, final int orientation) {
/**
* 判断当前是否存在config 配置 ,如果存在直接加载广告 ,如果不存在则注册config加载回调
*/
if (TTAdsSdk.configLoadSuccess()) {
Log.e(TAG, "load ad 当前config配置存在,直接加载广告");
loadAd(adUnitId, orientation);
} else {
Log.e(TAG, "load ad 当前config配置不存在,正在请求config配置....");
TTAdsSdk.registerConfigCallback(mSettingConfigCallback); //不用使用内部类,否则在ondestory中无法移除该回调
}
}
private void loadAd(final String adUnitId, int orientation) {
mttRewardAd = new TTRewardAd(this, "901121543");
//创建广告请求参数AdSlot,具体参数含义参考文档
AdSlot adSlot = new AdSlot.Builder()
.setSupportDeepLink(true)
.setAdStyleType(AdSlot.TYPE_EXPRESS_AD)//AdSlot.TYPE_EXPRESS_AD 标识pangle使用动态模板激励视频;AdSlot.TYPE_NATIVE_AD:使用原生激励视频
.setRewardName("金币") //奖励的名称
.setRewardAmount(3) //奖励的数量
.setUserID("user123")//用户id,必传参数
.setOrientation(orientation) //必填参数,期望视频的播放方向:TTAdConstant.HORIZONTAL 或 TTAdConstant.VERTICAL
.build();
//请求广告
mttRewardAd.loadRewardAd(adSlot, new TTRewardedAdLoadCallback() {
@Override
public void onRewardVideoLoadFail(AdError adError) {
loadSuccess = false;
}
@Override
public void onRewardVideoAdLoad() {
loadSuccess = true;
}
@Override
public void onRewardVideoCached() {
loadSuccess = true;//激励视频资源加载成功
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
TTAdsSdk.unregisterConfigCallback(mSettingConfigCallback);
if (mttRewardAd != null) {
mttRewardAd.destroy();
}
}接入方可调用showRewardAd(Activity activity, TTRewardedAdListener adRewardedListener)展示激励视频广告,activity为界面Activity,adRewardedListener为激励视频交互回调。在调用showRewardAd之前可先调用isReady() 方法判断广告是否已准备好
if (loadSuccess && mttRewardAd != null && mttRewardAd.isReady()) {
//在获取到广告后展示,强烈建议在onRewardVideoCached回调后,展示广告,提升播放体验
//该方法直接展示广告
//展示广告,并传入广告展示的场景
mttRewardAd.showRewardAd(RewardVideoActivity.this, mTTRewardedAdListener);
}具体使用请参考demo示例。
public interface TTRewardedAdListener extends ITTAdatperCallback {
/**
* 广告的展示回调
*/
void onRewardedAdShow();
/**
* 广告的下载bar点击回调-注意Admob的激励视频不会回调该方法
*/
void onRewardClick();
/**
* 广告关闭的回调
*/
void onRewardedAdClosed();
/**
* 视频播放完毕的回调 - Admob广告不存在该回调
*/
void onVideoComplete();
/**
* 视频播放失败的回调 - Mintegral GDT Admob广告不存在该回调
*/
void onVideoError();
/**
* 激励视频播放完毕,验证是否有效发放奖励的回调
*/
void onRewardVerify(RewardItem rewardItem);
}服务器到服务器回调让您判定是否提供奖励给观看广告的用户。当用户成功看完广告时,您可以在头条媒体平台配置从头条服务器到您自己的服务器的回调链接,以通知您用户完成了操作。
头条服务器会以 GET 方式请求第三方服务的回调链接,并拼接以下参数回传:
user_id=%s&trans_id=%s&reward_name=%s&reward_amount=%d&extra=%s&sign=%s
| 字段名称 | 字段定义 | 字段类型 | 备注 |
|---|---|---|---|
| sign | 签名 | string | 签名 |
| user_id | 用户id | string | 调用SDK透传,应用对用户的唯一标识 |
| trans_id | 交易id | string | 完成观看的唯一交易ID |
| reward_amount | 奖励数量 | int | 媒体平台配置或调用SDK传入 |
| reward_name | 奖励名称 | string | 媒体平台配置或调用SDK传入 |
| extra | Extra | string | 调用SDK传入并透传,如无需要则为空 |
appSecurityKey: 您在头条媒体平台新建奖励视频代码位获取到的密钥 transId:交易id sign = sha256(appSecurityKey:transId)
Python 示例:
import hashlib
if __name__ == "__main__":
trans_id = "6FEB23ACB0374985A2A52D282EDD5361u6643"
app_security_key = "7ca31ab0a59d69a42dd8abc7cf2d8fbd"
check_sign_raw = "%s:%s" % (app_security_key, trans_id)
sign = hashlib.sha256(check_sign_raw).hexdigest()返回 json 数据,字段如下:
| 字段名称 | 字段定义 | 字段类型 | 备注 |
|---|---|---|---|
| isValid | 校验结果 | bool | 判定结果,是否发放奖励 |
示例:
{
"isValid": true
}
本SDK为接入方提供全屏视频广告,该广告的效果播放全屏的视频,视频一定时间后可跳过,无需全程观看完。 支持的广告尺寸: 全屏横屏播放和竖屏,默认横屏
| 函数名称 | 函数说明 |
|---|---|
| TTFullVideoAd(Activity activity,String adUnitId) | 构造方法,参数:Activity ,adUnitId,广告位Id |
| loadFullAd(AdSlot adSlot, @NonNull TTFullVideoAdLoadCallback listener) | AdSlot请求配置信息,加载监听回调TTFullVideoAdLoadCallback |
| showFullAd(Activity activity, TTFullVideoAdListener fullVideoAdListener) | 展示全屏广告,交互监听TTFullVideoAdListener |
| boolean isReady() | 判断广告是否已准备好,一般在showFullAd之前调用 |
| destroy() | 清理回收资源 |
接入方可调用loadFullAd(AdSlot adSlot, @NonNull TTFullVideoAdLoadCallback listener)异步加载全屏视频广告,adslot为请求广告的信息,TTFullVideoAdLoadCallback为广告加载成功或失败的回调。
注:每次加载全屏视频广告的时候需要新建一个TTFullVideoAd,否则可能会出现广告填充问题( 例如:mTTFullVideoAd = new TTFullVideoAd(this, “901121073”);)
/**
* config回调
*/
private TTAdsSdk.SettingConfigCallback mSettingConfigCallback = new TTAdsSdk.SettingConfigCallback() {
@Override
public void configLoad() {
Log.e(TAG, "load ad 在config 回调中加载广告");
loadAd();
}
};
/**
* 加载广告
*/
private void loadAdWithCallback() {
/**
* 判断当前是否存在config 配置 ,如果存在直接加载广告 ,如果不存在则注册config加载回调
*/
if (TTAdsSdk.configLoadSuccess()) {
Log.e(TAG, "load ad 当前config配置存在,直接加载广告");
loadAd();
} else {
Log.e(TAG, "load ad 当前config配置不存在,正在请求config配置....");
TTAdsSdk.registerConfigCallback(mSettingConfigCallback); //不能使用内部类,否则在ondestory中无法移除该回调
}
}
private void loadAd(final String adUnitId, int orientation) {
mTTFullVideoAd = new TTFullVideoAd(this, "901121073");
//step4:创建广告请求参数AdSlot,具体参数含义参考文档
AdSlot adSlot = new AdSlot.Builder()
.setSupportDeepLink(true)
.setAdStyleType(AdSlot.TYPE_EXPRESS_AD)//AdSlot.TYPE_EXPRESS_AD 标识pangle使用动态模板全屏视频;AdSlot.TYPE_NATIVE_AD:使用原生全屏视频
.setRewardName("金币") //奖励的名称
.setRewardAmount(3) //奖励的数量
.setUserID("user123")//用户id,必传参数
.setMediaExtra("media_extra") //附加参数,可选
.setOrientation(orientation) //必填参数,期望视频的播放方向:TTAdConstant.HORIZONTAL 或 TTAdConstant.VERTICAL
.build();
//请求广告
mTTFullVideoAd.loadFullAd(adSlot, new TTFullVideoAdLoadCallback() {
@Override
public void onFullVideoLoadFail(AdError adError) {
loadSuccess = false;
}
@Override
public void onFullVideoAdLoad() {
loadSuccess = true;
}
@Override
public void onFullVideoCached() {
loadSuccess = true;
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
//注销config回调
TTAdsSdk.unregisterConfigCallback(mSettingConfigCallback);
if (mTTFullVideoAd != null) {
mTTFullVideoAd.destroy();
}
}
接入方可调用showFullAd(Activity activity, TTFullVideoAdListener fullVideoAdListener)异步加载激励视频广告,activity为宿主activity,fullVideoAdListener为全屏视频交互回调。在调用展示方法之前,可调用isReady()方法先判断广告是否已准备好
if (loadSuccess && mTTFullVideoAd != null && mTTFullVideoAd.isReady()) {
//在获取到广告后展示,强烈建议在onFullVideoCached回调后,展示广告,提升播放体验
//该方法直接展示广告
//展示广告,并传入广告展示的场景
mTTFullVideoAd.showFullAd(FullVideoActivity.this, mTTFullVideoAdListener);
} public interface TTFullVideoAdListener extends ITTAdatperCallback {
/**
* 广告的展示回调
*/
void onFullVideoAdShow();
/**
* 广告的下载bar点击回调
*/
void onFullVideoAdClick();
/**
* 广告关闭的回调
*/
void onFullVideoAdClosed();
/**
* 视频播放完毕的回调- Admob广告不存在该回调,
*/
void onVideoComplete();
/**
* 视频播放失败的回调- Mintegral GDT Admob广告不存在该回调,仅穿山甲SDK广告回调
*/
void onVideoError();
/**
* 跳过视频播放 - Mintegral GDT Admob广告不存在该回调,仅穿山甲SDK广告回调
*/
void onSkippedVideo();
}详细代码请参考demo中的FullVideoActivity。
SDK为接入方提供了信息流广告Dislike逻辑,当用户选择关闭广告时候,会有提示询问用户,包含“不感兴趣”、“看过了”选项供用户选择。该反馈主要用于头条广告对用户端的广告策略,用来优化提升广告的点击率,提升广告效果及合作伙伴的收益。
在获得TTNativeAd后,先通过boolean hasDislike()方法判断当前广告是否存在dislike,如果存在分别对原生信息流广告和模板信息流广告进行dislike的设置具体方式如下:
//设置dislike弹窗,如果有
if (ad.hasDislike()) {
final TTAdDislike ttAdDislike = ad.getDislikeDialog((Activity) mContext);
adViewHolder.mDislike.setVisibility(View.VISIBLE);
adViewHolder.mDislike.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//使用接口来展示
ttAdDislike.showDislikeDialog();
ttAdDislike.setDislikeCallback(new TTDislikeCallback() {
@Override
public void onSelected(int position, String value) {
TToast.show(mContext, "点击 " + value);
//用户选择不喜欢原因后,移除广告展示
mData.remove(ad);
sumCount--;//总数也要减少
notifyDataSetChanged();
}
@Override
public void onCancel() {
TToast.show(mContext, "dislike 点击了取消");
}
});
}
});
} //判断是否存在dislike按钮
if (ad.hasDislike()) {
ad.setDislikeCallback((Activity) mContext, new TTDislikeCallback() {
@Override
public void onSelected(int position, String value) {
TToast.show(mContext, "点击 " + value);
//用户选择不喜欢原因后,移除广告展示
mData.remove(ad);
sumCount--;
notifyDataSetChanged();
}
@Override
public void onCancel() {
TToast.show(mContext, "dislike 点击了取消");
}
});
}| 错误码 | 说明 |
|---|---|
| 20000 | 成功 |
| 40000 | http content type错误 |
| 40001 | http request pb错误(请求参数类型错误) |
| 40002 | source_type=‘app’, 请求app不能为空 |
| 40003 | source_type=‘wap’, 请求wap不能为空 |
| 40004 | 广告位不能为空 |
| 40005 | 广告位尺寸不能为空 |
| 40006 | 广告位ID不合法 |
| 40007 | 广告数量错误 |
| 40008 | 图片尺寸错误 |
| 40009 | 媒体ID不合法 |
| 40010 | 媒体类型不合法 |
| 40011 | 广告类型不合法 |
| 40012 | 媒体接入类型不合法,已废弃 |
| 40013 | 代码位id小于9亿,但是adType不是开屏 |
| 40014 | redirect参数不正确 |
| 40015 | 媒体整改超过期限,请求非法 |
| 40016 | adUnitId 与 app_id对应关系不合法 |
| 40017 | 媒体接入类型不合法 API/SDK |
| 40018 | 媒体包名与录入不一致 |
| 40019 | 媒体配置adtype和请求不一致 |
| 40020 | 开发注册新上线广告位超出日请求量限制 |
| 40021 | apk签名sha1值与媒体平台录入不一致 |
| 40022 | 媒体请求素材是否原生与媒体平台录入不一致 |
| 40023 | os字段填的不对 |
| 40024 | sdk 版本过低不返回广告 |
| 40025 | 引入SDK包不完整,建议校验SDK包完整性或联系技术支持 |
| 40029 | 模板广告请求使用了错误的方式,见下方FAQ说明 |
| 50001 | 服务器错误 |
| 60001 | show event处理错误 |
| 60002 | click event处理错误 |
| 60007 | 激励视频验证服务器异常或处理失败 |
| -1 | 数据解析失败 |
| -2 | 网络错误 |
| -3 | 解析数据没有ad |
| -4 | 返回数据缺少必要字段 |
| -5 | bannerAd加载图片失败 |
| -6 | 插屏广告图片加载失败 |
| -7 | 开屏广告图片加载失败 |
| -8 | 频繁请求 |
| -9 | 请求实体为空 |
| -10 | 缓存解析失败 |
| -11 | 缓存过期 |
| -12 | 缓存中没有开屏广告 |
| 101 | 渲染结果数据解析失败 |
| 102 | 主模板无效 |
| 103 | 模板差量无效 |
| 104 | 物料数据异常 |
| 105 | 模板数据解析异常 |
| 106 | 渲染异常 |
| 107 | 渲染超时未回调 |
1.全局信息:
2.信息流广告:
3.Andriod 7.0及以上 用户点击了“点击安装”后没有反应,或者下载完成后没有调起安装界面。
4.如何区分落地页广告还是app下载广告?
5.信息流视频广告如何记录展示?
6.资源混淆问题:如果您的应用对资源也进行混淆(如andResGuard),请不要混淆穿山甲的任何资源,防止资源找不到崩溃,穿山甲的资源清单请咨询技术支持
7.40029错误码,原因有以下两种 - 1. SDK版本低:您使用的sdk版本不得低于2.5.0.0,麻烦升级到平台最新版本sdk。 - 2. 接口使用错误:创建的代码位类型是模板渲染/非模板渲染,但是请求方法是非模板渲染/模板渲染的方法。解决办法:使用模板渲染的方法去请求模板渲染类型或者使用非模板渲染的方法去请求非模板类型的广告,如果代码位在平台上是模板渲染,可以参考文档中个性化模板XX广告的部分,demo中参考带有express部分的代码。如果代码位不是模板渲染,则不要调用含有express字样的接口。 - 参考文档:https://partner.oceanengine.com/doc?id=5dd0fe716b181e00112e3eb8
8.其他问题请咨询MSDK相关人员。