贴片广告是一种视频广告形式,开发者可以将广告位设置在其APP内的视频播放前/播放中/播放结束后。贴片广告的时长可以设置成固定时长,如5s/15s等;也可以不限制固定时长,在5-60s范围内由系统返回收益最高的广告,帮助开发者实现收益最大化。贴片广告目前仅支持自渲染,可以使用穿山甲默认播放器,也可以申请使用开发者自己的播放器。
自渲染贴片广告:已回收,不再提供创建(仅支持历史创建代码位)。
SDK版本要求: 3400及以上。
//创建TTAdNative对象,createAdNative(Context context) context需要传入Activity对象
TTAdNative mTTAdNative = TTAdSdk.getAdManager().createAdNative(this);
xxxxxxxxxx
AdSlot adSlot = new AdSlot.Builder()
.setCodeId(codeId)
.setImageAcceptedSize(640, 320) // 单位px
.setAdCount(3) //请求广告数量为1到3条
.build();
参数 | 说明 |
setCodeId | 平台创建的代码位ID 以9开头9位数字 |
setAdCount | 请求数量1-3条,建议设置1 |
setImageAcceptedSize | 设置请求广告的尺寸 单位:px |
调用 mTTAdNative.loadStream(adSlot, new TTAdNative.FeedAdListener)
方法异步加载贴片广告。
mTTAdNative.loadStream(adSlot, new TTAdNative.FeedAdListener() {
//请求广告失败
public void onError(int code, String message) {
}
//请求广告成功
public void onFeedAdLoad(List<TTFeedAd> ads) {
if (ads == null || ads.isEmpty()) {
return;
}
if (mStreamAdPlayer != null) {
mStreamAdPlayer.clear();
}
// 使用自定义播放器需要考虑为视频Url预加载
// 各家开发者的视频播放器个有不同
// 需要预加载请在通过ttFeedAd.getCustomVideo().getVideoUrl()拿到视频url之后自行预加载
mStreamAdPlayer = new StreamAdPlayer(ads, mAdLayout);
}
});
回调 | 说明 |
onError() | 请求失败回调 |
onFeedAdLoad() | 请求成功回调 |
xxxxxxxxxx
public interface TTFeedAd {
/**
* 获取穿山甲logo,图片大小:80*80
*
* @return bitmap对象
*/
Bitmap getAdLogo();
/**
* 广告标题
*
* @return
*/
String getTitle();
/**
* 广告描述
*
* @return
*/
String getDescription();
/**
* 广告来源
*
* @return
*/
String getSource();
/**
* 广告图标Image
*
* @return
*/
TTImage getIcon();
/**
* 广告图片Image list
*
* @return
*/
List<TTImage> getImageList();
/**
* 得到Feed广告交互类型,贴片广告近为视频广告
*
* @return 2:在浏览器打开网页,3:在app中打开,4:下载应用,5:拨打电话 其它:未知类型
*/
int getInteractionType();
/**
* 得到Feed广告图片模式
*
* @return 3大图 2单图 4组图 16竖图 5横版视频 15竖版视频 166直播拉流 -1:未知类型
*/
int getImageMode();
/**
* 获取下载状态控制器
*/
DownloadStatusController getDownloadStatusController();
/**
* 注册可点击的View,click/show会在内部完成
*
* @param container 渲染广告最外层的ViewGroup
* @param clickView 可点击的View
*/
void registerViewForInteraction( ViewGroup container, View clickView, AdInteractionListener listener);
/**
* 注册可点击的View,click/show会在内部完成
*
* @param container 渲染广告最外层的ViewGroup
* @param clickViews 可点击的View的列表
* @param creativeViews 用于下载或者拨打电话的View
*/
void registerViewForInteraction( ViewGroup container, List<View> clickViews, List<View> creativeViews, AdInteractionListener listener);
/**
* 注册可点击的View,click/show会在内部完成,注册dislike按钮
*
* @param container 渲染广告最外层的ViewGroup
* @param clickViews 可点击的View的列表
* @param creativeViews 用于下载或者拨打电话的View
* @param dislikeView dislike按钮
* @param listener 点击回调
*/
void registerViewForInteraction( ViewGroup container, List<View> clickViews, List<View> creativeViews, View dislikeView, AdInteractionListener listener);
/**
* 设置下载监听器
*/
void setDownloadListener(TTAppDownloadListener downloadListener);
/**
* 兼容下载类广告,使用activity申请权限
*/
void setActivityForDownloadApp( Activity activity);
/**
* 获取广告的view,如视频广告的view,在广告平台可设置是否自动播放、是否静音等。
*
* @return
*/
View getAdView();
/**
* 信息流视频广告回调接口,仅适用于适用穿山甲播放器播放贴片视频广告
*/
interface VideoAdListener {
/**
* 视频广告加载成功
*
* @param ad
*/
void onVideoLoad(TTFeedAd ad);
/**
* 视频广告加载失败(原生MediaPlayer内部提供的错误类型)
* @param errorCode 错误类型:
* MEDIA_ERROR_UNKNOWN
* MEDIA_ERROR_SERVER_DIED
*
* @param extraCode 额外错误信息
* MEDIA_ERROR_IO
* MEDIA_ERROR_MALFORMED
* MEDIA_ERROR_UNSUPPORTED
* MEDIA_ERROR_TIMED_OUT
* MEDIA_ERROR_SYSTEM
*
*/
void onVideoError(int errorCode, int extraCode);
/**
* 视频广告播放回调
*
* @param ad
*/
void onVideoAdStartPlay(TTFeedAd ad);
/**
* 视频广告暂停回调
*
* @param ad
*/
void onVideoAdPaused(TTFeedAd ad);
/**
* 视频广告续播
*
* @param ad
*/
void onVideoAdContinuePlay(TTFeedAd ad);
}
void setVideoAdListener(VideoAdListener videoAdListener);
}
AdInteractionListener涉及到广告计费,必须正确调用 convertView必须使用ViewGroup。
在加载到贴片广告后,接入方需要注册在贴片广告中可以点击的View,即TTFeedAd.registerViewForInteraction()
方法,以实现广告的功能交互及计。包含图文点击区域的注册和附加创意按钮点击区域的注册。对于落地页广告,用户点击图文广告区域会跳转到相应的落地页,点击附加创意区域会进行电话拨打、应用下载等操作。
注意: 如果需要点击图文区域也能进行下载或者拨打电话动作,请将图文区域的view传入creativeViewList,详细代码如下。
注册点击View示例的示例代码如下,该示例片段在Demo的BaseAdapter getView()
方法中调用。
xxxxxxxxxx
/**
* 注册可点击的View,click/show会在内部完成
* @param container 渲染广告最外层的ViewGroup
* @param clickViews 可点击的View的列表
* @param creativeViews 用于下载或者拨打电话的View
*/
// 可以被点击的view, 也可以把convertView放进来意味整个item可被点击,点击会跳转到落地页
List<View> clickViewList = new ArrayList<View>();
clickViewList.add(convertView);
// 创意点击区域的view 点击根据不同的创意进行下载或拨打电话动作
//如果需要点击图文区域也能进行下载或者拨打电话动作,请将图文区域的view传入creativeViewList
List<View> creativeViewList = new ArrayList<View>();
creativeViewList.add(adViewHolder.mCreativeButton);
// 注册普通点击区域,创意点击区域。重要! 这个涉及到广告计费及交互,必须正确调用。convertView必须使用ViewGroup。
ad.registerViewForInteraction((ViewGroup) convertView, images, clickViewList, creativeViewList,adViewHolder.mDislike,new TTNativeAd.AdInteractionListener() {
// 点击普通区域的回调
public void onAdClicked(View view, TTNativeAd ad) {
}
// 点击创意区域的回调
public void onAdCreativeClick(View view, TTNativeAd ad) {
}
// 广告曝光展示的回调
public void onAdShow(TTNativeAd ad) {
}
});
回调 | 说明 |
onAdClicked() | 点击普通区域回调 |
onAdCreativeClick() | 点击创意区域回调 |
onAdShow() | 广告展示回调 |
当返回的广告为应用下载类型,即ad.getInteractionType() == TTAdConstant.INTERACTION_TYPE_DOWNLOAD 时,接入方可调用如下示例代码接入 Feed 广告下载控制器:
xxxxxxxxxx
private void bindDownLoadStatusController(AdViewHolder adViewHolder, final TTFeedAd ad) {
final DownloadStatusController controller = ad.getDownloadStatusController();
adViewHolder.mStopButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (controller != null) {
controller.changeDownloadStatus();
Toast.makeText(mContext, "改变下载状态", Toast.LENGTH_SHORT).show();
Log.d(TAG, "改变下载状态");
}
}
});
adViewHolder.mRemoveButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (controller != null) {
controller.cancelDownload();
Toast.makeText(mContext, "取消下载", Toast.LENGTH_SHORT).show();
Log.d(TAG, "取消下载");
}
}
});
}
xxxxxxxxxx
//下载监听设置
TTAppDownloadListener downloadListener = new TTAppDownloadListener() {
//未开始下载
public void onIdle() {
}
/**
* 下载中回调
* @param totalBytes 安装包总字节数 -1 :未知
* @param currBytes 当前已下载的字节数
* @param fileName 下载文件名称
* @param appName 当前下载的APP名
*/
"SetTextI18n") (
public void onDownloadActive(long totalBytes, long currBytes, String fileName, String appName) {
}
/**
* 下载暂停回调
* @param totalBytes 安装包总字节数 -1 :未知
* @param currBytes 当前已下载的字节数
* @param fileName 下载文件名称
* @param appName 当前下载的APP名
*/
"SetTextI18n") (
public void onDownloadPaused(long totalBytes, long currBytes, String fileName, String appName) {
}
/**
* 下载失败回调
* @param totalBytes 安装包总字节数 -1 :未知
* @param currBytes 当前已下载的字节数
* @param fileName 下载文件名称
* @param appName 当前下载的APP名
*/
public void onDownloadFailed(long totalBytes, long currBytes, String fileName, String appName) {
}
/**
* 安装完成回调
* @param fileName 下载文件名称
* @param appName 当前下载的APP名
*/
public void onDownloadFinished(long totalBytes, String fileName, String appName) {
}
/**
* 下载完成回调
* @param totalBytes 安装包总字节数 -1 :未知
* @param fileName 下载文件名称
* @param appName 当前下载的APP名
*/
public void onInstalled(String fileName, String appName) {
}
};
回调 | 说明 |
onIdle() | 绑定下载监听回调 |
onDownloadActive() | 下载中回调 |
onDownloadPaused() | 下载暂停回调 |
onDownloadFailed() | 下载失败回调 |
onDownloadFinished() | 下载完成回调 |
onInstalled() | 安装完成回调 |
如果App有自己实现的播放器,可以替代SDK中默认的播放器来播放广告,但是需要额外处理好生命周期和事件回调。
xxxxxxxxxx
class OneAd {
// 开发者自定义的播放器View
View adView;
double duration;
// 广告对象
TTFeedAd ttFeedAd;
public OneAd(View adView, double duration, TTFeedAd ttFeedAd) {
this.adView = adView;
this.duration = duration;
this.ttFeedAd = ttFeedAd;
}
public void play() {
if (adView instanceof VideoView) {
((VideoView)adView).start();
if (ttFeedAd.getCustomVideo() != null) {
// 使用自定义播放器需要上报视频播放的埋点
ttFeedAd.getCustomVideo().reportVideoStart();
}
}
}
public void stop() {
if (adView instanceof VideoView) {
if (ttFeedAd.getCustomVideo() != null) {
// 使用自定义播放器需要上报视频播放结束的埋点
ttFeedAd.getCustomVideo().reportVideoBreak(((VideoView) adView).getCurrentPosition());
}
}
}
public void pauseVideo() {
if (adView instanceof VideoView) {
((VideoView)adView).pause();
if (ttFeedAd.getCustomVideo() != null) {
// 使用自定义播放器需要上报视频暂停埋点
ttFeedAd.getCustomVideo().reportVideoPause(((VideoView) adView).getCurrentPosition());
}
}
}
public void continueVideo() {
if (adView instanceof VideoView) {
// Android 自带的VideoView继续播放有关键帧问题
// 请使用自己的播放器自行处理继续播放的问题
((VideoView)adView).start();
if (ttFeedAd.getCustomVideo() != null) {
// 使用自定义播放器需要上报视频继续播放埋点
ttFeedAd.getCustomVideo().reportVideoContinue(((VideoView) adView).getCurrentPosition());
}
}
}
}
xxxxxxxxxx
// StreamAdPlayer 的 getVideoTypeView
public OneAd getVideoTypeView(final TTFeedAd ttFeedAd) {
if (ttFeedAd == null || ttFeedAd.getCustomVideo() == null) {
return null;
}
// 这里new出来的是就是自定义的播放器暂时使用android自带的播放器
// •暂时使用android自带的播放器,开发者此处应该生成自己的播放器
VideoView videoView = new VideoView(getApplicationContext());
videoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
public void onCompletion(MediaPlayer mp) {
// 播放器播放结束回调时,应该调用此处进行事件上报
if (ttFeedAd.getCustomVideo() != null) {
ttFeedAd.getCustomVideo().reportVideoFinish();
}
}
});
// 设置Videourl
videoView.setVideoURI(Uri.parse(ttFeedAd.getCustomVideo().getVideoUrl()));
// 设置布局等
ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.WRAP_CONTENT);
videoView.setLayoutParams(layoutParams);
...
// 此处返回广告封装对象时,参数里传入播放器实例
return new OneAd(videoView, ttFeedAd.getVideoDuration(), ttFeedAd);
}
xxxxxxxxxx
mTTAdNative.loadStream(adSlot, new TTAdNative.FeedAdListener() {
public void onFeedAdLoad(List<TTFeedAd> ads) {
...
// 使用自定义播放器需要考虑为视频Url预加载
// 需要预加载请在此处通过ttFeedAd.getCustomVideo().getVideoUrl()拿到视频url之后自行预加载
...
}
});
xxxxxxxxxx
// Activity中
protected void onPause() {
super.onPause();
if (mStreamAdPlayer != null) {
mStreamAdPlayer.onPause();
}
}
protected void onResume() {
super.onResume();
if (mStreamAdPlayer != null) {
mStreamAdPlayer.onResume();
}
}
...
// StreamAdPlayer 类中
public void onPause() {
// 此处pauseVideo是为了通知自定义播放器暂停
if (mNowPlayAd != null) {
mNowPlayAd.pauseVideo();
}
mHandler.postDelayedPause();
}
public void onResume() {
// 此处continueVideo是为了自定义播放器续播
if (mNowPlayAd != null) {
mNowPlayAd.continueVideo();
}
mHandler.postDelayedResume();
}
方法 | 说明 |
getVideoUrl() | 获取视频url |
reportVideoStart() | 上报播放开始 |
reportVideoPause() | 上报播放暂停 |
reportVideoContinue() | 上报播放继续 |
reportVideoFinish() | 上报播放结束 |
reportVideoBreak() | 上报播放中止 |
reportVideoAutoStart() | 上报自动播放 |
reportVideoStartError() | 上报起播错误 |
reportVideoError() | 上报播放中错误 |
在获得TTFeedAd后,调用TTFeedAd.getDislikeDialog()获取TTAdDislike对象,然后为该对象设置用户选择结果回调。事例代码:
xxxxxxxxxx
private void bindDislikeAction(View dislike, final TTFeedAd ad, boolean isCustomDislike) {
if (isCustomDislike) {
// 使用自定义Dislike,用户选择"为什么看到此广告",开发者需要执行startPersonalizePromptActivity逻辑进行跳转
final DislikeInfo dislikeInfo = ad.getDislikeInfo();
if (dislikeInfo == null || dislikeInfo.getFilterWords() == null || dislikeInfo.getFilterWords().isEmpty()) {
return;
}
final DislikeDialog dislikeDialog = new DislikeDialog(this, dislikeInfo);
dislikeDialog.setOnPersonalizationPromptClick(new DislikeDialog.OnPersonalizationPromptClick() {
public void onClick(PersonalizationPrompt personalizationPrompt) {
TToast.show(FeedVideoActivity.this, "点击了为什么看到此广告");
}
});
ad.setDislikeDialog(dislikeDialog);
dislike.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
dislikeDialog.show();
}
});
} else {
// 使用默认Dislike
final TTAdDislike ttAdDislike = ad.getDislikeDialog(this);
dislike.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (ttAdDislike != null)
ttAdDislike.showDislikeDialog();
}
});
}
}
回调 | 说明 |
onItemClick() | 自定义样式情况下用户点击filterWord回调 |
onClick() | 自定义样式情况下用户点击了”为什么看到此广告“ |
onSelected() | 默认dislike样式,点击filterWord回调。开发者可以在此回调中移除广告 |
onCancel() | 默认dislike样式,点击取消回调 |
onShow() | 默认dislike样式,dislike弹窗展示回到 |
onRefuse() | 默认dislike样式,用户重复点击dislike按钮回调,3600版本废除 |
5.1.0.0及以上版本,dislike功能下,“为什么看到此广告”接口标记废弃
复制
xxxxxxxxxx
// DislikeInfo.java
/**
* 获得为什么看到此广告信息
* @return
*/
PersonalizationPrompt getPersonalizationPrompt();
// PersonalizationPrompt.java
public interface PersonalizationPrompt {}
// TTDislikeController.java
/**
* 5100版本去除,保留接口及空实现
*/
void onDislikeEvent(Context context, boolean isShow);
/**
* 5100版本去除,保留接口及空实现
*/
void openWebPage(Context context, boolean isDiy);
// TTDislikeDialogAbstract.java
/**
* 启动为什么看到此界面Activity
* 5100版本废弃
*/
public void startPersonalizePromptActivity() {
}
5.1.0.0及以上版本,NativeAdType的get和set方法标记废弃
xxxxxxxxxx
// TTAdSlot.java
int getNativeAdType();
void setNativeAdType(int nativeAdType);
xxxxxxxxxx
ad.uploadDislikeEvent("xxx"); // v>6.0.0.0新增Dislike自主上报接口,String类型即可。
AdInteractionListener涉及到广告计费,必须正确调用 convertView
必须使用ViewGroup。
自渲染渲染贴片请参考Demo中StreamActivity
使用自定义播放器可参看Demo中StreamCustomPlayerActivity