章鱼聚合 SDK-Android 接入文档
注意:
- 本 SDK 最低兼容
Android API 16(Android 4.1 ICS)
- 确保 support v4、v7 包版本不小于
24.0.0
- 集成前请和章鱼聚合 SDK 人员确认所有使用的依赖库版本号
- 媒体接入信通院 oaid_sdk 的时候需要将压缩包内 Octopus\assets\下的 supplierconfig.json 文件复制到项目 app 工程 assets 目录里,路径:工程\app\src\main\assets\
一、导入 SDK 依赖
1.1、压缩包目录结构
-
文件目录 目录说明 Octopus/assets/supplierconfig.json 接入信通院 oaid_sdk 的时候需要用到的 json 文件. Octopus/libs/***.aar 项目中依赖的 aar 文件. OctopusDemo 示例工程, 用来方便媒体参考接入. app-release.apk 示例 APP, 用来演示章鱼聚合广告提供的多种广告展现形式. whiteList.txt 渠道白名单,媒体如果设置了资源混淆,需要添加这个配置. 章鱼聚合 SDK-Android 接入文档.html 章鱼聚合 SDK-Android 接入文档.
1.2、导入 SDK 文件
1.2.1、在 app 目录下新建 libs 文件夹.
1.2.2、将 Octopus/libs 目录下的文件拷贝到 libs 文件夹下.
1.2.3、在 app/build.gradle 添加如下代码:
-
android {
compileSdkVersion 28
// 如果集成京东SDK,则可能会遇到如下报错:
// Default interface methods are only supported starting with Android N (--min-api 24): void
// com.jd.ad.sdk.bl.dynamicrender.DynamicRenderView$IDynamicRenderCallback.onAnimationEnd()
// 添加以下代码可解决
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
// 设置gradle编译选项,开发者可以根据自己对平台的选择进行合理配置,为了保证兼容性,默认支持以下五种架构
ndk {
abiFilters 'armeabi-v7a','x86','arm64-v8a','x86_64','armeabi'
}
}
repositories {
flatDir {
dirs 'libs'
}
}
dependencies {
// 怎么判断你的项目是support版本还是Androidx版本
// 如果你的项目添加的是support依赖,则你的项目是support版本,例如:
implementation "com.android.support:appcompat-v7:28.0.0"
implementation "com.android.support:support-v4:28.0.0"
implementation "com.android.support:recyclerview-v7:28.0.0"
// 如果你的项目添加的是Androidx依赖,则你的项目是androidx版本,例如:
implementation 'androidx.appcompat:appcompat:1.0.0'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.recyclerview:recyclerview:1.2.1'
// 集成章鱼聚合SDK需导入的aar(必选)
implementation(name: 'octopus_group_sdk_3.2.13.6', ext: 'aar')
// 开发者可根据APP需要导入以下广告aar文件
// 1、集成章鱼广告需导入的aar
implementation(name: 'octopus_ad_sdk_1.5.9.11', ext: 'aar')
// 2、集成京东广告需导入的aar(注意:区分support和androidx)
//***如果你的项目是support版本,则导入以下aar
implementation(name: 'jad_yun_sdk_v2.0.2', ext: 'aar')
//***如果你的项目是androidx版本,则导入以下aar
implementation(name: 'jad_yun_sdk_v2.1.2', ext: 'aar')
// 3、集成趣萌广告需导入的aar(注意:区分support和androidx)
//***如果你的项目是support版本,则导入以下aar
implementation(name: 'qumeng-3.461.11.427', ext: 'aar')
//***如果你的项目是androidx版本,则导入以下aar
implementation(name: 'qumeng-3.461.11.427x', ext: 'aar')
// 4、集成广点通广告需导入的aar
implementation(name: 'GDTSDK.unionNormal.4.540.1410', ext: 'aar')
// 5、集成穿山甲广告需导入的aar
implementation(name: 'open_ad_sdk_5.7.0.6', ext: 'aar')
// 6、集成快手广告需导入的aar
implementation(name: 'kssdk-ad-3.3.51.1-publishRelease-97f3383ba2', ext: 'aar')
// 7、集成百度广告需导入的aar
implementation(name: 'Baidu_MobAds_SDK-release_v9.313', ext: 'aar')
// 8、集成Oneway广告需导入的aar
implementation(name: 'Oneway-2.5.4-release', ext: 'aar')
// 9、集成Sigmob广告需导入的aar
implementation(name: 'wind-common-1.4.9', ext: 'aar')
implementation(name: 'wind-sdk-4.12.6', ext: 'aar')
// 集成信通院oaid_sdk需导入的aar
implementation(name: 'oaid_sdk_1.0.25', ext: 'aar')
}
1.3、AndroidManifest 配置
1.3.1、添加访问权限
在 AndroidManifest.xml 文件中添加,建议在您的隐私协议中向开发者声明章鱼聚合 SDK 会获取下述权限并应用于广告投放
-
<!--必要权限-->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!--可选权限-->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<!-- 如果有视频相关的广告且使用textureView播放,请务必添加,否则黑屏 -->
<uses-permission android:name="android.permission.WAKE_LOCK" />
<!--获取应用安装列表的权限属于个人信息,由渠道引入,媒体可以通过以下配置,主动移除这个权限-->
<uses-permission
android:name="android.permission.QUERY_ALL_PACKAGES"
tools:node="remove" />
<!--获取手机状态的权限可能涉及到获取个人信息,由渠道引入,媒体可以通过以下配置,主动移除这个权限-->
<uses-permission
android:name="android.permission.READ_PHONE_STATE"
tools:node="remove" />
<!--必要权限,解决安全风险漏洞,发送和注册广播事件需要调用带有传递权限的接口-->
<permission
android:name="${applicationId}.openadsdk.permission.TT_PANGOLIN"
android:protectionLevel="signature" />
<uses-permission android:name="${applicationId}.openadsdk.permission.TT_PANGOLIN" />
注意:章鱼聚合 SDK 不强制获取可选权限,即使没有获取可选权限 SDK 也能正常运行;获取可选权限将帮助 Octopus 优化投放广告精准 度和用户的交互体验,提高 eCPM。
1.3.2、overrideLibrary 设置
由于引入的 sdk 支持的最小版本与 app 支持的最小版本可能不一致,需要在 AndroidManifest 文件中添加 overrideLibrary 配置:
-
<uses-sdk tools:overrideLibrary="com.octopus.ad,com.octopus.group,com.bun.miitmdid,
com.kwad.sdk,com.bytedance.sdk.openadsdk,com.jd.ad.sdk" />
注意:请开发者务必按照上面信息进行注册声明,详情见 Demo。
1.3.3、provider 配置
-
<!--targetSDKVersion >= 24时才需要添加这些个provider。请开发者根据自己的包名来替换${applicationId}这个值-->
<!--GDT Sdk安装广告下载的APP需要用到这个-->
<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>
<!--CSJ Sdk安装广告下载的APP需要用到这个-->
<provider
android:name="com.bytedance.sdk.openadsdk.TTFileProvider"
android:authorities="${applicationId}.TTFileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
1.3.4、配置网络权限
在 targetSdkVersion 28 及以上的手机上允许 HTTP(S)网络请求,在“AndroidManifest.xml”做以下配置。
-
<application
...
android:usesCleartextTraffic="true"
>
...
</application>
1.3.5、开启硬件加速
视频广告的 MediaView 内部使用了 TextureView,需要在开启硬件加速的窗口中才能使用。 所以需要在 AndroidManifest.xml 添加如下声明:
-
方式一:
<application
android:hardwareAccelerated="true"
... ...
</application>
方式二:
<activity
android:hardwareAccelerated="true"
... ...
</activity>
1.4、混淆配置
为了保证 Octopus SDK 正常工作, 请务必按照以下 ProGuard 配置打包.
-
-ignorewarnings
-dontoptimize
-dontpreverify
-keepattributes Signature
-keepattributes *Annotation*
-dontwarn android.app.**
-dontwarn android.support.**
-dontwarn sun.misc.**
-dontwarn org.apache.**
-keep class **.R$* {*;}
-keep class sun.misc.**{*;}
-keep class android.support.** { *; }
-keep class android.app.**{*;}
-keepclassmembers class * extends android.app.Activity {
public void *(android.view.View);
}
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
# androidx 混淆
-keep class com.google.android.material.** {*;}
-keep class androidx.** {*;}
-keep public class * extends androidx.**
-keep interface androidx.** {*;}
-dontwarn com.google.android.material.**
-dontnote com.google.android.material.**
-dontwarn androidx.**
# 移动安全联盟oaid混淆
-keep class XI.CA.XI.**{*;}
-keep class XI.K0.XI.**{*;}
-keep class XI.XI.K0.**{*;}
-keep class XI.xo.XI.XI.**{*;}
-keep class com.asus.msa.SupplementaryDID.**{*;}
-keep class com.asus.msa.sdid.**{*;}
-keep class com.bun.lib.**{*;}
-keep class com.bun.miitmdid.**{*;}
-keep class com.huawei.hms.ads.identifier.**{*;}
-keep class com.samsung.android.deviceidservice.**{*;}
-keep class com.zui.opendeviceidlibrary.**{*;}
-keep class org.json.**{*;}
-keep public class com.netease.nis.sdkwrapper.Utils {public <methods>;}
# Octopus混淆
-dontwarn com.octopus.group.**
-dontwarn com.octopus.ad.**
-keep class com.octopus.group.** {*; }
-keep class com.octopus.ad.** {*; }
# 聚合混淆
# 如果接入了京东广告,需要添加如下配置
-keep class com.jd.ad.sdk.** { *; }
# 如果接入了广点通广告,需要添加如下配置
-keep class com.qq.e.** {
public protected *;
}
# 如果接入了穿山甲广告,需要添加如下配置
-keep class com.bytedance.sdk.openadsdk.** {*;}
-keep public interface com.bytedance.sdk.openadsdk.downloadnew.** {*;}
-keep class com.pgl.sys.ces.* {*;}
# 如果接入了快手联盟,需要添加如下配置
-keep class com.kwad.sdk.** { *;}
-keep class com.ksad.download.** { *;}
-keep class com.kwai.filedownloader.** { *;}
# 如果接入了百度广告,需要添加如下配置
-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.** {*;}
# 如果接入了Sigmob广告,需要添加如下配置
-keep class sun.misc.Unsafe.**{ *; }
-keep class com.sigmob.**{*;}
-keep interface com.sigmob.**{*;}
-keep class com.czhj.**{*;}
-keep interface com.czhj.**{*;}
# 优化
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
# 保护内部类
-keepattributes Exceptions,InnerClasses,Signature,Deprecated,SourceFile,LineNumberTable,*Annotation*,EnclosingMethod
二、SDK 初始化
2.1、初始化 SDK
注意:①、初始化 SDK 必须在调用广告接口之前。appId 由运营人员提供
②、建议在 application 里面调用;假如 App 有功能引导,也可点击"立即体验"按钮中调用
③、在主线程中调用 sdk 的初始化(init)方法
2.1.1、如需不需要自定义隐私开关控制,请调用如下方法
-
OctopusGroup.init(applicationContext, appId);
2.1.2、如需自定义隐私开关控制,请调用如下方法
-
OctopusGroup.init(applicationContext, appId, new OctopusCustomController());
2.1.3、如需传入自己获取的 oaid,请调用如下初始化方法
-
OctopusGroup.init(applicationContext, appId, new OctopusCustomController(), "DEVICE_OAID");
2.2、隐私信息控制开关
-
public abstract class OctopusCustomController {
/**
* 是否允许SDK主动使用地理位置信息
*
* @return true可以获取,false禁止获取。默认为true
*/
public boolean isCanUseLocation() {
return true;
}
/**
* 是否允许SDK主动使用ACCESS_WIFI_STATE权限
*
* @return true可以使用,false禁止使用。默认为true
*/
public boolean isCanUseWifiState() {
return true;
}
/**
* 是否允许SDK主动使用手机硬件参数,如:imei,imsi
*
* @return true可以使用,false禁止使用。默认为true
*/
public boolean isCanUsePhoneState() {
return true;
}
/**
* 是否能使用Oaid
* @return true可以使用,false禁止使用。默认为true
*/
public boolean isCanUseOaid() {
return true;
}
/**
* 是否能使用Gaid
*
* @return true可以使用,false禁止使用。默认为true
*/
public boolean isCanUseGaid() {
return true;
}
}
2.3、其它特殊设置
2.3.1、如果正在使用的 oaid_sdk 版本不是 1.0.25,需要传入正在使用的 oaid_sdk 版本号
-
OctopusGroup.setOaidVersion("x.x.x"); // 传入自己的oaid_sdk版本号
2.3.2、如果需要点击广告后不直接下载,而是弹出二次确认弹框
-
// 设置是否直接下载: true:直接下载,false:二次弹窗确认,默认为true
OctopusGroup.setDownloadDirect(false);
2.3.3、如果需要关闭个性化广告推荐 (请在用户点击关闭个性化广告推荐时才调用此方法,否则影响广告收益):
-
// 设置是否允许个性化广告推荐,不允许后将获取不到广告: true:允许,false:不允许,默认为true
OctopusGroup.setSupportPersonalized(false);
三、开屏广告
3.1、添加广告容器
在需要添加开屏广告的 Activity 对应的布局文件添加一个 ViewGroup 来填充广告,例如:
-
<FrameLayout
android:id="@+id/fl_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@id/rl_bottom" />
3.2、开屏广告接口说明
-
/**
* 开屏广告构造函数
* @param context 必须传入Activity的上下文
* @param adTypeId 聚合SDK的广告位id,由运营人员提供
* @param adListener 开屏广告监听器
* @param usableTime 超时时间
*/
public SplashAd(Context context, String adTypeId, AdListener adListener, long usableTime)
/**
* @param widthDp 广告宽度dp值
* @param heightDp 广告高度dp值
* /
public void loadAd(int widthDp,int heightDp)
/**
* 当媒体选择不展示此次广告时,请调用此方法,方便后续数据分析
*/
public void reportNotShow()
/**
* 展示广告
* @param parent 广告容器
*/
public void show(ViewGroup parent){}
3.3、开屏广告回调说明
-
/**
* 开屏广告监听器
*/
AdListener {
/**
* 广告加载成功
*/
@Override
public void onAdLoaded()
/**
* 广告展示
*/
@Override
public void onAdShown()
/**
* 加载失败
* @param errorCode 错误码
*/
@Override
public void onAdFailedToLoad(int errorCode)
/**
* 广告关闭
*/
@Override
public void onAdClosed()
/**
* 倒计时回调,返回广告还将被展示的剩余时间。
* 通过这个接口,开发者可以自行决定是否显示倒计时提示,或者还剩几秒的时候显示倒计时
*/
@Override
public void onAdTick(long millisUnitFinished)
/**
* 广告点击
*/
@Override
public void onAdClicked()
}
3.4、开屏广告示例
-
注意: 在主线程中调用广告对象的创建(new Ad())和加载(load)方法
-
创建开屏广告实例:
// 广告容器
mAdContainer = this.findViewById(R.id.fl_container);
// 开屏广告请求超时时长
int totalTime = 5000;
mSplashAd = new SplashAd(this, "7046", new AdListener() {
@Override
public void onAdLoaded() {
Log.i("OctopusGroupDemo", "onAdLoaded");
if (mSplashAd != null) {
Log.i("OctopusGroupDemo", "ad ecpm = " + mSplashAd.getECPM());
mSplashAd.show(mAdContainer);
}
}
@Override
public void onAdShown() {
Log.i("OctopusGroupDemo", "onAdShown");
}
@Override
public void onAdFailedToLoad(int errorCode) {
Log.i("OctopusGroupDemo", "onAdFailedToLoad:" + errorCode);
jump();
}
@Override
public void onAdClosed() {
Log.i("OctopusGroupDemo", "onAdClosed");
jumpWhenAdPageFinish();
}
@Override
public void onAdTick(long millisUnitFinished) {
Log.i("OctopusGroupDemo", "onAdTick millisUnitFinished == " + millisUnitFinished);
}
@Override
public void onAdClicked() {
Log.i("OctopusGroupDemo", "onAdClicked");
}
}, totalTime); // 广告请求超时时长,建议5秒以上,该参数单位为ms
mSplashAd.loadAd(360,640); // 第一个参数是宽度,第二个参数是高度 单位是dp
-
开屏页一定要禁止用户对返回按钮的控制,否则将可能导致用户手动退出了 App 而广告无法正常曝光和计费:
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_HOME) {
return true;
}
return super.onKeyDown(keyCode, event);
} -
开屏页的 onDestroy 方法中请调用:
@Override
protected void onDestroy() {
if (mSplashAd != null){
mSplashAd.destroy();
}
super.onDestroy();
} -
解决点击广告后页面跳转问题(点击后应该先跳转到广告落地页,从落地页返回再进入应用主页),请参考 demo 中如下写法
// 如果用户点击广告,需要等待广告页面关闭后再跳转主页面。
public boolean mCanJumpImmediately = false;
// 立即跳转主页面
private void jump() {
startActivity(new Intent(SplashActivity.this, MainActivity.class));
finish();
}
// 如果用户点击广告,需要等待广告页面关闭后再跳转主页面。
private void jumpWhenAdPageFinish() {
if (mCanJumpImmediately) {
jump();
} else {
mCanJumpImmediately = true;
}
}
@Override
protected void onResume() {
super.onResume();
if (mCanJumpImmediately) {
jumpWhenAdPageFinish();
}
mCanJumpImmediately = true;
}
@Override
protected void onPause() {
super.onPause();
mCanJumpImmediately = false;
}
3.5、开屏广告的验证
3.5.1、开屏广告显示,用户点击跳过按钮,可正常跳过(跳转到目标界面)
3.5.2、开屏广告显示,用户正常观看广告若干秒(比如 5 秒),跳过按钮自动消失,可正常跳转(跳转到目标界面)
3.5.3、开屏广告显示,用户点击广告显示广告落地页,关闭广告落地页后跳转到目标界面
- PS:完整流程请参考 Demo 中的 com.octopus.demo.SplashActivity 的示例代码。
四、原生(信息流)广告
4.1、原生广告接口说明
-
/**
* 原生广告构造方法
* @param context 必须传入Activity的上下文
* @param adTypeId 聚合SDK的广告位id,由运营人员提供
* @param adListener 原生广告监听
* @param usableTime 广告请求超时时长,单位毫秒,建议5秒(5000)以上
*/
public NativeAd(Context context, String adTypeId, NativeAdListener adListener, long asableTime)
/**
* 广告加载,只加载一条广告
* @param adWidthDp 广告view的宽度,单位为dp, 特别说明:假如广告有左右间距,故广告view的宽度 = 屏幕宽度 - 左右间距总和
* @param adHeightDp 广告view的高度,单位为dp,特别说明:0表示高度自适应
*/
public void loadAd(float adWidthDp, float adHeightDp)
/**
* 恢复广告状态
*/
public void resume()
/**
* 资源释放
*/
public void destroy()
4.2、原生广告回调说明
-
/**
* 原生广告监听器
*/
NativeAdListener {
/**
* 广告加载失败
* @param code
*/
void onAdFailed(int code);
/**
* 广告加载成功
* @param view 广告view
*/
void onAdLoaded(View view);
/**
* 广告展示
*/
void onAdShown();
/**
* 广告关闭
*/
void onAdClosed();
/**
* 广告点击
*/
void onAdClick();
}
4.3、原生广告示例
-
注意: 在主线程中调用广告对象的创建(new Ad())和加载(load)方法
-
创建原生广告实例:
private NativeAd mNativeAd;
//广告容器
private FrameLayout mAdContainer;
//特别说明:context 必须传入 Activity
mNativeAd = new NativeAd(NativeAdActivity.this, "7045", new NativeAdListener() {
@Override
public void onAdFailed(int code) {
Log.i("OctopusGroupDemo",TAG + " Native ad onAdFailed " + code);
}
@Override
public void onAdLoaded(View view) {
Log.i("OctopusGroupDemo",TAG + " Native ad onAdLoaded");
Log.i("OctopusGroupDemo", "ad ecpm = " + mNativeAd.getECPM());
if (mAdContainer.getChildCount() > 0) {
mAdContainer.removeAllViews();
}
// 广告可见才会产生曝光,否则将无法产生收益。
mAdContainer.addView(view);
}
@Override
public void onAdShown() {
Log.i("OctopusGroupDemo",TAG + " Native ad onAdShown");
}
@Override
public void onAdClosed() {
Log.i("OctopusGroupDemo",TAG + " Native ad onAdClosed");
//移除广告
if (mAdContainer != null && mAdContainer.getChildCount() > 0) {
mAdContainer.removeAllViews();
}
}
@Override
public void onAdClick() {
Log.i("OctopusGroupDemo",TAG + " Native ad onAdClick");
}
}, 5000);//第四个参数是:广告请求超时时长,建议设置为5000毫秒;
/*
* 加载广告
* 广告view的宽度,单位为dp, 特别说明:假如广告有左右间距,故广告view的宽度 = 屏幕宽度 - 左右间距总和
* 广告view的高度,单位为dp,特别说明:0表示高度自适应
*/
mNativeAd.loadAd(UiUtil.getScreenWidthDp(this), 0); -
在页面的 onResume 和 onDestroy 方法中请调用:
@Override
protected void onResume() {
super.onResume();
// 必须要在Activity.onResume()时通知到广告数据,以便重置广告恢复状态
if (mNativeAd != null) {
mNativeAd.resume();
}
}
@Override
protected void onDestroy() {
if (mNativeAd != null){
mNativeAd.destroy();
}
super.onDestroy();
}
- PS:完整流程请参考 Demo 中的 com.octopus.demo.NativeAdActivity 的示例代码。
五、插屏广告
5.1、插屏广告接口说明
-
/**
* 插屏广告构造函数
* @param context Activity的上下文
* @param adTypeId 聚合SDK的广告位id,由运营人员提供
* @param adListener 插屏广告监听
* @param usableTime 广告超时时长,单位毫秒,建议5秒(5000)以上
*/
public InterstitialAd(Context context, String adTypeId, InterstitialAdListener adListener, long usableTime)
/**
* 广告加载
*/
public void loadAd()
/**
* 广告是否加载成功
* @return true表示加载成功;false则失败
*/
public boolean isLoaded()
/**
* 广告展示
* @param activity
*/
public void showAd(@NonNull Activity activity)
/**
* 资源释放
*/
public void destroy()
5.2、插屏广告回调说明
-
/**
* 插屏广告监听器
*/
InterstitialAdListener {
/**
* 广告加载失败
* @param code
*/
void onAdFailed(int code);
/**
* 广告加载成功
*/
void onAdLoaded();
/**
* 广告展示
*/
void onAdShown();
/**
* 广告关闭
*/
void onAdClosed();
/**
* 广告点击
*/
void onAdClick();
}
5.3、插屏广告示例
-
注意: 在主线程中调用广告对象的创建(new Ad())和加载(load)方法
-
创建插屏广告实例:
/**
* context 必须传入 Activity类型
*/
mInterstitialAd = new InterstitialAd(this, "7047", new InterstitialAdListener() {
@Override
public void onAdFailed(int code) {
Log.i("OctopusGroupDemo",TAG + " onAdFailed ");
Toast.makeText(InterstitialActivity.this, R.string.load_ad_fail, Toast.LENGTH_LONG).show();
}
@Override
public void onAdLoaded() {
Log.i("OctopusGroupDemo",TAG + " onAdLoaded");
Toast.makeText(InterstitialActivity.this, R.string.load_ad_success, Toast.LENGTH_LONG).show();
//插屏广告加载成功直接显示插屏
if (mInterstitialAd != null && mInterstitialAd.isLoaded()) {
Log.i("OctopusGroupDemo", "ad ecpm = " + mInterstitialAd.getECPM());
// 广告展示需要传入Activity
mInterstitialAd.showAd(InterstitialActivity.this);
}
}
@Override
public void onAdShown() {
Log.i("OctopusGroupDemo",TAG + " onAdShown");
}
@Override
public void onAdClosed() {
Log.i("OctopusGroupDemo",TAG + " onAdClosed");
}
@Override
public void onAdClick() {
Log.i("OctopusGroupDemo",TAG + " onAdClick");
}
}, 5000);//超时时间,单位为毫秒,建议5000以上
//插屏广告加载
mInterstitialAd.loadAd(); -
在页面的 onDestroy 方法中请调用:
@Override
protected void onDestroy() {
if (mInterstitialAd != null){
mInterstitialAd.destroy();
}
super.onDestroy();
}
- PS: 完整流程请参考 Demo 中的 com.octopus.demo.InterstitialActivity 的示例代码。
六、激励视频
6.1、激励视频接口说明
-
/**
* 激励视频广告构造函数
* @param context 上下文
* @param adTypeId 聚合SDK的广告位id,由运营人员提供
* @param adListener 激励视频广告监听
* @param usableTime 广告超时时长,单位毫秒,建议10秒(10000)以上
*/
public RewardedVideoAd(Context context, String adTypeId, RewardedVideoAdListener adListener,long usableTime)
/**
* 广告加载
*/
public void loadAd()
/**
* 广告是否加载成功
* @return true表示加载成功;false则失败
*/
public boolean isLoaded()
/**
* 广告展示
* @param activity
*/
public void showAd(@NonNull Activity activity)
/**
* 资源释放
*/
public void destroy()
6.2、激励视频回调说明
-
/**
* 激励视频广告监听器
*/
RewardedVideoAdListener {
/**
* 获得奖励,在该回调中做奖励操作
*/
void onRewarded();
/**
* 广告加载失败
*/
void onRewardedVideoAdFailedToLoad(int i);
/**
* 广告加载成功
*/
void onRewardedVideoAdLoaded();
/**
* 广告展示
*/
void onRewardedVideoAdShown();
/**
* 广告关闭
*/
void onRewardedVideoAdClosed();
/**
* 广告点击
*/
void onRewardedVideoClick();
}
6.3、激励视频示例
-
注意: 在主线程中调用广告对象的创建(new Ad())和加载(load)方法
-
创建激励视频实例:
RewardedVideoAd mRewardedVideoAd = new RewardedVideoAd(this, "7048", new RewardedVideoAdListener() {
/**
* 获得奖励,在该回调中做奖励操作
*/
@Override
public void onRewarded() {
Log.i("OctopusGroupDemo","enter onRewarded");
}
/**
* 加载失败
* @param i 错误码
*/
@Override
public void onRewardedVideoAdFailedToLoad(int i) {
Log.i("OctopusGroupDemo","enter onRewardedVideoAdFailedToLoad errorCode = "+i);
}
/**
* 广告加载成功
*/
@Override
public void onRewardedVideoAdLoaded() {
Log.i("OctopusGroupDemo","enter onRewardedVideoAdLoaded");
if (mRewardedVideoAd != null && mRewardedVideoAd.isLoaded()) {
Log.i("OctopusGroupDemo", "ad ecpm = " + mRewardedVideoAd.getECPM());
mRewardedVideoAd.showAd(RewardedVideoActivity.this);
}
}
/**
* 广告展示
*/
@Override
public void onRewardedVideoAdShown() {
Log.i("OctopusGroupDemo","enter onRewardedVideoAdShown");
}
/**
* 广告关闭
*/
@Override
public void onRewardedVideoAdClosed() {
Log.i("OctopusGroupDemo","enter onRewardedVideoAdClosed");
}
/**
* 广告点击
*/
@Override
public void onRewardedVideoClick() {
Log.i("OctopusGroupDemo","enter onRewardedVideoClick");
}
},10000);//加载激励视频的超时时长,建议10秒以上,该参数单位为ms;
mRewardedVideoAd.loadAd(); -
在页面的 onDestroy 方法中请调用:
@Override
protected void onDestroy() {
if (mRewardedVideoAd != null){
mRewardedVideoAd.destroy();
}
super.onDestroy();
}
- PS:完整流程请参考 Demo 中的 com.octopus.demo.RewardedVideoActivity 的示例代码。
七、原生(信息流)自渲染广告
7.1、原生自渲染广告接口说明
-
/**
* 自定义广告构造方法
* @param context 必须传入Activity的上下文
* @param adTypeId 聚合SDK的广告位id,由运营人员提供
* @param adListener 原生广告监听
* @param usableTime 广告请求超时时长,单位毫秒,建议5秒(5000)以上
*/
public NativeUnifiedAd(Context context, String adTypeId, NativeUnifiedAdListener adListener, long usableTime)
/**
* 广告是否加载成功
* @return true表示加载成功;false则失败
*/
public boolean isLoaded()
/**
* 广告加载,只加载一条广告
*/
public void loadAd()
/**
* 恢复广告状态
*/
public void resume()
/**
* 资源释放
*/
public void destroy()
7.2、原生自渲染广告回调说明
-
/**
* 原生自渲染广告监听器
*/
NativeUnifiedAdListener {
/**
* 广告加载失败
* @param code
*/
void onAdFailed(int code);
/**
* 广告加载成功
* @param response 广告响应结果
*/
void onAdLoaded(NativeUnifiedAdResponse response);
/**
* 广告展示
*/
void onAdShown();
/**
* 广告点击
*/
void onAdClick();
}
7.3、原生自渲染广告响应说明
-
/**
* 原生自渲染广告响应数据
*/
public interface NativeUnifiedAdResponse {
/**
* 获取广告标题,短文字
*/
String getTitle();
/**
* 获取广告描述,长文字
*/
String getDescription();
/**
* 获取 Icon 图片地址
*/
String getIconUrl();
/**
* 获取广告单图图片地址
*/
String getImageUrl();
/**
* 获取图片的地址列表(多图广告)
*/
List<String> getImgList();
/**
* 获取广告Logo链接
*/
String getLogoUrl();
/**
* 获取广告文字Logo链接
*/
String getTextLogoUrl();
/**
* 获取广告LogoBitmap
*/
Bitmap getLogo(Context context);
/**
* 获取广告文字LogoBitmap
*/
Bitmap getTextLogo(Context context);
/**
* 获取广告素材类型
*/
int getMaterialType();
/**
* 获取按钮文案
*/
String getButtonText();
/**
* 是否视屏类广告
*/
boolean isVideo();
/**
* 获取放置广告内容的容器
*/
ViewGroup getViewContainer();
/**
* 获取广告视频view
*/
View getVideoView();
/**
* 注册view为可点击控件
*/
void registerViewForInteraction(List<View> views);
}
7.4、原生自渲染广告示例
-
注意: 在主线程中调用广告对象的创建(new Ad())和加载(load)方法
-
创建原生自渲染广告实例:
private NativeUnifiedAd mNativeAd;
private void loadAd() {
//context 必须传入 Activity类型
mNativeAd = new NativeUnifiedAd(NativeUnifiedAdActivity.this, "7166", new NativeUnifiedAdListener() {
@Override
public void onAdFailed(int code) {
Log.i("OctopusGroupDemo", TAG + " Native ad onAdFailed " + code);
Toast.makeText(getApplicationContext(), getResources().getString(R.string.load_ad_fail) + ",错误码 = " + code, Toast.LENGTH_LONG).show();
}
@Override
public void onAdLoaded(NativeUnifiedAdResponse response) {
Log.i("OctopusGroupDemo", TAG + " Native ad onAdLoaded");
Log.i("OctopusGroupDemo", "ad ecpm = " + mNativeAd.getECPM());
handleUnifiedView(response);
Toast.makeText(getApplicationContext(), getResources().getString(R.string.load_ad_success), Toast.LENGTH_LONG).show();
}
@Override
public void onAdShown() {
Log.i("OctopusGroupDemo", TAG + " Native ad onAdShown");
}
@Override
public void onAdClick() {
Log.i("OctopusGroupDemo", TAG + " Native ad onAdClick");
}
}, 5000);//第四个参数是:广告请求超时时长,建议设置为5000毫秒;
// 是否自动添加广告Logo,默认true
mNativeAd.setIsAddLogo(true);
// 广告加载
mNativeAd.loadAd();
}
@SuppressLint("InflateParams")
private void handleUnifiedView(NativeUnifiedAdResponse response) {
if (response == null) return;
View mUnifiedView = LayoutInflater.from(this).inflate(R.layout.item_native_unified_ad_view, null);
ImageView imageIv = mUnifiedView.findViewById(R.id.ad_image);
FrameLayout videoFl = mUnifiedView.findViewById(R.id.ad_video);
ImageView iconIv = mUnifiedView.findViewById(R.id.ad_icon);
TextView titleTv = mUnifiedView.findViewById(R.id.ad_title);
TextView desTv = mUnifiedView.findViewById(R.id.ad_desc);
Button actionBt = mUnifiedView.findViewById(R.id.ad_button);
Log.e("OctopusGroupDemo", TAG + "response imageUrl:" + response.getImageUrl()
+ "\n;IconUrl:" + response.getIconUrl()
+ "\n;getTitle:" + response.getTitle()
+ "\n;getDescription:" + response.getDescription()
+ "\n;getButtonText:" + response.getButtonText()
+ "\n;getMaterialType:" + response.getMaterialType()
+ "\n;isVideo:" + response.isVideo()
);
if (!TextUtils.isEmpty(response.getImageUrl())) {
OctopusImageUtils.with(this).load(response.getImageUrl()).into(imageIv);
}
if (!TextUtils.isEmpty(response.getIconUrl())) {
iconIv.setVisibility(View.VISIBLE);
OctopusImageUtils.with(this).load(response.getIconUrl()).into(iconIv);
}
if (!TextUtils.isEmpty(response.getTitle())) {
titleTv.setText(response.getTitle());
}
if (!TextUtils.isEmpty(response.getDescription())) {
desTv.setText(response.getDescription());
}
if (!TextUtils.isEmpty(response.getButtonText())) {
actionBt.setText(response.getButtonText());
}
if (response.isVideo()) {
imageIv.setVisibility(View.GONE);
videoFl.setVisibility(View.VISIBLE);
videoFl.addView(response.getVideoView(), new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 600, Gravity.CENTER));
}
View adContainer = response.getViewContainer();
if (adContainer instanceof FrameLayout) {
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
adContainer.setLayoutParams(params);
((FrameLayout) adContainer).removeAllViews();
((FrameLayout) adContainer).addView(mUnifiedView);
}
mAdContainer.removeAllViews();
mAdContainer.addView(adContainer);
List<View> views = new ArrayList<>();
views.add(imageIv);
views.add(actionBt);
views.add(titleTv);
views.add(iconIv);
response.registerViewForInteraction(views);
}
-
R.layout.item_native_unified_ad_view 布局文件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<ImageView
android:id="@+id/ad_image"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:contentDescription="@null"
android:scaleType="fitCenter" />
<FrameLayout
android:id="@+id/ad_video"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_marginBottom="20dp">
<ImageView
android:id="@+id/ad_icon"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_centerVertical="true"
android:adjustViewBounds="true"
android:contentDescription="@null"
android:scaleType="fitCenter"
android:visibility="gone" />
<Button
android:id="@+id/ad_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginEnd="5dp"
android:layout_marginRight="5dp"
android:contentDescription="@null"
android:importantForAccessibility="no" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginStart="5dp"
android:layout_marginLeft="5dp"
android:layout_toStartOf="@+id/ad_button"
android:layout_toLeftOf="@+id/ad_button"
android:layout_toEndOf="@+id/ad_icon"
android:layout_toRightOf="@+id/ad_icon"
android:orientation="vertical">
<TextView
android:id="@+id/ad_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#000000"
android:textSize="14sp" />
<TextView
android:id="@+id/ad_desc"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:textColor="#000000"
android:textSize="12sp" />
</LinearLayout>
</RelativeLayout>
</LinearLayout>
-
在页面的 onResume 和 onDestroy 方法中请调用:
@Override
protected void onResume() {
super.onResume();
// 必须要在Activity.onResume()时通知到广告数据,以便重置广告恢复状态
if (mNativeUnifiedAd != null) {
mNativeUnifiedAd.resume();
}
}
@Override
protected void onDestroy() {
if (mNativeUnifiedAd != null){
mNativeUnifiedAd.destroy();
}
super.onDestroy();
}
- PS:完整流程请参考 Demo 中的 com.octopus.demo.NativeUnifiedAdActivity 的示例代码。
八、竞胜竞败回传(媒体 RTB 时调用,提高 ECPM 出价)
-
说明:章鱼广告平台根据媒体传回来的竞胜竞败价格,通过相应算法自动提高出价来获得广告曝光,媒体 RTB 时一定要调用,否则会导致价格出不上去。
-
示例:
splashAd.sendWinNotice(1000); // 价格传竞价第二高价格
splashAd.sendLossNotice(100,ADBidEvent.PRICE_LOW_FILTER,ADBidEvent.CSJ); // 价格传竞价最高的价格
8.1 接口说明
-
IBidding 接口说明
方法名 含义 getECPM(); 获取本条广告实时的 eCPM 价格,单位是分 sendWinNotice(int secondWinPrice); 竞价成功时上报接口 secondWinPrice 竞价第二名价格,单位是分 (非必填) sendLossNotice(int winPrice, String lossReason, String winBidder); 竞价失败时上报接口 winPrice 胜出者价格 单位分(非必填) lossReason 竞价失败原因(非必填) winBidder 胜出者 (非必填) 枚举值如下 -
ADBidEvent
public class ADBidEvent {
/**
* 竞价失败原因
* 1001 底价过滤
* 1002 bid价格低于最高价
* 1003 素材黑名单过滤
* 1004 竞品过滤
* 1005 超时过滤
* 1006 其它过滤
*/
public static final String BID_PRICE_FILTER = "1001";
public static final String PRICE_LOW_FILTER = "1002";
public static final String ADM_BLACKLIST_FILTER = "1003";
public static final String COMPETE_FILTER = "1004";
public static final String TIMEOUT_FILTER = "1005";
public static final String OTHER_FILTER = "1006";
/**
* 竞价胜出者
* CSJ 穿山甲/头条
* GDT 优量汇/广点通
* KUAISHOU 快手
* BAIDU 百青藤/百度
* SIGMOB sigmob
* OPPO oppo
* VIVO vivo
* HUAWEI 华为
* XIAOMI 小米
* OCTOPUS 章鱼
* JD 京东
* QM 趣盟
* ONEWAY 万唯
* OTHER 其他家
*/
public static final String CSJ = "CSJ";
public static final String GDT = "GDT";
public static final String KUAISHOU = "KUAISHOU";
public static final String BAIDU = "BAIDU";
public static final String SIGMOB = "SIGMOB";
public static final String OPPO = "OPPO";
public static final String VIVO = "VIVO";
public static final String HUAWEI = "HUAWEI";
public static final String XIAOMI = "XIAOMI";
public static final String OCTOPUS = "OCTOPUS";
public static final String JINGDONG = "JD";
public static final String QUMENG = "QM";
public static final String ONEWAY = "ONEWAY";
public static final String OTHER = "OTHER";
}
九、TopOn 平台接入章鱼聚合文档
-
Topon 自定义广告接入地址:https://docs.toponad.com/#/zh-cn/android/NetworkAccess/customnetwork/customnetwork
-
9.1 自定义广告源 adapter 参数
参数填写:
{"app_id":"应用ID","slot_id":"广告位ID","is_unified":"是否是自渲染1:是 0 否"}
广告类型 广告类名称 服务端配置参数 开屏 com.octopus.group.topon.OctopusATSplashAdapter "app_id" // 应用 ID
"slot_id" // 广告位 ID插屏 com.octopus.group.topon.OctopusATInterstitialAdapter "app_id" // 应用 ID
"slot_id" // 广告位 ID激励视频 com.octopus.group.topon.OctopusATRewardVideoAdapter "app_id" // 应用 ID
"slot_id" // 广告位 ID原生 com.octopus.group.topon.OctopusATNativeAdapter "app_id" // 应用 ID
"slot_id" // 广告位 ID
"is_unified":"0"//渲染方式-模板渲染
"is_unified":"1"//渲染方式-自渲染横幅 com.octopus.group.topon.OctopusATBannerAdapter "app_id" // 应用 ID
"slot_id" // 广告位 ID -
9.2 添加广告平台
-
9.3 创建广告源