优推聚合 Android SDK 接入文档
优推聚合 Android SDK 接入文档
一、SDK版本更新记录
SDK版本 | 修改日期 | 修改说明 |
---|---|---|
2.2.9 | 2023-09-15 | 1.更新三方SDK:优推adn v3.0.10 2.修复已知问题 |
2.2.7 | 2023-09-07 | 1.增加兜底广告源功能 2.支持SDK本地化预置策略功能 3.支持Gromore本地缓存配置 4.预缓存广告逻辑优化 5.更新三方SDK:优推ADXv3.0.9 |
2.1.19 | 2023-08-25 | 修复已知问题 |
2.1.18 | 2023-08-21 | 更新三方adn 快手:v3.3.51.1 穿山甲:v5.5.1.5 百度:v9.313 优量汇:v4.540.1410 sigmob:v4.12.6 倍孜:v4.90.2.55 mtg:v16.4.91 优推ADX:v3.0.6 |
2.1.15 | 2023-08-12 | 修复已知问题 |
2.1.13 | 2023-08-03 | 1.增加bidding与瀑布流并行功能 2. 增加缓存池底价和竞价底价功能 3.更新三方SDK:优推ADXv3.0.3 4.修复已知问题 |
2.1.6 | 2023-07-21 | 1.优化sdk初始化速度 2.兼容优量汇半屏开屏广告 3.修复已知问题 |
2.0.5 | 2023-07-06 | 1.优化SDK逻辑 2.修复已知问题 3.使用第三方SDK版本 百度 v9.28,快手 v3.3.42,穿山甲(包含GroMore) v5.1.7.3,流量汇 v4.520.1390,SigMob v4.12.2,倍孜 v4.90.2.36,Oneway v2.5.3, Mintegral v16.4.41,优推ADX v2.0.8 |
二、SDK接入准备
接入聚合变现SDK前,请您联系平台人员申请对应的AppId,广告位 id 等
三、接入SDK
3.1 导入aar
SDK接入使用aar的方式进行接入,解压提供的聚合广告SAAdSDK文件,在压缩包中找到adalliance_x.x.x.aar和第三方平台 aar,拷贝aar库到libs文件中 。
SDK下载地址: SDK下载
3.2 添加依赖
在根目录的build.gradle中添加:
buildscript {
repositories {
google()
jcenter()
//mintegral sdk依赖 引入mintegral sdk需要添加此maven
maven {
url "https://dl-maven-android.mintegral.com/repository/mbridge_android_sdk_oversea"
}
}
dependencies {
classpath "com.android.tools.build:gradle:4.1.0"
}
}
allprojects {
repositories {
google()
jcenter()
//mintegral sdk依赖 引入mintegral sdk需要添加此maven
maven {
url "https://dl-maven-android.mintegral.com/repository/mbridge_android_sdk_oversea"
}
}
}
在app工程下的build.gradle文件中添加依赖,代码如下:
dependencies {
implementation 'com.squareup.okhttp3:okhttp:3.10.0'
implementation 'com.squareup.okhttp3:logging-interceptor:3.12.0'
implementation 'com.google.code.gson:gson:2.8.0'
//Glide
implementation 'com.github.bumptech.glide:glide:4.8.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.8.0'
//广告alliance sdk
implementation(name: 'adalliance_2.2.9_release', ext: 'aar')
//优推adn广告sdk
implementation(name: 'adalliance_adn_sdk.3.0.10', ext: 'aar')
//快手联盟广告sdk
implementation(name: 'kssdk-ad-3.3.51.1', ext: 'aar')
//穿山甲
implementation(name: 'open_ad_sdk_5.5.1.5', ext: 'aar')
//流量汇
implementation(name: 'GDTSDK.unionNormal.4.540.1410', ext: 'aar')
//Sigmob
implementation(name: 'wind-sdk-4.12.6', ext: 'aar')
implementation(name: 'wind-common-1.4.9', ext: 'aar')
//百度广告
implementation(name:'Baidu_MobAds_SDK-release_v9.313',ext:'aar')
//倍孜广告
implementation(name: 'beizi_fusion_sdk_4.90.2.55', ext: 'aar')
implementation(name: 'beizi_ad_sdk_3.4.20.35', ext: 'aar')
//Oneway
implementation(name: 'Oneway-2.5.3-release', ext: 'aar')
//mtg
//支持Android X 版本
implementation 'com.mbridge.msdk.oversea:reward:16.4.91'
implementation 'com.mbridge.msdk.oversea:mbnative:16.4.91'
implementation 'com.mbridge.msdk.oversea:mbsplash:16.4.91'
implementation 'com.mbridge.msdk.oversea:mbbanner:16.4.91'
implementation 'com.mbridge.msdk.oversea:newinterstitial:16.4.91'
implementation 'com.mbridge.msdk.oversea:mbnativeadvanced:16.4.91'
//如果您需要使用竞价广告,请添加此条依赖语句。(mbbid)
implementation 'com.mbridge.msdk.oversea:mbbid:16.4.91'
implementation 'com.tencent:mmkv:1.0.19'
implementation ('com.google.android.exoplayer:exoplayer:2.11.4'){
exclude group:'androidx.core',module:'core'
exclude group:'androidx.appcompat',module:'appcompat'
exclude group:'androidx.constraintlayout',module:'constraintlayout'
exclude group:'androidx.test',module:'test'
exclude group:'androidx.annotation',module:'annotation'
exclude group:'androidx.collection',module:'collection'
exclude group:'androidx.media',module:'media'
exclude group:'androidx.versionedparcelable',module:'versionedparcelable'
}
}
3.3 AndroidManifest.xml⽂件配置
需要相关权限,请在您的App的AndroidManifest.xml⽂件中,添加配置如下:
<!--网络状态-->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!--联网权限-->
<uses-permission android:name="android.permission.INTERNET" />
<!--获取设备标识-->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<!--获取MAC地址-->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!--获取安装应用权限-->
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<!--读写权限-->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<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.QUERY_ALL_PACKAGES" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!-- 穿山甲如果有视频相关的广告且使用textureView播放,请务必添加,否则黑屏 -->
<uses-permission android:name="android.permission.WAKE_LOCK/>
<!--必要权限,解决安全风险漏洞,发送和注册广播事件需要调用带有传递权限的接口-->
<permission
android:name="${applicationId}.openadsdk.permission.TT_PANGOLIN"
android:protectionLevel="signature" />
<uses-permission android:name="${applicationId}.openadsdk.permission.TT_PANGOLIN" />
<provider
android:name="com.alliance.ssp.ad.utils.NMSSPFileProvider"
android:authorities="${applicationId}.NMSSPFileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/nmssp_file_path" />
</provider>
<!-- 穿山甲 start -->
<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>
<provider
android:name="com.bytedance.sdk.openadsdk.multipro.TTMultiProvider"
android:authorities="${applicationId}.TTMultiProvider"
android:exported="false" />
<!-- 穿山甲 end -->
<!-- 优量汇 start -->
<!-- targetSDKVersion >= 24时才需要添加这个provider。provider的authorities属性的值为${applicationId}.fileprovider,
请开发者根据自己的${applicationId}来设置这个值,例如本例中applicationId为"com.qq.e.union.demo"。 >
<provider
android:name="com.qq.e.comm.GDTFileProvider"
android:authorities="${applicationId}.gdt.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/gdt_file_path" />
</provider>
<!-- 优量汇 end -->
<!-- sigmob start -->
<activity
android:name="com.sigmob.sdk.base.common.AdActivity"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
/>
<!-- targetSDKVersion >= 24时才需要添加这个provider。
provider的authorities属性的值为${applicationId}.sigprovider -->
<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>
<!-- sigmob end -->
3.4 ABI架构
部分广告平台的SDK中带有so库
建议: 在build.gradle中添加如下配置
defaultConfig {
...
ndk{
abiFilters 'armeabi-v7a','arm64-v8a'
}
}
3.5 在res/xml目录下添加xml文件
添加文件nmssp_file_path.xml
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-cache-path name="nmssp_external_download_path" path="nmssp_download"/>
</paths>
添加文件pangle_file_paths.xml
<?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>
添加文件 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>
添加文件 sigmob_provider_paths.xml
<paths>
<!-- 这个下载路径不可以修改,SigDownload -->
<external-cache-path
name="SigMob_root"
path="SigDownload" />
<external-path
name="SigMob_root_external"
path="." />
</paths>
3.6 混淆配置
请确保您的应⽤打包混淆时,请在混淆配置⽂件proguard-rules.pro,添加如下配置:
-keepclassmembers class **.R$* {
public static <fields>;
}
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
-keep public class * extends android.app.Fragment
-ignorewarnings
-keep class androidx.annotation.** {*;}
-keep class com.alliance.ssp.ad.api.** { *; }
# 聚合 sdk
-keep class com.alliance.** {*;}
# 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
-keep class bykvm*.**
-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>;
}
-keepclassmembers class * {
*** getContext(...);
*** getActivity(...);
*** getResources(...);
*** startActivity(...);
*** startActivityForResult(...);
*** registerReceiver(...);
*** unregisterReceiver(...);
*** query(...);
*** getType(...);
*** insert(...);
*** delete(...);
*** update(...);
*** call(...);
*** setResult(...);
*** startService(...);
*** stopService(...);
*** bindService(...);
*** unbindService(...);
*** requestPermissions(...);
*** getIdentifier(...);
}
-keep class com.bytedance.pangle.** {*;}
-keep class com.bytedance.sdk.openadsdk.** { *; }
-keep class com.bytedance.frameworks.** { *; }
-keep class ms.bd.c.Pgl.**{*;}
-keep class com.bytedance.mobsec.metasec.ml.**{*;}
-keep class com.ss.android.**{*;}
-keep class com.bytedance.embedapplog.** {*;}
-keep class com.bytedance.embed_dr.** {*;}
-keep class com.bykv.vk.** {*;}
# 快手 sdk
-keep class org.chromium.** {*;}
-keep class org.chromium.** { *; }
-keep class aegon.chrome.** { *; }
-keep class com.kwai.**{ *; }
-dontwarn com.kwai.**
-dontwarn com.kwad.**
-dontwarn com.ksad.**
-dontwarn aegon.chrome.**
# mtg sdk
-keepattributes Signature
-keepattributes *Annotation*
-keep class com.mbridge.** {*; }
-keep interface com.mbridge.** {*; }
-keep class android.support.v4.** { *; }
-dontwarn com.mbridge.**
-keep class **.R$* { public static final int mbridge*; }
# 百度 sdk
-ignorewarnings
-dontwarn com.baidu.mobads.sdk.api.**
-keepclassmembers class * extends android.app.Activity {
public void *(android.view.View);
}
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
-keep class com.baidu.mobads.** { *; }
-keep class com.style.widget.** {*;}
-keep class com.component.** {*;}
-keep class com.baidu.ad.magic.flute.** {*;}
-keep class com.baidu.mobstat.forbes.** {*;}
# 倍孜 sdk
-dontwarn com.beizi.fusion.**
-dontwarn com.beizi.ad.**
-keep class com.beizi.fusion.** {*; }
-keep class com.beizi.ad.** {*; }
-keep class com.google.android.exoplayer2.** {*; }
-keep class com.github.ykrank.androidlifecycle.** { *; }
如果您的应⽤启⽤了资源混淆或资源缩减,您需要保留SDK的资源,SDK的资源名都是包含nmadssp关键字的。您可以在资源混淆配置⽂件添加如下配置:
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools"
tools:keep="@layout/layout_nmssp_*,@id/nmadssp_*,@style/nmadssp_*,
@drawable/nmadssp_*,@string/nmadssp_*,@color/nmadssp_*,@attr/
nmadssp_*,@dimen/nmadssp_*" />
四、SDK初始化
请在您应⽤的 Application 的 onCreate() ⽅法中调⽤以下代码来初始化⼴告sdk。
SAAllianceAdInitParams initParams = new SAAllianceAdInitParams.Builder()
.setKeyEvent(true) // 是否开启增长助手,如果不使用可不开启 选填
.setDebug(true) // 是否开启debug日志打印
.setMainChannelId("") // 主渠道id 必填可自定义传参,例如"VIVO"
.setChildChannelId("") // 子渠道id 必填可自定义传参,例如"VIVO"
.setInitCallback(new SAAllianceAdInitCallback() {
@Override
public void onSuccess() {
// 初始化成功
}
@Override
public void onFail(int errorCode, String errorMessage) {
// 初始化失败
}
}).build();
SAAllianceAdSdk.init("app id", context, initParams);// appid 必填
注:开通增长助手功能请联系商务
预置策略配置说明
当遇到应用首次安装并且网络拉取配置失败时,客户端表现为请求策略失败,可使用此功能。可在平台提前下载瀑布流配置导入到工程中,在SDK初始化时配置使用。该功能适用于所有广告类型。
//聚合SDK预置策略配置文件,支持广告位下的预置策略配置
List<String> presetStrategies = new ArrayList<>();
presetStrategies.add(jsonFromFilename(application, "10000227.json"));
presetStrategies.add(jsonFromFilename(application, "50000038.json"));
//gromore本地缓存配置
String csjJson = jsonFromFilename(this, "site_config_5392071.json");
SAAllianceAdInitParams initParams = new SAAllianceAdInitParams.Builder()
.setKeyEvent(true) // 是否开启关键行为,如果不使用可不开启 选填
.setDebug(true) // 是否开启debug日志打印
.setMainChannelId("") // 主渠道id 必填可自定义传参,例如"VIVO"
.setChildChannelId("") // 子渠道id 必填可自定义传参,例如"VIVO"
.setPresetStrategies(presetStrategies) //聚合SDK预置策略配置
.setCSJPresetStrategy(csjJson) //gromore本地缓存配置
.setInitCallback(new SAAllianceAdInitCallback() {
@Override
public void onSuccess() {
// 初始化成功
}
@Override
public void onFail(int errorCode, String errorMessage) {
// 初始化失败
}
}).build();
SAAllianceAdSdk.init("app id", context, initParams);// appid 必填
public static String jsonFromFilename(Application application, String filename) {
StringBuilder stringBuilder = new StringBuilder();
try {
BufferedReader bf = new BufferedReader(new InputStreamReader(
application.getAssets().open(filename)));
String line;
while ((line = bf.readLine()) != null) {
stringBuilder.append(line);
}
} catch (Exception e) {
e.printStackTrace();
}
return stringBuilder.toString();
}
五、广告加载
5.1 开屏广告
请求开屏示例
// 页面跳转逻辑处理
private boolean adClick;
private boolean canJump = false;
@Override
protected void onResume() {
super.onResume();
canJump = true;
adClick = false;
}
@Override
protected void onPause() {
super.onPause();
canJump = false;
}
@Override
protected void onStop() {
super.onStop();
canJump = false;
}
SASplashAd splashAd;
private void loadSplashView(String sposId) {
splashAd = new SASplashAd(splashactivity, postId, new SABaseAd.LoadListener() {
@Override
public void onLoaded() {
// show
splashAd.showInContainer(mSplashContainer);
}
@Override
public void onError(AdError adError) {
}
});
splashAd.setInteractionListener(new SASplashAd.InteractionListener() {
@Override
public void sa_splashShowFail(AdError adError) {
}
@Override
public void sa_splashDidShow() {
canJump = true;
}
@Override
public void sa_splashDidClick() {
adClick = true;
}
@Override
public void sa_splashDidSkip() {
next();
}
@Override
public void sa_splashDidTimeOver() {
//有的广告在播完或者点击广告之后会调用这个函数,然后会造成app主页覆盖广告落地页的情况
if (canJump && !adClick) {
next();
}
}
@Override
public void sa_splashLifeTime(long l) {
}
@Override
public void sa_splashDidExposure() {
}
});
//如果开屏需要自定义底部logo需要传入广告容器尺寸,否则不需要传广告容器尺寸
splashAd.setAdSize(new SAAdSize(width,height));
splashAd.loadAd();
}
private void next() {
// 页面跳转
}
SASplashAd
// 获取ecpm,单位为分
public String getEcpm();
// 获取adn错误列表
public List<AdError> getAdErrorList();
// 判断广告是否可用
public boolean isReady();
// 获取本次填充的广告平台名称
public String getPlatformName();
// SASplashAd构造函数
public SASplashAd(Activity activity, String slotId, SABaseAd.LoadListener loadListener);
// 加载广告
public void loadAd();
// 展示广告
public void showInContainer(ViewGroup container);
// 支持半屏开屏广告
public void setAdSize(SAAdSize adSize);
SASplashAd.InteractionListener
方法名 | 方法说明 |
---|---|
void sa_splashShowFail(AdError var1); | 展示失败 |
void sa_splashDidShow(); | 展示成果 |
void sa_splashDidClick(); | 广告点击 |
void sa_splashDidSkip(); | 点击跳过 |
void sa_splashDidTimeOver(); | 播放完毕 |
void sa_splashLifeTime(long var1); | 开屏倒计时 |
void sa_splashDidExposure(); | 开屏广告曝光 |
AdError说明
adErrorCode | 错误码 |
---|---|
adErrorMsg | 错误信息 |
platformName | 广告平台名称 |
adSourceId | 聚合广告位ID |
codeId | 广告源ID |
SAAdSize说明
width | 容器的宽(dp) |
---|---|
height | 容器的高(dp) |
5.2 插屏广告
SAInterstitialAd
// 获取ecpm,单位为分
public String getEcpm();
// 获取adn错误列表
public List<AdError> getAdErrorList();
// 判断广告是否可用
public boolean isReady();
// 获取本次填充的广告平台名称
public String getPlatformName();
// SAInterstitialAd构造函数
public SAInterstitialAd(Activity activity, String slotId, SABaseAd.LoadListener loadListener);
// 加载广告
public void loadAd();
// 展示广告
public void showAtActivity(Activity activity);
// 设置静音
public void setVideoMuted(boolean videoMuted)
请求插屏示例
private void getInterstitialView(String posId) {
mInterstitialAd = new SAInterstitialAd(this, posId, this);
mInterstitialAd.setVideoMuted(true);//设置插屏视频静音
mInterstitialAd.setInteractionListener(this);
mInterstitialAd.loadAd();
}
@Override
public void onLoaded() {
// 加载成功
// 展示插屏
mInterstitialAd.showAtActivity(this);
// 如果加载和展示相隔时间较久,需要调用isReady判断广告是否失效
}
@Override
public void onError(AdError error) {
// 加载失败
}
@Override
public void sa_interstitialShowFail(AdError error) {
// 展示失败
}
@Override
public void sa_interstitialDidShow() {
// 插屏展示
}
@Override
public void sa_interstitialDidClick() {
// 插屏点击
}
@Override
public void sa_interstitialDidSkip() {
// 插屏视频跳过,部分广告平台有此回调
}
@Override
public void sa_interstitialDidClose() {
// 插屏关闭
}
@Override
public void sa_interstitialDidExposure() {
// 插屏曝光
}
SAInterstitialAd.InteractionListener
方法名 | 方法说明 |
---|---|
void sa_interstitialShowFail(AdError error); | 展示失败 |
void sa_interstitialDidShow(); | 展示成功 |
void sa_interstitialDidClick() | 广告点击 |
void sa_interstitialDidSkip() | 广告跳过 |
void sa_interstitialDidClose() | 广告关闭 |
void sa_interstitialDidExposure | 广告曝光 |
5.3 激励广告
请求激励示例
private void loadAd(String posId) {
mRewardAd = new SARewardVideoAd(this, posId, this);
mRewardAd.setVideoMuted(false);//设置插屏视频静音
mRewardAd.loadAd();
mRewardAd.setInteractionListener(this);
}
private void showAd() {
mRewardAd.show(this);
}
@Override
public void onLoaded() {
// 加载成功
// 展示插屏
showAd();
// 如果加载和展示相隔时间较久,需要调用isReady判断广告是否失效
}
@Override
public void onError(AdError error) {
// 加载失败
}
@Override
public void sa_rewardVideoShowFail(AdError error) {
// 展示失败
}
@Override
public void sa_rewardVideoDidShow() {
// 展示成功
}
@Override
public void sa_rewardVideoDidClick() {
// 广告点击
}
@Override
public void sa_rewardVideoDidSkip() {
// 广告跳过
}
@Override
public void sa_rewardVideoDidPlayFinish() {
// 播放完毕
}
@Override
public void sa_rewardVideoDidClose() {
// 广告关闭
}
@Override
public void sa_rewardVideoDidExposure() {
// 广告曝光
}
@Override
public void sa_rewardVideoDidRewardEffective(boolean effective) {
// 广告激励结果回调
}
SARewardVideoAd
// 获取ecpm,单位为分
public String getEcpm();
// 获取adn错误列表
public List<AdError> getAdErrorList();
// 判断广告是否可用
public boolean isReady();
// 获取本次填充的广告平台名称
public String getPlatformName();
// SARewardVideoAd构造函数
public SARewardVideoAd(Activity activity, String slotId, LoadListener loadListener)
// 加载广告
public void loadAd();
// 展示广告
public void show(Activity activity);
// 设置静音
public void setVideoMuted(boolean videoMuted)
SARewardVideoAd.InteractionListener
方法名 | 方法说明 |
---|---|
void sa_rewardVideoShowFail(AdError error) | 展示失败 |
void sa_rewardVideoDidShow | 展示成功 |
void sa_rewardVideoDidClick() | 广告点击 |
void sa_rewardVideoDidSkip() | 广告跳过 |
void sa_rewardVideoDidPlayFinish() | 视频播放完毕 |
void sa_rewardVideoDidClose() | 广告关闭 |
void sa_rewardVideoDidExposure() | ⼴告曝光 |
void sa_rewardVideoDidRewardEffective(boolean effective) | 激励结果回调 |
5.4 Banner广告
请求Banner示例
SABannerAd bannerAd = new SABannerAd(postId, act_);
bannerAd.setLoadListener(new SABaseAd.LoadListener() {
@Override
public void onLoaded() {
bannerAd.render();
}
@Override
public void onError(AdError adError) {
}
});
bannerAd.setInteractionListener(new SABannerAd.InteractionListener() {
@Override
public void sa_bannerRenderSuccess() {
adContainer.removeAllViews();
adContainer.addView(bannerAd.getAdView());
}
@Override
public void sa_bannerRenderFailure(AdError adError) {
}
@Override
public void sa_bannerShowFailure(AdError adError) {
}
@Override
public void sa_bannerDidShow() {
}
@Override
public void sa_bannerDidClick() {
}
@Override
public void sa_bannerDidClose() {
}
@Override
public void sa_bannerDidExposure() {
}
});
bannerAd.setAdSize(new SAAdSize(adWidth, adHeight));
bannerAd.load();
SABannerAd
// 获取ecpm,单位为分
public String getEcpm();
// 获取adn错误列表
public List<AdError> getAdErrorList();
// 判断广告是否可用
public boolean isReady();
// 获取本次填充的广告平台名称
public String getPlatformName();
// SABannerAd构造函数
public SABannerAd(Activity activity, String slotId, LoadListener loadListener)
// 加载广告
public void loadAd();
// 展示广告
adContainer.addView(bannerAd.getAdView());
SABaseAd.LoadListener
方法名 | 方法说明 |
---|---|
void onLoaded() | 加载成功 |
void onError(AdError error) | 加载失败 |
SABannerAd.InteractionListener
方法名 | 方法说明 |
---|---|
void sa_bannerRenderSuccess() | 广告渲染成功 |
void sa_bannerRenderFailure(AdError error) | 广告渲染失败 |
void sa_bannerShowFailure(AdError error) | 广告展示失败 |
void sa_bannerDidShow() | 广告已经展示 |
void sa_bannerDidClick() | 广告点击 |
void sa_bannerDidExposure() | 广告曝光 |
void sa_bannerDidClose() | 广告点击关闭 |
5.5 信息流广告
请求信息流广告示例
private void loadAd() {
feedAdManager = new SAFeedAdManager("posid");
feedAdManager.setActivity(this);
feedAdManager.setMuted(true);
feedAdManager.setAdSize(new SAAdSize(width, Height));
feedAdManager.setLoadListener(new SAFeedAdManager.LoadListener() {
@Override
public void onFeedAdLoad(List<SAFeedAd> ads) {
if (list != null && list.size() > 0) {
SAFeedAd feedAd = list.get(0);
if (feedAd.isExpress()) {
//模板渲染
SAExpressFeedAd expressFeedAd = feedAd.getExpressFeedAd();
expressFeedAd.setInteractionListener(new SAExpressFeedAd.InteractionListener() {
@Override
public void sa_feedAdRenderSuccess() {
View adView = expressFeedAd.getAdView();
adContainer.removeAllViews();
adContainer.addView(view);
}
@Override
public void sa_feedAdRenderFailure(AdError adError) {}
@Override
public void sa_feedAdShowFail(AdError adError) {}
@Override
public void sa_feedAdDidShow() {}
@Override
public void sa_feedAdDidClick() {}
@Override
public void sa_feedAdDidExposure() {}
@Override
public void sa_feedAdDidClose() {}
});
feedAd.getExpressFeedAd().isReady();
feedAd.getExpressFeedAd().render();
}else {
//自渲染参考下面示例代码
}
}
}
@Override
public void onError(AdError error) {
}
});
feedAdManager.loadFeedAd();
}
SAFeedAdManager说明
public class SAFeedAdManager {
// 获取个ADN加载失败的错误信息
public List<AdError> getAdErrorList() {}
// 设置监听
public void setLoadListener(SAFeedAdManager.LoadListener loadListener) {}
// 构造函数
public SAFeedAdManager(String slotId) {}
// 设置视频类信息流是否静音
public void setMuted(boolean muted) {}
// 设置activity
public void setActivity(Activity activity) {}
/**
* 期望广告的size,宽度最低为375,单位dp
* 高度建议设置为0
* @param adSize size
*/
public void setAdSize(SAAdSize adSize) {
this.adSize = adSize;
}
// 加载广告
public void loadFeedAd() {}
public interface LoadListener {
void onFeedAdLoad(List<SAFeedAd> ads);
void onError(AdError error);
}
}
SAFeedAd说明
public class SAFeedAd {
// 是否是模版渲染信息流广告
// if true 请调用getExpressFeedAd函数,获取SAExpressFeedAd类型广告
// if false 请调用getNativeAdData函数,获取SANativeAdData类型广告
public boolean isExpress() {}
//获取SAExpressFeedAd类型广告
public SAExpressFeedAd getExpressFeedAd() {}
//获取SANativeAdData类型广告
public SANativeAdData getNativeAdData() {}
}
SAExpressFeedAd.InteractionListener
方法名 | 方法说明 |
---|---|
void sa_feedAdRenderSuccess() | 广告渲染成功 |
void sa_feedAdRenderFailure(AdError error) | 广告渲染失败 |
void sa_feedAdShowFail(AdError error) | 广告展示失败 |
void sa_feedAdDidShow() | 广告已经展示 |
void sa_feedAdDidClick() | 广告点击 |
void sa_feedAdDidExposure() | 广告曝光 |
void sa_feedAdDidClose() | 广告点击关闭 |
SANativeAdData说明
方法名 | 方法说明 |
---|---|
String getTitle() | 广告标题 |
String getDescription() | 广告文字内容 |
Bitmap getAdLogo() | 获取广告平台logo bitmap |
String getAdLogoUrl() | 获取广告平台logo url |
String getIconUrl() | 获取icon url |
List<String>getImageList() | 获取图片url列表 |
SANativeADMediaMode getFeedAdMode() | 获取广告媒体素材类型,一图、多图、视频等形式 |
String getEcpm() | 获取价格,单位为分 |
String getPlatformName() | 获取ADN名称 |
SANativeADMediaMode 自渲染广告媒体素材类型说明
public enum SANativeADMediaMode {
// 单张图片
OneImage,
// 多张图片
GroupImage,
// 视频类型
Video,
// 只有一个appIcon类型
OnlyIcon,
}
bindAdToView说明
/**
* @param adContainer 自渲染广告最外层的容器,必选
* @param clickViews 所有可以点击的view,必选
* @param ctaViews 触发创意广告的view(点击下载或拨打电话)
* @param disLike
* @param imgViews
* @param listener
*/
public void bindAdToView(ViewGroup adContainer, ImageView icon, ImageView adLogo, List<View> clickViews, List<View> ctaViews, View disLike, ViewGroup mediaContainer, List<ImageView> imgViews, SAUnifiedFeedAdInteractionListener listener) {
@Override
public void onAdShow() {
// 展示
}
@Override
public void onAdClick() {
// 点击
}
@Override
public void onAdError(int errorCode, String msg) {
// 展示失败
}
});
示例代码
public class MixFeedActivity extends Activity {
private SAFeedAdManager feedAdManager;
private List<SAFeedAd> feedAds = new ArrayList<>();
private LoadMoreListView listView;
private FeedListAdapter mFeedListAdapter;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_mix_feed);
listView = findViewById(R.id.feed_list);
listView.setLoadMoreListener(() -> {
loadAd();
});
mFeedListAdapter = new FeedListAdapter(this, feedAds);
listView.setAdapter(mFeedListAdapter);
loadAd();
}
private void loadAd() {
feedAdManager = new SAFeedAdManager("id");
feedAdManager.setActivity(this);
feedAdManager.setMuted(true);
DisplayMetrics metrics = getResources().getDisplayMetrics();
float scale = metrics.density;
int width = (int) (metrics.widthPixels / (scale <= 0 ? 1 : scale) + 0.5f);
feedAdManager.setAdSize(new SAAdSize(width, 0));
feedAdManager.setLoadListener(new SAFeedAdManager.LoadListener() {
@Override
public void onFeedAdLoad(List<SAFeedAd> ads) {
// 广告请求成功
if (listView != null) {
listView.setLoadingFinish();
}
if (ads == null || ads.isEmpty()) {
// 广告数据为空
return;
}
int loadCount = 15;// 模拟每次展示的Item刷新个数
for (int i = 0; i < loadCount; i++) {
feedAds.add(null);
}
int totalCount = feedAds.size();
Set<Integer> set = new HashSet<>();
for (SAFeedAd feedAd : ads) {
if (feedAd == null) {
continue;
}
int random = (int) (Math.random() * loadCount) + totalCount - loadCount;
while (set.contains(random)) {
random = (int) (Math.random() * loadCount) + totalCount - loadCount;
}
set.add(random);
feedAds.set(random, feedAd);
setFeedAdInteractionListener(feedAd);
}
mFeedListAdapter.notifyDataSetChanged();
}
@Override
public void onError(AdError error) {
if (listView != null) {
listView.setLoadingError();
}
// 广告请求失败
}
});
feedAdManager.loadFeedAd();
}
private void setFeedAdInteractionListener(SAFeedAd mixFeedAd) {
//模板渲染
if (mixFeedAd.isExpress()) {
SAExpressFeedAd feedAd = mixFeedAd.getExpressFeedAd();
feedAd.setInteractionListener(new SAExpressFeedAd.InteractionListener() {
@Override
public void sa_feedAdRenderSuccess() {
// 渲染成功
}
@Override
public void sa_feedAdRenderFailure(AdError error) {
// 渲染失败
}
@Override
public void sa_feedAdShowFail(AdError error) {
// 展示失败
}
@Override
public void sa_feedAdDidShow() {
// 展示
}
@Override
public void sa_feedAdDidClick() {
// 点击
}
@Override
public void sa_feedAdDidExposure() {
// 曝光
}
@Override
public void sa_feedAdDidClose() {
// 点击关闭
}
});
feedAd.render();
} else {
//自渲染
}
}
private static class FeedListAdapter extends BaseAdapter {
private Context mContext;
private List<SAFeedAd> mFeedList;
FeedListAdapter(Context context, List<SAFeedAd> feedList) {
this.mContext = context;
this.mFeedList = feedList;
}
@Override
public int getCount() {
return mFeedList.size();
}
@Override
public SAFeedAd getItem(int position) {
return mFeedList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public int getItemViewType(int position) {
SAFeedAd feedAd = getItem(position);
if (feedAd != null) {
if (feedAd.isExpress()) {
return ItemViewType.ITEM_VIEW_TYPE_AD;
} else {
switch (feedAd.getNativeAdData().getFeedAdMode()) {
case GroupImage:
return ItemViewType.ITEM_VIEW_TYPE_AD_NATIVE_GROUP;
case Video:
return ItemViewType.ITEM_VIEW_TYPE_AD_NATIVE_VIDEO;
default:
return ItemViewType.ITEM_VIEW_TYPE_AD_NATIVE_IMAGE;
}
}
} else {
return ItemViewType.ITEM_VIEW_TYPE_NORMAL;
}
}
@Override
public int getViewTypeCount() {
return 5;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
SAFeedAd feedAd = getItem(position);
switch (getItemViewType(position)) {
case ItemViewType.ITEM_VIEW_TYPE_AD:
return getExpressAdItemView(convertView, parent, feedAd.getExpressFeedAd());
case ItemViewType.ITEM_VIEW_TYPE_AD_NATIVE_IMAGE:
return getImageItemView(convertView, parent, feedAd.getNativeAdData());
case ItemViewType.ITEM_VIEW_TYPE_AD_NATIVE_VIDEO:
return getVideoItemView(convertView, parent, feedAd.getNativeAdData());
case ItemViewType.ITEM_VIEW_TYPE_AD_NATIVE_GROUP:
return getGroupItemView(convertView, parent, feedAd.getNativeAdData());
default:
return getNormalItemView(convertView, parent, position);
}
}
private View getExpressAdItemView(View convertView, ViewGroup parent, final SAExpressFeedAd feedAd) {
ExpressFeedAdViewHolder adViewHolder;
if (convertView == null) {
convertView = LayoutInflater.from(mContext).inflate(R.layout.feed_list_item_ad_container,
parent, false);
adViewHolder = new ExpressFeedAdViewHolder(convertView);
convertView.setTag(adViewHolder);
} else {
adViewHolder = (ExpressFeedAdViewHolder) convertView.getTag();
}
View adView = feedAd.getAdView();
if (adView != null && adView.getParent() == null) {
adViewHolder.mAdContainer.removeAllViews();
adViewHolder.mAdContainer.addView(adView);
}
return convertView;
}
private View getImageItemView(View convertView, ViewGroup parent, final SANativeAdData feedAd) {
NativeFeedAdImageViewHolder adViewHolder;
if (convertView == null) {
convertView = LayoutInflater.from(mContext).inflate(R.layout.self_feed_list_item_ad_container_01, parent, false);
adViewHolder = new NativeFeedAdImageViewHolder(convertView);
convertView.setTag(adViewHolder);
} else {
adViewHolder = (NativeFeedAdImageViewHolder) convertView.getTag();
}
List<View> clicks = new ArrayList<>();
List<ImageView> imageViews=new ArrayList<>();
FrameLayout container = adViewHolder.mAdContainer;
ImageView logo = adViewHolder.iv_logo;
ImageView bigImage = adViewHolder.imageView;
clicks.add(bigImage);
clicks.add(adViewHolder.tvTitle);
clicks.add(adViewHolder.tvDes);
clicks.add(logo);
imageViews.add(bigImage);
feedAd.bindAdToView(container, null, logo, clicks, null, null, null, imageViews, new SAUnifiedFeedAdInteractionListener() {
@Override
public void onAdShow() {
// 展示
}
@Override
public void onAdClick() {
// 点击
}
@Override
public void onAdError(int errorCode, String msg) {
// 展示失败
}
});
if ("".equals(feedAd.getDescription())) adViewHolder.tvDes.setVisibility(View.GONE);
else adViewHolder.tvDes.setVisibility(View.VISIBLE);
adViewHolder.tvTitle.setText(feedAd.getTitle());
adViewHolder.tvDes.setText(feedAd.getDescription());
return convertView;
}
private View getGroupItemView(View convertView, ViewGroup parent, final SANativeAdData feedAd) {
NativeFeedAdGroupImageViewHolder adViewHolder;
if (convertView == null) {
convertView = LayoutInflater.from(mContext).inflate(R.layout.self_feed_list_item_ad_container_03, parent, false);
adViewHolder = new NativeFeedAdGroupImageViewHolder(convertView);
convertView.setTag(adViewHolder);
} else {
adViewHolder = (NativeFeedAdGroupImageViewHolder) convertView.getTag();
}
adViewHolder.tvTitle.setText(feedAd.getTitle());
adViewHolder.tvDes.setText(feedAd.getDescription());
List<View> clicks = new ArrayList<>();
List<ImageView> imageViews=new ArrayList<>();
clicks.add(convertView);
imageViews.add(adViewHolder.iv_1);
imageViews.add(adViewHolder.iv_2);
imageViews.add(adViewHolder.iv_3);
clicks.addAll(imageViews);
clicks.add(adViewHolder.iv_logo);
clicks.add(adViewHolder.tvTitle);
clicks.add(adViewHolder.tvDes);
feedAd.bindAdToView(adViewHolder.mAdContainer, null, adViewHolder.iv_logo, clicks, null, null, null, imageViews, new SAUnifiedFeedAdInteractionListener() {
@Override
public void onAdShow() {
// 展示
}
@Override
public void onAdClick() {
// 点击
}
@Override
public void onAdError(int errorCode, String msg) {
// 展示失败
}
});
return convertView;
}
private View getVideoItemView(View convertView, ViewGroup parent, final SANativeAdData feedAd) {
NativeFeedAdVideoViewHolder adViewHolder;
if (convertView == null) {
convertView = LayoutInflater.from(mContext).inflate(R.layout.self_feed_list_item_ad_container_02, parent, false);
adViewHolder = new NativeFeedAdVideoViewHolder(convertView);
convertView.setTag(adViewHolder);
} else {
adViewHolder = (NativeFeedAdVideoViewHolder) convertView.getTag();
}
List<View> clicks = new ArrayList<>();
List<ImageView> imageViews=new ArrayList<>();
FrameLayout container = adViewHolder.mAdContainer;
ImageView logo = adViewHolder.iv_logo;
FrameLayout mediaContainer = adViewHolder.mediaContainer;
clicks.add(container);
clicks.add(mediaContainer);
clicks.add(logo);
feedAd.bindAdToView(container, null, logo, clicks, null, null, mediaContainer, imageViews, new SAUnifiedFeedAdInteractionListener() {
@Override
public void onAdShow() {
// 展示
}
@Override
public void onAdClick() {
// 点击/
}
@Override
public void onAdError(int errorCode, String msg) {
// 展示失败
}
});
adViewHolder.tvTitle.setText(feedAd.getTitle());
adViewHolder.tvDes.setText(feedAd.getDescription());
return convertView;
}
@SuppressLint("DefaultLocale")
private View getNormalItemView(View convertView, ViewGroup parent, int position) {
FeedListAdapter.NormalViewHolder normalViewHolder;
if (convertView == null) {
normalViewHolder = new FeedListAdapter.NormalViewHolder();
convertView =
LayoutInflater.from(mContext).inflate(R.layout.native_item_normal, parent, false);
normalViewHolder.textView = convertView.findViewById(R.id.tv);
convertView.setTag(normalViewHolder);
} else {
normalViewHolder = (FeedListAdapter.NormalViewHolder) convertView.getTag();
}
normalViewHolder.textView.setText(String.format("ListView item %d", position));
return convertView;
}
@interface ItemViewType {
int ITEM_VIEW_TYPE_NORMAL = 0;
int ITEM_VIEW_TYPE_AD = 1;
int ITEM_VIEW_TYPE_AD_NATIVE_IMAGE = 2;
int ITEM_VIEW_TYPE_AD_NATIVE_VIDEO = 3;
int ITEM_VIEW_TYPE_AD_NATIVE_GROUP = 4;
}
private static class NormalViewHolder {
TextView textView;
}
}
}
六、广告预缓存
为提升广告加载效率,可在优推聚合管理平台,开启广告位预缓存功能
如果要开启预缓存功能,需要在SDK初始化之后在项目中做如下配置
SAPreCacheConfig config = new SAPreCacheConfig.Builder()
.setPreCacheActivity(this)
.setRewardMuted(true)
.setInterstitialMuted(true)
.setFeedMuted(true)
.setFeedAdSize(new SAAdSize(width, 0),posid)//支持广告类型广告位尺寸传入
.build();
SAAllianceAdSdk.setPreCacheConfig(config);
七、SDK错误码&错误信息说明
第三方广告平台常见错误码
穿山甲
错误码 | 说明 |
---|---|
20001 | 没有合适的广告返回而导致的请求没有填充,偶现属于正常情况,请尝试更换设备进行验证,不要使用模拟器进行测试,或稍后再试。如都不能解决,请查看穿山甲-SDK错误码进行排查或者向穿山甲平台提单进行询问 |
40006 | 广告位ID不合法,检查优推后台广告源配置 |
40016 | 代码位ID与应用ID不匹配或者应用ID缺失,检查优推后台广告源配置 |
40018 | 代码中配置的包名和穿山甲后台一致 |
40019 | 广告请求方法与代码位类型不匹配 |
40029 | 检查穿山甲代码位的渲染类型,优推后台穿山甲广告源的配置需与穿山甲后台的配置保持一致 |
更多的穿山甲错误码信息请查看(需登录):Pangle错误码
优量汇
错误码 | 说明 |
---|---|
4001 | 初始化错误, 包括广告位为空、App ID为空、Context/Activity为空,检查优推后台广告源配置 |
4003 | 广告位错误,检查优推后台广告源配置 |
5002 | 视频素材下载错误,如网络环境不佳导致视频类广告无法下载 |
5004 | 没有匹配到合适的广告资源,属于调试中或者线上广告的正常现象 |
5010 | 广告位与调用接口不匹配,导致广告样式校验失败,,检查优推后台广告源配置与优量汇一致 |
更多的流量汇错误码信息请查看:GDT错误码
百度
错误码 | 说明 |
---|---|
200000或0 | 无广告返回 |
加载Banner广告时一直没有回调 | ATBannerView需要先add到window上再发起load请求 |
更多的百度错误码信息请查看(需登录):百度错误码
快手
错误码 | 说明 |
---|---|
40001 | 没有网络 |
40002 | 数据解析失败 |
40003 | 广告数据为空 |
310001 | appId未注册 |
310002 | appId⽆效 |
310004 | packageName与注册的packageName不⼀致 |
330001 | posId未注册 |
330002 | posId⽆效 |
330004 | posid与注册的appId信息不⼀致 |
更多的快手错误码信息请查看(需登录):快手错误码
Mintegral
错误码 | 说明 |
---|---|
EXCEPTION_RETURN_EMPTY | 确保Mintegral后台-应用设置中开启了是否接受apk广告投放 |
EXCEPTION_SIGN_ERROR | 检查优推后台Mintegral代码位配置(AppKey) |
EXCEPTION_TIMEOUT | 请求超时 |
EXCEPTION_UNIT_NOT_FOUND | 该unitID不存在/填写错误,检查优推后台Mintegral代码位配置(广告单元id) |
EXCEPTION_UNIT_NOT_FOUND_IN_APP | 在该appID和unitID不匹配,检查优推后台Mintegral代码位配置(广告单元id) |
EXCEPTION_UNIT_ADTYPE_ERROR | 传入的unitID广告类型不符,检查优推后台Mintegral代码位配置(广告形式不匹配) |
errorCode: 3507 errorMessage: data load failed, errorMsg is Network error,I/O exception | 检查是否连了代理,并且开启了SSL Proxying,去掉后重试 |
Network error,I/O exception | 检查是否连接了代理,并且开启了SSL Proxying,去掉后重试 |
更多的Mintegral的错误信息请查看:Mintegral错误码
SigMob
错误码 | 说明 |
---|---|
200000 | 无广告填充,通过Sigmob后台添加测试设备进行测试 |
500420 | App被关闭,请前往Sigmob平台检查app状态 |
500473 | 请求的Appid不存在,请检查请求参数,检查优推后台广告源配置 |
500422 | 请求由于缺少设备标识符(IMEI/OAID/IDFA)被过滤 |
更多的Sigmob的错误信息请查看:Sigmob错误码
Oneway
错误码 | 说明 |
---|---|
CAMPAIGN_NO_FILL | 请求广告失败,无广告内容 |