跳到主要内容

TapADN SDK Android 接入文档

SDK 概述​

TapADN SDK 是一款功能完善的移动广告SDK,支持多种广告形式:

  • 开屏广告(Splash Ad):应用启动时展示的全屏广告
  • 激励视频广告(Reward Video Ad):用户观看完整视频后获得奖励
  • Banner广告:固定位置的横幅广告
  • 插屏广告(Interstitial Ad):全屏或半屏的插屏广告
  • 信息流广告(Feed Ad):嵌入内容流中的原生广告

主要特性:

  • 丰富的自定义配置选项
  • 完善的隐私合规控制
  • 多样化的广告交互回调

最低支持 Android 5.0(API level 21),编译环境为 Android Studio。

将 dirichlet_ad_5.3.1.6.aar 拷贝到游戏目录下的 src/main/libs 目录中。

在游戏目录下 build.gradle 文件中添加代码:

提示
  • 从 SDK 5.2.1.5 版本开始,SDK 不再依赖 Android Support Library、AndroidX 或 Glide,无需为 SDK 添加这些依赖。
  • 从 SDK 4.1.0.0 版本开始,SDK 已不再依赖 RxJava,无需添加 RxJava 相关依赖(io.reactivex.rxjava2:rxandroid 和 io.reactivex.rxjava2:rxjava)。
repositories{
flatDir{
dirs 'src/main/libs'
}
}
dependencies {
// ...
implementation(name: "dirichlet_ad_5.3.1.6", ext: "aar") // 广告 SDK
implementation 'com.squareup.okhttp3:okhttp:3.10.0'
// ...
}

Android AD SDK 5.3.1.6 与 AD Demo 使用 OkHttp 3.10.0,上例与其保持一致。宿主已使用兼容版本时无需降级,请避免同时引入多份 OkHttp 类。

权限申请 & 清单声明配置​

配置 AndroidManifest.xml 时按实际功能选择权限,不要求全部添加。AAR 已声明的权限和组件会自动合并,请检查最终 Merged Manifest。权限声明不等于用户授权,也不会代替初始化前的隐私开关配置。

<!-- 广告 SDK 已添加的权限 -->
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

<!-- 以下权限按实际功能选用,当前 ADN 不采集或转发 IMEI -->
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<uses-permission android:name="android.permission.BLUETOOTH"/>
<!-- 仅在宿主确有蓝牙连接功能时按系统版本配置,不是广告接入的通用要求 -->
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
<!-- 位置相关功能按需配置;SDK 权限申请辅助接口仅申请粗略位置 -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<!-- 仅在需要发送通知时配置 -->
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>

<provider
android:authorities="${applicationId}.com.tds.ad.fileprovider"
android:name="com.tapsdk.tapad.internal.TapADFileProvider"
android:exported="false"
android:grantUriPermissions="true" />

AndroidManifest 组件配置​

重要:SDK内部使用了多个Activity和Provider,这些组件会自动合并到您的应用中,无需手动配置。但如果遇到合并冲突,可以参考以下配置:

点击查看完整的组件配置(仅供参考,正常情况无需手动添加)
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="your.package.name">

<!-- Android 11+ 包可见性配置 -->
<queries>
<intent>
<action android:name="android.intent.action.MAIN" />
</intent>
<package android:name="com.tencent.mm" />
</queries>

<application>
<!-- SDK内部使用的Activity(自动合并,无需手动添加) -->
<!-- 竖屏视频广告Activity -->
<activity
android:name="com.tapsdk.tapad.stub.activity.Stub_Standard_Portrait_Activity"
android:configChanges="orientation|keyboardHidden|navigation|screenSize"
android:exported="false"
android:screenOrientation="portrait" />

<!-- 横屏视频广告Activity -->
<activity
android:name="com.tapsdk.tapad.stub.activity.Stub_Standard_Landscape_Activity"
android:configChanges="orientation|keyboardHidden|navigation|screenSize"
android:exported="false"
android:screenOrientation="landscape" />

<!-- 试玩广告Activity -->
<activity
android:name="com.tapsdk.tapad.stub.activity.Stub_Playable_Portrait_Activity"
android:configChanges="orientation|keyboardHidden|navigation|screenSize"
android:exported="false"
android:screenOrientation="portrait" />

<activity
android:name="com.tapsdk.tapad.stub.activity.Stub_Playable_Landscape_Activity"
android:configChanges="orientation|keyboardHidden|navigation|screenSize"
android:exported="false"
android:screenOrientation="landscape" />

<!-- 通用广告Activity -->
<activity
android:name="com.tapsdk.tapad.stub.activity.Stub_Portrait_Activity"
android:configChanges="orientation|keyboardHidden|navigation|screenSize"
android:exported="false"
android:screenOrientation="sensorPortrait" />

<activity
android:name="com.tapsdk.tapad.stub.activity.Stub_Landscape_Activity"
android:configChanges="orientation|keyboardHidden|navigation|screenSize"
android:exported="false"
android:screenOrientation="sensorLandscape" />

<!-- 内置浏览器Activity -->
<activity
android:name="com.tapsdk.tapad.internal.ui.views.web.BrowserActivity"
android:exported="false"
android:screenOrientation="sensor"
android:configChanges="orientation|keyboardHidden|screenSize"
android:windowSoftInputMode="adjustResize|stateHidden" />

<!-- 应用安装/打开透明Activity -->
<activity
android:name="com.tapsdk.tapad.stub.activity.Stub_Install_or_OpenApp_Translucent_Activity"
android:configChanges="orientation|keyboardHidden|navigation|screenSize"
android:exported="false" />

<!-- FileProvider:用于APK下载安装 -->
<provider
android:name="com.tapsdk.tapad.internal.TapADFileProvider"
android:authorities="${applicationId}.com.tds.ad.fileprovider"
android:exported="false"
android:grantUriPermissions="true" />

<!-- 下载Provider -->
<provider
android:name="com.tapsdk.tapad.internal.download.OkDownloadProvider"
android:authorities="${applicationId}.com.tapsdk.tapad.okdownload"
android:exported="false" />
</application>
</manifest>

注意:

  • 以上组件配置会通过Gradle的Manifest合并机制自动添加到您的应用中
  • 如果在构建时遇到Manifest合并冲突,可以在主应用的AndroidManifest.xml中使用 tools:replace 或 tools:merge 来解决
  • ${applicationId} 会自动替换为您应用的包名

ProGuard 混淆配置​

重要:SDK 已内置 R8/ProGuard 混淆规则(通过 consumerProguardFiles 自动合并),通常无需手动添加任何配置。

如遇混淆相关问题或需要自定义配置,可参考以下规则:

-dontwarn okhttp3.**
-dontwarn okio.**
-dontwarn javax.annotation.**
-dontwarn org.conscrypt.**
-dontwarn com.tapsdk.tapad.**
-keepnames class okhttp3.internal.publicsuffix.PublicSuffixDatabase
-keepattributes JavascriptInterface
-keepclassmembers class * { @android.webkit.JavascriptInterface <methods>; }
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keepclasseswithmembers class * { public <init>(android.content.Context, android.util.AttributeSet); }
-keepclasseswithmembers class * { public <init>(android.content.Context, android.util.AttributeSet, int); }
-keep class * implements android.os.Parcelable { public static final android.os.Parcelable$Creator *; }
-keepclassmembers class * extends com.tapsdk.tapad.protobuf.GeneratedMessageLite {
<fields>;
}
-keepnames class * extends com.tapsdk.tapad.protobuf.GeneratedMessageLite
-keepnames class * extends com.tapsdk.tapad.protobuf.GeneratedMessageLite$Builder
-keeppackagenames com.tapsdk.tapad.**

注意:

  • 上述规则已包含在 SDK 的 AAR 文件中,构建时会自动应用
  • 正式发布前务必测试混淆后的 APK,确保广告功能正常运行

获取广告权限​

以下兼容接口仅检查并尝试申请尚未授予的 READ_PHONE_STATE 和 ACCESS_COARSE_LOCATION,不申请精确位置、通知等其他权限,也不会根据隐私控制器开关自动筛选。

当前 ADN 不采集或转发 IMEI。不要把获取设备状态或位置权限作为所有用户初始化 SDK 的前提;仅需某一项或其他权限时,应由宿主按具体功能自行申请并处理拒绝结果。

方式一:检查未授权权限并尝试申请

TapAdManager.get().requestPermissionIfNecessary(activity);

方式二:带申请记录的频控

TapAdManager.get().requestPermissionIfNecessary(activity, true);
  • activity:用于申请权限的 Activity 上下文。
  • enableFrequencyControl = false:与单参数版本相同,检查未授权权限后尝试申请,不保证每次弹窗;是否展示由系统权限状态等因素决定。
  • enableFrequencyControl = true:频控存储可用时,已有申请记录则跳过,否则尝试申请并记录;记录不代表用户已授权。频控存储尚未初始化时,会降级为普通申请,不能依赖它保证“初始化前只弹一次”。

请在用户触发相关功能、确需权限时调用,不要在每次启动时无条件申请。

初始化​

基本初始化​

取得所需用户同意并配置隐私控制器后,在主线程初始化一次,传入 Application 上下文。无需固定在 Application.onCreate() 中执行;首次启动应等待用户完成同意流程。下面的方法由宿主在满足这些条件后调用:

import com.tapsdk.tapad.TapAdSdk;
import com.tapsdk.tapad.TapAdConfig;
import com.tapsdk.tapad.TapAdCustomController;
import android.app.Application;

/**
* 自定义Application类
* 注意:需要在AndroidManifest.xml中配置此Application
*/
public class MyApplication extends Application {

// 由宿主在取得所需用户同意后,于主线程调用
public void initAdSdkAfterConsent(TapAdCustomController privacyController) {

// 构建SDK配置对象
TapAdConfig config = new TapAdConfig.Builder()
.withMediaId(YOUR_MEDIA_ID) // 必填:媒体ID(在 Dirichlet Ad 平台申请)
.withMediaName("YOUR_MEDIA_NAME") // 必填:媒体名称
.withMediaKey("YOUR_MEDIA_KEY") // 必填:媒体密钥(用于签名验证)
.enableDebug(false) // 选填:是否开启调试模式(正式版务必设置为false)
.withCustomController(privacyController) // 按用户选择配置,示例见下文
.shakeEnabled(true) // 选填:是否启用摇一摇广告交互功能,默认true开启
.build();

// 初始化 SDK
// 主线程调用,只需初始化一次;隐私控制器应在此之前完成配置
TapAdSdk.init(this, config);
}
}

完整配置示例​

以下返回值用于演示配置方式,请根据用户选择设置所有隐私开关,不要直接将示例中的 true 当作用户授权。新增四个开关示例以 false 演示关闭,SDK 未覆盖时默认值均为 true。

/**
* 完整的SDK初始化配置示例
* 包含所有可配置参数及详细说明
*/
TapAdConfig config = new TapAdConfig.Builder()
// ========== 基础必填参数 ==========
.withMediaId(YOUR_MEDIA_ID) // 必填:媒体ID(替换为实际值)
.withMediaName("YOUR_MEDIA_NAME") // 必填:媒体名称
.withMediaKey("YOUR_MEDIA_KEY") // 必填:媒体密钥

// ========== TapTap相关配置 ==========
.withTapClientId("YOUR_TAP_CLIENT_ID") // 选填:TapTap ClientId(如接入TapTap登录)

// ========== 功能开关 ==========
.enableDebug(false) // 选填:是否开启调试模式(正式版务必设置为false)
.shakeEnabled(true) // 选填:是否启用摇一摇广告交互功能

// ========== 隐私控制配置 ==========
.withCustomController(new TapAdCustomController() {

/**
* 是否允许SDK获取地理位置信息
* @return true-允许,false-不允许
*/
@Override
public boolean isCanUseLocation() {
return true;
}

/**
* 手动提供地理位置信息
* 仅在位置授权允许时使用,不用于初始化采集
* @return TapAdLocation对象,包含经纬度和精度
*/
@Override
public TapAdLocation getTapAdLocation() {
double latitude = 39.9042; // 纬度
double longitude = 116.4074; // 经度
double accuracy = 100.0; // 精度(米)
return new TapAdLocation(latitude, longitude, accuracy);
}

/**
* 是否允许SDK获取设备状态(READ_PHONE_STATE权限)
* @return true-允许,false-不允许
*/
@Override
public boolean isCanUsePhoneState() {
return true;
}

/**
* 手动提供设备IMEI
* 兼容接口;当前 ADN 不采集或转发 IMEI,包括手动提供的值
* @return IMEI字符串
*/
@Override
public String getDevImei() {
return null; // 返回null表示不提供
}

/**
* 是否允许SDK获取WiFi状态
* @return true-允许,false-不允许
*/
@Override
public boolean isCanUseWifiState() {
return true;
}

// 5.3.0.0 新增:MAC 访问控制(兼容接口,不新增 ADN 主动 MAC 采集)
@Override
public boolean isCanUsePhoneMacAddress() {
return false; // 示例关闭;请根据用户选择设置
}

// 5.3.0.0 新增:BSSID 采集,同时受 Wi-Fi 总开关控制
@Override
public boolean isCanUseBssid() {
return false; // 示例关闭;请根据用户选择设置
}

// 5.3.0.0 新增:SSID 采集,与 BSSID 分别配置,同样受 Wi-Fi 总开关限制
@Override
public boolean isCanUseSsid() {
return false; // 示例关闭;请根据用户选择设置
}

// 5.3.0.0 新增:传感器访问,与 shakeEnabled 交互开关独立
@Override
public boolean isCanUseSensor() {
return false; // 示例关闭;请根据用户选择设置
}

/**
* 是否允许SDK写入外部存储(用于下载APK)
* @return true-允许,false-不允许
*/
@Override
public boolean isCanUseWriteExternal() {
return true;
}

// 5.3.0.4 新增:自研 OAID 获取、使用及向适配器提供 OAID 的开关
// 默认 true,与 Android ID 开关独立;初始化前按用户授权配置
@Override
public boolean isCanUseOaid() {
return true; // 已取得必要授权时建议保持开启;用户拒绝或撤回授权时返回 false
}

/**
* 手动提供OAID(匿名设备标识符),同样受 OAID 开关控制
* @return OAID字符串
*/
@Override
public String getDevOaid() {
return null; // 不手动提供;SDK 仅在用户授权、隐私配置及设备条件允许时获取
}

/**
* 是否允许SDK获取应用安装列表
* @return true-允许,false-不允许
*/
@Override
public boolean alist() {
return true;
}

/**
* 是否允许SDK获取Android ID
* @return true-允许,false-不允许
*/
@Override
public boolean isCanUseAndroidId() {
return true;
}
})
.build();

// 初始化SDK
TapAdSdk.init(this, config);

OAID 采集与接入说明​

Android SDK 5.3.0.4 及以上版本支持独立的 OAID 开关 isCanUseOaid(),默认返回 true。建议在取得用户必要授权后保持开启,关闭或未获取到 OAID 可能影响广告投放效果。

SDK 可自动获取 OAID,开发者无需手动传入,getDevOaid() 可保留默认 null。将 isCanUseOaid() 设为 false 后,将关闭 TapADN 自身的 OAID 获取、使用及向适配器提供 OAID,包括缓存值和手动传入值。

隐私采集开关​

以下为 Android SDK 5.3.0.4 中 TapAdCustomController 的全部 11 个布尔开关,默认均返回 true。请在初始化前根据用户授权覆盖对应方法,需要关闭时返回 false。返回 true 不代表已取得用户授权或 Android 系统权限,也不代表 SDK 会采集全部对应信息。

版本说明中的“既有接口”表示在 5.3.0.0 之前已提供,不表示其最早引入版本;5.3.0.0 新增四项开关,5.3.0.4 新增独立 OAID 开关。

方法默认值版本说明控制范围
isCanUseLocation()true既有接口位置访问。
isCanUsePhoneState()true既有接口电话状态访问控制,包含自研 ADN 的设备序列号(Serial)读取及缓存值使用;接口存在不代表自研 ADN 主动采集 IMEI。
isCanUseWifiState()true既有接口Wi-Fi 状态访问;关闭后自研 BSSID、SSID 采集也受限。
isCanUseWriteExternal()true既有接口是否允许主动使用 WRITE_EXTERNAL_STORAGE;不等于授予系统存储权限。
alist()true既有接口应用安装列表访问。
isCanUseAndroidId()true既有接口Android ID 访问;与 OAID 开关独立。
isCanUsePhoneMacAddress()true5.3.0.0 新增MAC 地址访问兼容控制,不新增自研 ADN 主动 MAC 采集。
isCanUseBssid()true5.3.0.0 新增BSSID 采集,与 SSID 分别配置,同时受 Wi-Fi 总开关控制。
isCanUseSsid()true5.3.0.0 新增SSID 采集,与 BSSID 分别配置,同时受 Wi-Fi 总开关控制。
isCanUseSensor()true5.3.0.0 新增传感器访问;与 shakeEnabled 摇一摇交互开关独立。
isCanUseOaid()true5.3.0.4 新增自研 OAID 获取、使用及向适配器提供 OAID,包含缓存值和开发者提供值。

设备序列号(Serial)控制​

Android SDK 5.3.0.4 中,自研 ADN 在广告请求阶段通过 Android 系统接口读取设备序列号(Serial),作为广告请求中的设备标识符,并在本地缓存。该行为受既有的 isCanUsePhoneState() 开关及系统权限共同限制。

  • 请在初始化前按用户授权配置 isCanUsePhoneState();返回 false 时,自研 ADN 不读取 Serial,也不使用缓存的 Serial。此开关还控制其他电话状态访问,不能仅用于单独关闭 Serial。
  • Android 10 以下需通过 READ_PHONE_STATE 权限检查;Android 10 及以上需通过系统特权权限检查,普通应用仅获得 READ_PHONE_STATE 不能读取 Serial。SDK 不会为此主动申请额外权限,接入方无需新增特权权限声明。
  • 初始化阶段不主动读取系统 Serial;缓存值的使用同样受上述开关和系统权限限制。请在 App 隐私政策中按实际接入情况披露 Serial 的采集目的、方式和场景,参见隐私政策。

在初始化配置的 .withCustomController(...) 中覆盖该方法即可关闭;请保留控制器中已配置的其他隐私方法:

.withCustomController(new TapAdCustomController() {
@Override
public boolean isCanUsePhoneState() {
return false;
}
})

手动传值接口​

以下接口默认返回 null,用于开发者主动提供数据,不是采集开关。仅在取得相应授权且确有需要时提供。

方法说明
getTapAdLocation()手动提供位置;自研 ADN 仅在位置授权允许时使用,不用于初始化采集。
getDevOaid()手动提供 OAID,同样受 isCanUseOaid() 控制;返回 null 不等于关闭 OAID 获取。
getDevImei()兼容接口;当前自研 ADN 不采集或转发 IMEI,包括开发者提供的值。
provideCustomUser()提供 CustomUser 用户属性对象;不是隐私总开关或个性化广告开关。不提供时保留默认 null。

控制限制​

  • isCanUsePhoneMacAddress() 是兼容控制接口,不会新增自研 ADN 的主动 MAC 采集。
  • BSSID 与 SSID 可分别控制,但均不能绕过 isCanUseWifiState() == false。
  • 传感器授权与 shakeEnabled 摇一摇交互开关独立;关闭交互不等于关闭传感器授权。
  • 自研 ADN 初始化阶段不主动获取位置、BSSID、SSID、应用安装列表或传感器信息;广告请求阶段仍需遵循用户授权及隐私开关配置。
  • 手动提供的位置也受位置授权限制,不能通过回调绕过关闭状态。

广告个性化设置​

建议在 App 的广告设置或隐私设置中提供「个性化广告」开关,并向用户说明:

  • 开启后,SDK 会根据用户的使用情况展示更相关的广告。
  • 关闭后,广告数量不变,用户仍会看到广告,但广告相关度可能降低。

当用户修改开关时,调用以下接口同步到 SDK。App 需要自行保存用户选择,并在下次启动后重新设置一次。

import com.tapsdk.tapad.TapAdSdk;
import com.tapsdk.tapad.constants.Constants;

public void setPersonalizedAdEnabled(boolean enabled) {
TapAdSdk.putMediaGlobalSettings(
Constants.Personalization.PERSONAL_ADS_TYPE,
enabled
? Constants.Personalization.PERSONAL_ADS_TYPE_ALLOW
: Constants.Personalization.PERSONAL_ADS_TYPE_LIMIT
);
}

广告类型​

开屏广告​

开屏广告为用户在进入 App 时展示的全屏广告。开屏广告为一个 View,宽高默认为 match_parent。

信息

竖屏开屏广告 view 要求 width = 屏幕宽,height 需要 >= 75% 屏幕高,否则会影响计费。

横屏开屏广告 view 要求 width = 屏幕宽,height 需要 = 屏幕高,否则会影响计费。

建议业务逻辑:

  1. 每次启动应用的时候调用 SDK 接口请求开屏广告。
  2. SDK 会根据一定规则从候选队列里选取一个返回给游戏,获取成功就可以展示,获取失败的话本次不展示广告。
  3. 建议设置3-5秒的广告加载超时,超时后直接进入应用。
  4. 展示前务必检查广告的有效性(isValid())和过期时间。

获取广告​

import com.tapsdk.tapad.TapAdManager;
import com.tapsdk.tapad.TapAdNative;
import com.tapsdk.tapad.TapSplashAd;
import com.tapsdk.tapad.AdRequest;
import android.content.Context;
import android.util.DisplayMetrics;
import android.util.Log;

/**
* 开屏广告加载示例
*/
public class SplashAdLoader {

private TapAdNative tapAdNative;
private TapSplashAd splashAd;

public void loadSplashAd(Context context) {
// 第一步:创建广告加载器
// 注意:每个页面建议创建独立的TapAdNative实例
tapAdNative = TapAdManager.get().createAdNative(context);

// 第二步:获取屏幕尺寸(可选,用于优化广告展示效果)
DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
int screenWidth = displayMetrics.widthPixels;
int screenHeight = displayMetrics.heightPixels;

// 第三步:构建广告请求参数
AdRequest adRequest = new AdRequest.Builder()
.withSpaceId("YOUR_SPLASH_AD_SPACE_ID") // 必填:开屏广告位ID(在 Dirichlet Ad 后台获取)
.withExpressViewAcceptedSize(screenWidth, screenHeight)
// 选填:期望的广告尺寸(像素),建议传入屏幕实际宽高
.build();

// 第四步:加载开屏广告
tapAdNative.loadSplashAd(adRequest, new TapAdNative.SplashAdListener() {

/**
* 广告加载成功回调
* @param splashAd 开屏广告对象,用于后续展示
*/
@Override
public void onSplashAdLoad(TapSplashAd splashAd) {
Log.d("DirichletAD", "开屏广告加载成功");

// 保存广告对象
SplashAdLoader.this.splashAd = splashAd;

// 检查广告是否有效(是否在有效期内)
if (splashAd.isValid()) {
// 广告有效,可以展示
showSplashAd(splashAd);
} else {
// 广告已过期
Log.w("DirichletAD", "开屏广告已过期");
}
}

/**
* 广告加载失败回调
* @param code 错误码
* @param message 错误信息
*/
@Override
public void onError(int code, String message) {
Log.e("DirichletAD", "开屏广告加载失败: code=" + code + ", message=" + message);

// 根据错误码进行相应处理
switch (code) {
case 102001: // 网络异常
case 102002: // 网络超时
case 102003: // 无网络连接
// 可以提示用户检查网络或直接跳过
break;
case 103004: // 请求频繁
// 建议延迟一段时间后重试
break;
case 103002: // 无广告填充
// 正常情况,直接跳过
break;
default:
// 其他错误,建议跳过广告直接进入应用
break;
}
}
});
}

private void showSplashAd(TapSplashAd splashAd) {
// 展示广告的代码(见下文)
}
}

播放​

方式一:获取View并添加到容器

import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.RelativeLayout;
import com.tapsdk.tapad.TapSplashAd;

/**
* 展示开屏广告
* @param splashAd 已加载成功的开屏广告对象
*/
private void showSplashAd(TapSplashAd splashAd) {

// 第一步:设置广告交互监听器
splashAd.setSplashInteractionListener(new TapSplashAd.AdInteractionListener() {

/**
* 用户点击跳过按钮
* 在此进行资源清理和页面跳转
*/
@Override
public void onAdSkip() {
Log.d("DirichletAD", "用户点击跳过开屏广告");

// 销毁广告视图
splashAd.destroyView();
// 释放广告资源
splashAd.dispose();
// 跳转到主页
goToMainActivity();
}

/**
* 广告倒计时结束(自动关闭)
* 通常为3-5秒后自动触发
*/
@Override
public void onAdTimeOver() {
Log.d("DirichletAD", "开屏广告倒计时结束");

// 销毁广告视图
splashAd.destroyView();
// 释放广告资源
splashAd.dispose();
// 跳转到主页
goToMainActivity();
}

/**
* 用户点击广告(跳转到落地页)
*/
@Override
public void onAdClick() {
Log.d("DirichletAD", "用户点击开屏广告");
// 通常无需特殊处理,SDK会自动处理跳转
}

/**
* 广告开始展示
*/
@Override
public void onAdShow() {
Log.d("DirichletAD", "开屏广告开始展示");
// 可以在此记录广告展示事件
}

/**
* 广告有效曝光(满足曝光条件)
* 曝光条件通常包括:展示时长、可见面积等
*/
@Override
public void onAdValidShow() {
Log.d("DirichletAD", "开屏广告有效曝光");
// 建议在此上报广告曝光事件用于数据分析
}
});

// 第二步:获取广告View
View splashView = splashAd.getSplashView(activity);

// 第三步:从父容器中移除(如果已添加过)
// 这一步是为了避免重复添加导致的异常
if (splashView.getParent() != null) {
((ViewGroup) splashView.getParent()).removeView(splashView);
}

// 第四步:添加到布局容器
RelativeLayout container = findViewById(R.id.splash_container);
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.MATCH_PARENT, // 宽度充满父容器
RelativeLayout.LayoutParams.MATCH_PARENT // 高度充满父容器
);
container.addView(splashView, layoutParams);
}

/**
* 跳转到主页
*/
private void goToMainActivity() {
Intent intent = new Intent(this, MainActivity.class);
startActivity(intent);
finish(); // 结束开屏页
}

方式二:直接展示到Activity

splashAd.show(activity);

方式三:展示到指定容器

ViewGroup container = findViewById(R.id.splash_container);
splashAd.show(container);

设置应用Logo(仅开屏广告支持)​

开屏广告支持在左上角展示应用Logo,提升品牌识别度。

说明:Logo功能仅支持开屏广告,其他广告类型(激励视频、Banner、插屏、信息流)不支持Logo设置。

在SDK初始化时设置(推荐方式)

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;

public class MyApplication extends Application {
// 与基本初始化示例相同:取得所需用户同意后,在主线程调用一次
public void initAdSdkAfterConsent(TapAdCustomController privacyController) {

// 加载Logo图片
Bitmap logoBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.app_logo);

// 初始化SDK时配置Logo
TapAdConfig config = new TapAdConfig.Builder()
.withMediaId(YOUR_MEDIA_ID)
.withMediaName("YOUR_MEDIA_NAME")
.withMediaKey("YOUR_MEDIA_KEY")
.withCustomController(privacyController)
.withSplashLogoBitmap(logoBitmap) // 设置开屏广告左上角Logo
.enableDebug(false)
.build();

TapAdSdk.init(this, config);
}
}

Logo显示位置:

  • Logo显示在开屏广告的左上角
  • 竖屏时:距离顶部 44dp(状态栏下方),距离左侧 16dp
  • 横屏时:距离顶部 14dp,距离左侧 16dp
  • SDK会自动处理Logo的缩放和定位

注意:

  • Logo设置是可选的,不设置则不显示
  • Logo功能仅适用于开屏广告,不影响其他广告类型
  • Logo图片会占用内存,建议使用适当尺寸

广告生命周期管理​

@Override
protected void onDestroy() {
super.onDestroy();
if (splashAd != null) {
// 销毁广告视图
splashAd.destroyView();
// 释放广告资源
splashAd.dispose();
splashAd = null;
}
}

关闭开屏广告​

提示

注意 3.16.3.23 版本开始 开屏广告移除了自动关闭逻辑,需要媒体手动关闭。

// 场景 1 媒体展示开屏中直接关闭广告
if (splashAd != null)
{
splashAd.dispose();
splashAd.destroyView();
}

// 场景 2 在收到开屏广告交互事件后选择关闭
@Override
public void onAdSkip() {
if (splashAd != null)
{
splashAd.dispose();
splashAd.destroyView();
}
}

@Override
public void onAdTimeOver() {
if (splashAd != null)
{
splashAd.dispose();
splashAd.destroyView();
}
}

激励视频广告​

激励视频是一种全屏播放的视频广告,用户可以在观看完整的视频后获取奖励,视频广告播放结束后会显示结束页面,引导用户进行后续动作。目前激励视频广告的表现形式为:视频播放完展示 Endcard 页面。

使用场景包括但不限于:

  1. 游戏等应用内观看视频广告获得游戏内金币等。
  2. 积分类应用接入。
支持的广告尺寸
  • 全屏横屏(宽高比 16:9)
  • 全屏竖屏(宽高比 9:16)
  • Android 端暂不支持重力旋转。

获取广告​

// 注意,一个 Activity 中只需要创建一个 TapAdNative 对象
TapAdNative tapAdNative = TapAdManager.get().createAdNative(activity);

AdRequest adRequest = new AdRequest.Builder()
.withSpaceId("YOUR_SPACE_ID") // 广告后台获取广告位id
.withRewardName("YOUR_REWARD_NAME") // 奖品名称
.withRewardAmount("YOUR_REWARD_AMOUNT") // 奖品数量
.withExtra1("YOUR_EXTRA_INFO") // 游戏如果要通过 s2s 验证激励广告有效性的时候需要传入一些辅助信息来验证本次激励活动是否有效
.withUserId("GAME_USER_ID") // 游戏如果要通过 s2s 验证激励广告有效性的时候需要传入游戏中的玩家 id,来验证是否可以对当前用户发放奖励
.build();

tapAdNative.loadRewardVideoAd(adRequest, new TapAdNative.RewardVideoAdListener() {
@Override
public void onError(int code, String message) {
// 获取失败
}

@Override
public void onRewardVideoAdLoad(TapRewardVideoAd rewardVideoAd) {
// 获取广告成功,可以展示广告
}

@Override
public void onRewardVideoCached(TapRewardVideoAd rewardVideoAd) {
// 获取广告素材成功,可以展示广告,如果没有选择在 RewardVideoAdLoad 时展示广告。(更建议在这个回调中展示广告,体验更好)
}
});

播放​

// 注册激励广告交互事件监听
rewardAd.setRewardAdInteractionListener(new TapRewardVideoAd.RewardAdInteractionListener() {
@Override
public void onAdShow() {
// 激励广告已显示
}

@Override
public void onAdClose() {
// 激励广告已经关闭
}

@Override
public void onVideoComplete() {
// 视频播放结束
}

@Override
public void onVideoError() {
// 视频出错
}

@Override
public void onRewardVerify(boolean rewardVerify, int rewardAmount, String rewardName, int code, String msg) {
// 激励任务已完成,游戏可以选择在此时进行玩家奖励,或者进一步通过 s2s 的流程来确认是否可以对当前玩家发放奖励
}

@Override
public void onSkippedVideo() {
// 激励广告中玩家点击了跳过视频的按钮
}

@Override
public void onAdClick() {
// 激励广告点击事件
}

@Override
public void onAdValidShow() {
// 激励广告有效曝光事件 3.16.3.45 新增
}
});
rewardAd.showRewardVideoAd(activity);

模版渲染 Banner:开发者不用自行对广告样式进行编辑和渲染,可直接调用相关接口进行广告展示。

提示

不支持开发者在 view 添加按钮及对广告拦截处理。

获取广告​

// 注意,一个 Activity 中只需要创建一个 TapAdNative 对象
TapAdNative tapAdNative = TapAdManager.get().createAdNative(activity);
// 广告后台获取广告位 id
String spaceId = "YOUR_SPACE_ID";
tapAdNative.loadBannerAd(new AdRequest.Builder()
.withSpaceId(spaceId)
.build(), new TapAdNative.BannerAdListener() {

@Override
public void onError(int code, String message) {
// 获取广告失败
}

@Override
public void onBannerAdLoad(TapBannerAd bannerAd) {
// 获取广告成功,可以调用播放广告接口进行播放(**注意** banner 广告的获取和播放需要在同一个 activity 中)
}
});

播放​

bannerAd.setBannerInteractionListener(new TapBannerAd.BannerInteractionListener() {

@Override
public void onAdShow() {
// 广告已曝光
}

@Override
public void onAdClose() {
// 广告已关闭(玩家可以手动点击关闭 banner 广告)
}

@Override
public void onAdClick() {
// 玩家点击了 banner 广告
}

@Override
public void onDownloadClick() {
// 玩家点击了下载按钮
}

@Override
public void onAdValidShow() {
// 广告有效曝光
}
});

FrameLayout parentLayout = "your_layout";
parentLayout.addView(bannerAd.getBannerView());

自渲染信息流广告​

提示
  • TapADN SDK 从 3.16.3.28 版本开始自渲染信息流视频广告对外暴露视频控制接口。

为可自定义布局的信息流广告,包含大图和视频两种基本样式类型,应用下载、跳转到落地页和跳转到浏览器三种交互类型。

提示

支持的广告尺寸:

  • 大图(宽高比:1.78 的图片)
  • 视频(宽高比:1.78 的视频)

获取广告​

// 注意,一个 Activity/Fragment 中只需要创建一个 TapAdNative 对象
TapAdNative tapAdNative = TapAdManager.get().createAdNative(activity);
// 广告后台获取广告位 id
String spaceId = "YOUR_SPACE_ID";
tapAdNative.loadFeedAd(new AdRequest.Builder()
.withQuery("{QUERY}") // 搜索词,可选
.withSpaceId(spaceId)
.build(), new TapAdNative.FeedAdListener() {
@Override
public void onError(int code, String message) {
// 获取广告失败
}

@Override
public void onFeedAdLoad(TapFeedAd feedAd) {

}
});

// TapFeedAd 接口说明
public interface TapFeedAd {

/**
* 广告标题
*
* @return
*/
String getTitle();

/**
* 广告描述
*
* @return
*/
String getDescription();

/**
* 广告图标
*
* @return
*/
String getIconUrl();

/**
* 得到 Feed 广告图片模式
*
* @return 1:大图 2:视频
*/
int getImageMode();

/**
* 广告封面图片 Image list
*
* @return
*/
List<ImageInfo> getImageInfoList();

/**
* 获取 TapTap 得分
*
* @return
*/
double getScore();

/**
* 如果是直接下载类型,返回 apk 包大小,否则返回 “0B” 或者 “”。
*/
public String getApkSize();

/**
* 获取广告的 view,如视频广告的 view,当前版本为自动播放且默认打开声音,用户可以手动关闭声音。
*
* @return
*/
View getAdView();

/**
* @return 0: onKnown 1: 下载类广告 2:直接跳转外部App 3: 通过浏览器打开落地页
* 4: 小程序跳转类广告 3.16.3.30 新增
*/
int getInteractionType();

/**
* 获取合规信息
*
* @return
*/
ComplianceInfo getComplianceInfo();

/**
* 注册可点击的 view,click/show 会在内部完成
*
* @param container 渲染广告最外层的 ViewGroup
* @param clickViews 可点击的视图
* @param creativeViews 可点击的创意视图(广告下载的按钮)
* @param describeViews 可点击的介绍详情视图
* @param privacyViews 可点击的隐私协议视图
* @param permissionViews 可点击的权限视图
*
*/
@Deprecated
void registerViewForInteraction(ViewGroup container, List<View> clickViews, List<View> creativeViews,
List<View> describeViews, List<View> privacyViews, List<View> permissionViews, AdInteractionListener listener);

/**
* 注册可点击的 view,click/show 会在内部完成
*
* @param activity 渲染广告所在的 activity
* @param container 渲染广告最外层的 ViewGroup
* @param clickViews 可点击的视图
* @param creativeViews 可点击的创意视图(广告下载的按钮)
* @param describeViews 可点击的介绍详情视图
* @param privacyViews 可点击的隐私协议视图
* @param permissionViews 可点击的权限视图
*
*/
void registerViewForInteraction(Activity activity, ViewGroup container, List<View> clickViews, List<View> creativeViews,
List<View> describeViews, List<View> privacyViews, List<View> permissionViews, AdInteractionListener listener);

/**
* 设置下载监听器
*/
void setDownloadListener(TapAppDownloadListener listener);

/**
* 设置可以控制自渲染信息流视频,比如播放,暂停,音量键显隐等,v3.16.3.28可用
*/
void setVideoPlaySelfController(boolean isSelfController);

/**
* 设置自渲染信息流广告视频回调接口,v3.16.3.28可用
*/
void setVideoAdListener(VideoAdListener videoAdListener);

/**
* 暂停自渲染信息流广告视频播放,v3.16.3.28可用
*/
void stopVideoPlay();

/**
* 恢复自渲染信息流广告视频自动播放,v3.16.3.28可用
*/
void startVideoPlay();

/**
* 设置自渲染信息流广告音量键显隐,v3.16.3.28可用
*/
void setVolumeVisible(boolean isVisible);

/**
* 打开自渲染信息流广告视频音量(全局),v3.16.3.28可用
*/
void openVideoVolume();

/**
* 关闭自渲染信息流广告视频音量(全局),v3.16.3.28可用
*/
void closeVideoVolume();
}

// 应用合规信息
public interface ComplianceInfo {
/**
* 获取应用名称
*
* @return
*/
String getAppName();

/**
* 获取广告
*
* @return
*/
String getAppVersion();

/**
* 开发者名称
*
* @return
*/
String getDeveloperName();

/**
* 应用隐私协议地址
*
* @return
*/
String getPrivacyUrl();

/**
* 应用描述地址
*
* @return
*/
String getFunctionDescUrl();

/**
* 应用权限地址
*
* @return
*/
String getPermissionUrl();

}

public interface AdInteractionListener {

// 广告卡片点击
void onAdClicked(View view, TapFeedAd ad);

// 广告创意交互部分点击
void onAdCreativeClick(View view, TapFeedAd ad);

// 广告卡片曝光
void onAdShow(TapFeedAd ad);

// 广告卡片单次(第一次)曝光
void onDistinctAdShow(TapFeedAd ad);

// 广告有效曝光 3.16.3.45 新增
void onAdValidView(TapFeedAd ad);
}

// 自渲染信息流广告视频回调接口 3.16.3.28 版本开始
interface VideoAdListener {
void onVideoPrepared(TapFeedAd ad);
void onVideoStart(TapFeedAd ad);
void onVideoPause(TapFeedAd ad);
void onVideoVolumeOpen(TapFeedAd ad);
void onVideoVolumeClose(TapFeedAd ad);
}

// 广告包下载进度监听
public interface TapAppDownloadListener {

void onDownloadStart();

void onDownloadComplete();

void onUpdateDownloadProgress(int percent);

void onDownloadError();

void onInstalled();
}

广告行为监听​

信息

AdInteractionListener 涉及到广告计费,必须正确调用,convertView 必须使用 ViewGroup。

在加载到信息流广告后,接入方需要注册在信息流广告中可以点击的 View,即 TapFeedAd.registerViewForInteraction() 方法,以实现广告的功能交互及计。包含图文点击区域的注册,附加创意按钮点击区域的注册,隐私协议区域的注册,应用权限的注册。点击附加创意区域会进行应用下载操作。

注意: 如果需要点击图文区域也能进行下载,请将图文区域的 view 传入 creativeViews。示例代码如下:

public class FeedAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
...

@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
...
if (holder instanceof OtherViewHolder) {
...
} else if (holder instanceof adViewHolder) {
/**
* 注册可点击的 View,click/show 会在内部完成
* @param container 渲染广告最外层的 ViewGroup
* @param clickViews 可点击的 View 的列表
* @param creativeViews 用于下载的 View
* @param
*/
// 可以被点击的 view, 也可以把 convertView 放进来意味整个 item 可被点击,点击会跳转到落地页
// 创意点击区域的 view 点击根据不同的创意进行下载动作
// 如果需要点击图文区域也能进行下载动作,请将图文区域的 view 传入 creativeViewList
List<View> clickViewList = Collections.singletonList(adViewHolder.adImageView);
List<View> creativeViewList = Collections.singletonList(adViewHolder.creativeTextView);
List<View> privacyViewList = Collections.singletonList(adViewHolder.privacyTextView);
List<View> describeViewList = Collections.singletonList(adViewHolder.describeTextView);
List<View> permissionViewList = Collections.singletonList(adViewHolder.permissionTextView);

// 注册普通点击区域,创意点击区域。重要! 这个涉及到广告计费及交互,必须正确调用。convertView 必须使用 ViewGroup。
ad.registerViewForInteraction(activity, (ViewGroup) convertView, clickViewList, creativeViewList, describeViewList, privacyViewList, permissionViewList, new TapFeedAd.AdInteractionListener() {

// 点击普通区域的回调
@Override
public void onAdClicked(View view, TapFeedAd ad) {

}

// 点击创意区域的回调
@Override
public void onAdCreativeClick(View view, TapFeedAd ad) {

}

// 广告曝光展示的回调
@Override
public void onAdShow(TapFeedAd ad) {

}

// 广告第一次曝光
@Override
public void onDistinctAdShow(TapFeedAd ad) {

}

// 广告有效曝光 3.16.3.45 新增
@Override
public void onAdValidView(TapFeedAd ad) {

}
});
}
}
}

自定义下载确认弹窗​

Android AD 自渲染信息流可由宿主展示下载确认弹窗。以下示例适用于 SDK 5.3.1.6,接口基线为 5.3.1.1。

在广告加载成功后、注册点击区域前调用 setIsSelfDoubleWindow(true)。当 SDK 回调 onDownloadWindowConfirm() 时展示弹窗,用户确认后调用同一广告对象的 confirmDownload(),取消或关闭时调用 cancelDownload()。未开启时沿用 SDK 原有流程。

接口使用说明
setIsSelfDoubleWindow(true)开启宿主自定义确认弹窗,须在 registerViewForInteraction() 前调用
onDownloadWindowConfirm(TapFeedAd ad)收到回调后展示弹窗,不要在普通点击回调中自行下载 APK
confirmDownload()用户确认后继续由 SDK 执行后续下载、安装或打开流程
cancelDownload()取消本次待确认操作

以下方法放在持有广告的页面中。activity、adContainer 和各 View 列表由页面提供;应用隐私、权限及功能介绍的展示和点击绑定仍需保留。弹窗文案及样式可按产品需要调整。

import android.app.Activity;
import android.app.AlertDialog;
import android.view.View;
import android.view.ViewGroup;
import com.tapsdk.tapad.TapFeedAd;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;

// 页面成员字段,用于在页面销毁前关闭待处理弹窗。
private AlertDialog downloadDialog;

private void bindFeedAd(
Activity activity, TapFeedAd ad, ViewGroup adContainer,
List<View> clickViews, List<View> creativeViews,
List<View> describeViews, List<View> privacyViews,
List<View> permissionViews) {
ad.setIsSelfDoubleWindow(true);
ad.registerViewForInteraction(
activity, adContainer, clickViews, creativeViews,
describeViews, privacyViews, permissionViews,
new TapFeedAd.AdInteractionListener() {
@Override public void onAdClicked(View v, TapFeedAd ad) { }
@Override public void onAdCreativeClick(View v, TapFeedAd ad) { }
@Override public void onAdShow(TapFeedAd ad) { }
@Override public void onDistinctAdShow(TapFeedAd ad) { }
@Override public void onAdValidView(TapFeedAd ad) { }

@Override
public void onDownloadWindowConfirm(TapFeedAd ad) {
if (activity.isFinishing() || activity.isDestroyed()) {
ad.cancelDownload();
return;
}
AtomicBoolean decided = new AtomicBoolean(false);
Runnable cancel = () -> {
if (decided.compareAndSet(false, true)) {
ad.cancelDownload();
}
};
downloadDialog = new AlertDialog.Builder(activity)
.setTitle("下载确认")
.setMessage("是否继续下载、安装或打开该应用?")
.setPositiveButton("确认", (dialog, which) -> {
if (decided.compareAndSet(false, true)) {
ad.confirmDownload();
}
})
.setNegativeButton("取消", (dialog, which) -> cancel.run())
.setOnDismissListener(dialog -> cancel.run())
.show();
}
});
}

// 在页面销毁或释放该广告时调用;先关闭弹窗,再释放广告。
private void releaseFeedAd(TapFeedAd ad) {
if (downloadDialog != null) {
downloadDialog.dismiss();
downloadDialog = null;
}
ad.dispose();
}

返回键、点击弹窗外部或主动关闭弹窗均按取消处理;确认按钮导致弹窗关闭时不会再次取消。每次回调只提交一次确认或取消。

如需异步业务校验,请保留回调中的同一个 ad,在主线程且页面、广告仍有效时调用确认或取消方法。页面销毁后丢弃尚未返回的校验结果,广告释放后不要再调用确认。列表同时展示多个广告时,应分别管理各广告的弹窗和生命周期。

广告下载事件监听​

TapAppDownloadListener downloadListener = new TapAppDownloadListener() {

// 未开始下载
@Override
public void onIdle() {
}

// 下载中
@Override
public void onDownloadStart() {
}

// 下载完成
@Override
public void onDownloadComplete() {
}

/**
* 下载进度更新回调
* @param percent 取值范围[0,100] 当前下载进度
*/
@Override
public void onUpdateDownloadProgress(int percent) {;
}

// 下载出错 (网络/文件存储错)
@Override
public void onDownloadError() {
}

// 安装成功
@Override
public void onInstalled() {
}
};

Feed 流广告启动/暂停​

信息

如果 Feed 流是在 Activity 中使用,需要在 Activity 的 onResume 和 onPause 调用相关方法;

如果 Feed 流是在Fragment中使用,除了要考虑 onResume 和 onPause 的系统回调,还要注意 Fragment 的 setUserVisibleHint 回调。

// 启动
tapAdNative.resume();

// 暂停
tapAdNative.pause();

Feed 流广告销毁​

信息

如果是在 Activity 中创建,请在 Activity 中调用销毁方法

如果是在 Fragment 中创建,请在 Fragment 中调用销毁方法

tapAdNative.dispose();

插屏广告​

插屏广告:支持「全屏视频广告」、「全屏图文广告」和「半屏图文广告」等形式,具体广告展示形式在后台配置。

提示

插屏广告分横竖屏形式,强烈建议在后台配置后正确使用横屏或竖屏广告,若用错配置的 orientation,可能会出现 UI 兼容异常问题。

获取广告​

AdRequest adRequest = new AdRequest.Builder()
.withSpaceId("YOUR_SPACE_ID")
.build();
tapAdNative.loadInterstitialAd(adRequest,new TapAdNative.InterstitialAdListener() {
@Override
public void onInterstitialAdLoad(TapInterstitialAd interstitialAd) {
// 获取广告成功
}

@Override
public void onError(int code, String message) {
// 获取广告失败
}
});

播放​

interstitialAd.setInteractionListener(new TapInterstitialAd.InterstitialAdInteractionListener() {

@Override
public void onAdShow() {
Log.d(TAG,"onShow");
}

@Override
public void onAdClose() {
Log.d(TAG,"onAdClose");
}

@Override
public void onAdError() {
Log.d(TAG,"onAdError");
}

// 有效曝光回调 3.16.3.45 新增
@Override
public void onAdValidShow() {
Log.d(TAG,"onAdValidShow");
}

// 点击回调 3.16.3.47 新增
@Override
public void onAdClick() {
Log.d(TAG, "onAdClick");
}

});
interstitialAd.show(activity);

激励视频奖励发放说明​

奖励发放条件​

一般视频总时长为 10~60s,30s 以上的视频播放到 30s 时会显示“跳过”按钮。低于30s的激励视频观看达到 90% 即会回调奖励验证接口,高于 30s 激励视频观看到第 27s 的时候即会回调奖励验证接口。

奖励发放主要流程​

  • **客户端回调的优势:**对接简单、高效,通过接口回调结果在客户端完成奖励是否发放即可。
  • **服务端回调的优势:**开发者可在服务端进行二次校验,保证广告有效性后做出奖励发放,反作弊能力强。

奖励验证服务端回调 (S2S 验证)​

提示

S2S 验证需要开发者提供奖励发放的回调 URL,Security Key 由 Dirichlet Ad 服务端生成并提供给开发者,现阶段通过 KA 单点对接提供

  • 服务器回调模式不是必须的,只是增加了一次第三方服务器的验证判断。具体的奖励发放由客户端完成。
  • 服务端回调逻辑:Dirichlet Ad 根据“奖励发放条件“,先通过 “Dirichlet Ad 服务端”访问“开发者媒体服务端”向开发者确认是否进行奖励发放,再依据“开发者服务端”返回的 true/false,在客户端给出是/否发放奖励的回调。
  • Dirichlet Ad 服务端只是透传验证请求,不会在中间过程添加校验逻辑。为了保障开发者利益和用户体验,开发者可以在验证环节增加自己的校验逻辑。

SDK 奖励发放回调接口​

接口说明​
//视频播放完成后,奖励验证回调,rewardVerify:是否有效,code:错误码,msg:错误信息
void onRewardVerify(boolean rewardVerify, int rewardAmount, String rewardName,int code,String msg)
透传参数​

SDK 传给 Dirichlet Ad 服务端

字段名称字段定义字段类型备注
user_id用户idstring调用SDK透传,应用对用户的唯一标识
extra其他信息string调用SDK传入并透传,如无需要则为空

奖励验证方式​

  1. 同步验证
    1. 满足“奖励发放条件”
    2. 调用“奖励验证回调接口”,并等待返回
    3. 调用onRewardVerify
      1. rewardVerify=回调接口返回的isValid
      2. code=回调接口异常时的错误码
      3. msg=回调接口异常时的错误信息
    4. 开发者可根据rewardVerify决定是否发放奖励
  2. 异步验证
    1. 满足“奖励发放条件”
    2. 调用“奖励验证回调接口”,不等待返回
    3. 调用onRewardVerify
      1. rewardVerify=true(满足“奖励发放条件”)
      2. trans_id
    4. 开发者可通过trans_id查询服务端结果,决定是否发放奖励

奖励验证回调接口​

接口请求方式​
  • 接口请求方式: GET
  • 服务端会以 GET 方式请求第三方服务的回调链接,并拼接以下参数回传:
pid=%s&user_id=%s&trans_id=%s&extra=%s&sign=%s
请求参数定义​
字段名称字段定义字段类型备注
pid广告位 IDstring
user_id用户 IDstring调用 SDK 透传,应用对用户的唯一标识
trans_id交易 IDstring完成观看的唯一交易 ID,唯一标识该次激励广告
extra其他信息string调用 SDK 传入并透传,如无需要则为空
sign签名string签名
签名生成方式​
  • 获得 SecurityKey,在申请配置激励广告位页面,设置服务端验证回调接口时获取
  • 将 trans_id 和 SecurityKey 用 ':' 符号连接
  • 使用 sha256 生成签名,用小写 16 进制
sign = fmt.Sprintf("%x", sha256.Sum256(trans_id:SecurityKey))
返回值约定​
  • 返回值格式: json
  • 返回示例:
{"isValid":true}
返回值定义​
字段名称字段定义字段类型备注
isValid校验结果bool判定结果,是否发放奖励

测试与调试​

开启调试模式​

在开发阶段,建议开启SDK的调试模式以获取详细日志:

TapAdConfig config = new TapAdConfig.Builder()
.withMediaId(YOUR_MEDIA_ID)
.withMediaName("YOUR_MEDIA_NAME")
.withMediaKey("YOUR_MEDIA_KEY")
.enableDebug(false) // 是否开启调试模式(正式发布时务必设置为false)
.build();

注意:

  • 调试模式会输出大量日志,帮助排查问题
  • 正式发布时必须关闭调试模式(设置为false)
  • 调试模式可能影响性能,不要在生产环境使用

问题排查清单​

如果遇到广告无法展示的问题,请按以下清单排查:

  • SDK是否在取得所需用户同意、配置隐私控制器后于主线程初始化
  • mediaId、mediaKey等参数是否正确
  • 网络权限是否已添加并授予
  • 是否在主线程调用SDK方法
  • 广告容器是否正确添加到布局
  • Activity是否已销毁(广告展示时)
  • 是否开启了调试模式查看日志
  • 广告位ID(spaceId)是否正确
  • 是否在合适的时机调用dispose释放资源
  • AndroidManifest是否正确合并

常见问题​

如何处理广告加载超时?​

Handler handler = new Handler();
Runnable timeoutRunnable = new Runnable() {
@Override
public void run() {
// 超时处理
Toast.makeText(context, "广告加载超时", Toast.LENGTH_SHORT).show();
}
};

// 设置5秒超时
handler.postDelayed(timeoutRunnable, 5000);

// 加载广告
tapAdNative.loadSplashAd(adRequest, new TapAdNative.SplashAdListener() {
@Override
public void onSplashAdLoad(TapSplashAd splashAd) {
// 取消超时
handler.removeCallbacks(timeoutRunnable);
// 展示广告
}

@Override
public void onError(int code, String message) {
// 取消超时
handler.removeCallbacks(timeoutRunnable);
}
});

如何处理横竖屏切换?​

建议在Activity的AndroidManifest.xml中固定方向:

<activity
android:name=".SplashActivity"
android:screenOrientation="portrait"
android:configChanges="orientation|screenSize" />

如何避免内存泄漏?​

  1. 及时调用广告对象的 dispose() 方法
  2. 不要在静态变量中持有广告对象
  3. Activity销毁时清理所有广告引用
  4. 使用 ApplicationContext 而非 Activity context(在合适的场景)

为什么信息流广告视频不自动播放?​

检查以下几点:

  1. 是否调用了 tapAdNative.resume()
  2. 视频自动播放策略是否设置正确(VideoOption.AutoPlayPolicy)
  3. 当前网络环境是否符合播放策略(WiFi/移动网络)

如何提高广告填充率?​

  1. 确保SDK配置正确,mediaId、mediaKey等参数准确
  2. 合理控制广告请求频率,避免频繁请求
  3. 提供准确的地理位置信息
  4. 联系Dirichlet Ad运营团队优化广告配置

SDK 错误码说明​

以下为 Android SDK 5.3.0.4 中接入方可收到的常见错误。请结合回调场景、code 和完整 message 判断原因;不同端及聚合 SDK 的错误码不能混用。

广告加载失败​

错误码说明处理建议
100002请求参数无效检查广告请求及广告位参数
100003SDK 内部处理失败保留完整错误消息,重试仍失败时联系技术支持
100004SDK 未初始化完成 SDK 初始化后再加载广告
101004Context 为空检查传入的 Context 及其生命周期
102001网络请求失败检查网络连接及完整错误消息
102002网络请求超时检查网络状态,避免连续立即重试
102004DNS 解析失败检查设备网络和 DNS 配置
102005TLS 连接失败检查网络环境、证书及设备时间
103001广告加载失败根据错误消息排查响应或素材加载问题
103002广告无填充检查广告位配置,稍后重新请求
103005广告已过期重新加载广告

请求失败时还可能返回实际 HTTP 状态码或响应中的业务错误码,请保留原始 code 和 message,不要假定所有错误码均为六位数字。对于未列出的错误,请记录完整错误信息,并按加载失败处理。

服务端错误码说明​

广告请求的服务端业务错误可直接作为加载失败回调的 code 返回。例如 code = 10008,message 中包含 Server error code: 10008。这类错误与上面的 SDK 本地错误码共同使用,不能仅按数字位数判断来源。

服务端错误码说明处理建议
10001请求缺少设备信息确认 SDK 已正确初始化;持续出现时保留错误信息联系技术支持
10002请求中的设备标识信息不完整保留错误信息联系技术支持;此错误不代表某个具体标识(如 OAID)为空
10003请求缺少媒体信息检查媒体初始化配置
10004请求缺少应用信息核对应用信息与媒体配置,持续出现时联系技术支持
10005请求缺少 SDK 信息检查 SDK 依赖是否完整、版本是否配套
10006请求缺少网络信息保留错误信息联系技术支持;此错误不代表设备未联网
10008广告位不存在或与媒体不匹配核对媒体 ID、广告位 ID 及所属关系
10011当前请求没有可用广告源检查广告位投放配置,持续出现时联系技术支持
10012应用包名无效核对应用包名及媒体配置
20002没有广告满足底价要求检查广告位底价是否合理
20004广告位请求频率达到限制降低请求频率,避免失败后立即循环请求
20005媒体请求频率达到限制检查应用整体请求频率,稍后重试
20009当前返回的广告未通过可用性检查稍后重试,持续出现时联系技术支持
20011当前请求受到频次限制避免短时间重复请求,稍后重试
20014当前请求暂无可返回的广告稍后重试;持续出现时提供请求信息联系技术支持

以上为 TapADN 自身广告请求的错误说明,不适用于第三方广告网络的同号错误。请求信息由 SDK 自动生成,开发者无需手动补齐上述请求字段。表中未列出的错误,请保留完整 code、message 及返回的请求标识联系技术支持。

错误处理​

在带有 code、message 的失败回调中记录这两个字段。部分展示、播放失败回调不提供错误码,请按对应接口处理,不能自行套用加载错误码。

@Override
public void onError(int code, String message) {
Log.e("TapAd", "load failed: code=" + code + ", message=" + message);
// 根据错误类型提示或重新加载,避免在失败回调中无间隔循环请求。
}

联系技术支持时,请提供 SDK 版本、广告类型、广告位 ID 和完整错误消息;若返回内容中包含请求标识,请一并提供。