跳至主要內容

优推聚合 Android SDK 接入文档

大约 20 分钟

优推聚合 Android SDK 接入文档

一、SDK版本更新记录

SDK版本
修改日期
修改说明
2.2.92023-09-151.更新三方SDK:优推adn v3.0.10
2.修复已知问题
2.2.72023-09-071.增加兜底广告源功能
2.支持SDK本地化预置策略功能
3.支持Gromore本地缓存配置
4.预缓存广告逻辑优化
5.更新三方SDK:优推ADXv3.0.9
2.1.192023-08-25修复已知问题
2.1.182023-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.152023-08-12修复已知问题
2.1.132023-08-031.增加bidding与瀑布流并行功能
2. 增加缓存池底价和竞价底价功能
3.更新三方SDK:优推ADXv3.0.3
4.修复已知问题
2.1.62023-07-211.优化sdk初始化速度
2.兼容优量汇半屏开屏广告
3.修复已知问题
2.0.52023-07-061.优化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下载open in new window

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错误码open in new window

优量汇

错误码说明
4001初始化错误, 包括广告位为空、App ID为空、Context/Activity为空,检查优推后台广告源配置
4003广告位错误,检查优推后台广告源配置
5002视频素材下载错误,如网络环境不佳导致视频类广告无法下载
5004没有匹配到合适的广告资源,属于调试中或者线上广告的正常现象
5010广告位与调用接口不匹配,导致广告样式校验失败,,检查优推后台广告源配置与优量汇一致

更多的流量汇错误码信息请查看:GDT错误码open in new window

百度

错误码说明
200000或0无广告返回
加载Banner广告时一直没有回调ATBannerView需要先add到window上再发起load请求

更多的百度错误码信息请查看(需登录):百度错误码open in new window

快手

错误码说明
40001没有网络
40002数据解析失败
40003广告数据为空
310001appId未注册
310002appId⽆效
310004packageName与注册的packageName不⼀致
330001posId未注册
330002posId⽆效
330004posid与注册的appId信息不⼀致

更多的快手错误码信息请查看(需登录):快手错误码open in new window

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错误码open in new window

SigMob

错误码说明
200000无广告填充,通过Sigmob后台添加测试设备进行测试
500420App被关闭,请前往Sigmob平台检查app状态
500473请求的Appid不存在,请检查请求参数,检查优推后台广告源配置
500422请求由于缺少设备标识符(IMEI/OAID/IDFA)被过滤

更多的Sigmob的错误信息请查看:Sigmob错误码open in new window

Oneway

错误码说明
CAMPAIGN_NO_FILL请求广告失败,无广告内容
上次编辑于: