跳到主要内容

Dirichlet Ad SDK Android 接入文档

SDK 概述

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

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

主要特性:

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

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

dirichlet_ad_4.2.4.3.aar 拷贝到游戏目录下的 src/main/libs 目录中。

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

提示
  • Dirichlet Ad SDK 从 3.16.3.10 版本开始更新了 glide 的依赖,glide 版本从 4.0.0 更新到了 4.9.0。
  • 从 SDK 4.1.0.0 版本开始,SDK 已不再依赖 RxJava,无需添加 RxJava 相关依赖(io.reactivex.rxjava2:rxandroidio.reactivex.rxjava2:rxjava)。
repositories{
flatDir{
dirs 'src/main/libs'
}
}
dependencies {
// ...
implementation(name: "dirichlet_ad_4.2.4.3", ext: "aar") // 广告 SDK
implementation 'com.squareup.okhttp3:okhttp:3.12.1'
implementation "com.android.support:appcompat-v7:28.0.0"
implementation "com.android.support:support-annotations:28.0.0"
implementation "com.android.support:support-v4:28.0.0"
implementation "com.github.bumptech.glide:glide:4.9.0"
implementation 'com.android.support:recyclerview-v7:28.0.0'
// ...
}

权限申请 & 清单声明配置

配置 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.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"/>
<!-- targetVersion 31 及以上 建议游戏加上这个权限 -->
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
<!-- 为了获取更好的广告体验,建议游戏加上以下权限来获取用户信息 -->
<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">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/tapad_ad_file_path"/>
</provider>

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" />

<!-- 应用安装/打开透明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">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/tapad_ad_file_path" />
</provider>

<!-- 下载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:replacetools: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,确保广告功能正常运行

获取广告权限

为了获取更精准的广告推荐,SDK需要获取以下权限:

  • READ_PHONE_STATE:用于获取设备标识信息(如IMEI)
  • ACCESS_FINE_LOCATION:用于获取地理位置信息

建议在初始化之前主动请求这些权限,以提升广告填充率和用户体验。

SDK提供了两种权限请求方式:

方式一:基础权限请求(每次调用都会弹窗)

TapAdManager.get().requestPermissionIfNecessary(activity);

方式二:带频控的权限请求(推荐)

// enableFrequencyControl: true-启用频控,false-不启用频控
// 当启用频控时,SDK会记录是否已经请求过权限,避免重复弹窗
TapAdManager.get().requestPermissionIfNecessary(activity, true);

参数说明:

  • context:Activity 上下文,用于弹出权限请求对话框
  • enableFrequencyControl:是否启用频控
    • true:SDK 会通过 SharedPreferences 记录权限请求状态,只在首次调用时弹窗
    • false:每次调用都会检查并弹出权限请求(与无参版本相同)

推荐使用场景:

  • 应用启动时使用 requestPermissionIfNecessary(activity, true),避免每次启动都弹窗
  • 特定场景(如用户主动触发)使用 requestPermissionIfNecessary(activity, false) 或无参版本

初始化

基本初始化

在 Application 的 onCreate() 方法中初始化SDK:

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

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

@Override
public void onCreate() {
super.onCreate();

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

// 初始化 Dirichlet Ad SDK
// 注意:必须在Application的onCreate中初始化,且只需初始化一次
TapAdSdk.init(this, config);
}
}

完整配置示例

/**
* 完整的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;
}

/**
* 手动提供地理位置信息
* 当isCanUseLocation返回false时,可通过此方法提供位置
* @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
* 当isCanUsePhoneState返回false时,可通过此方法提供IMEI
* @return IMEI字符串
*/
@Override
public String getDevImei() {
return null; // 返回null表示不提供
}

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

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

/**
* 手动提供OAID(匿名设备标识符)
* @return OAID字符串
*/
@Override
public String getDevOaid() {
return null; // 返回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);

广告类型

开屏广告

开屏广告为用户在进入 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 {
@Override
public void onCreate() {
super.onCreate();

// 加载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")
.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());

自渲染信息流广告

提示
  • Dirichlet Ad 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 onAdValidShow();
}

// 自渲染信息流广告视频回调接口 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 可被点击,点击会跳转到落地页
List<View> clickViewList = new ArrayList<View>();
clickViewList.add(convertView);
// 创意点击区域的 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> describeTextView = Collections.singletonList(adViewHolder.describeTextView);
List<View> permissionViewList = Collections.singletonList(adViewHolder.permissionTextView);

// 注册普通点击区域,创意点击区域。重要! 这个涉及到广告计费及交互,必须正确调用。convertView 必须使用 ViewGroup。
ad.registerViewForInteraction((ViewGroup) convertView, images, 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 onAdValidShow(TapFeedAd 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是否正确初始化(在Application的onCreate中)
  • 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 错误码说明

错误码格式

SDK 错误码采用6位数字格式:1XXYYY

  • 1: 固定前缀,表示广告相关错误
  • XX: 错误类别(2位)
  • YYY: 具体错误编号(3位)

常见错误码

通用错误 (100XXX)

错误码说明解决方案
100000成功-
100001未知错误联系技术支持,提供session_id
100002参数无效检查传入参数是否正确
100003内部错误重试或联系技术支持
100004SDK未初始化确保先调用TapAdSdk.init()
100005资源已释放重新创建广告对象

初始化错误 (101XXX)

错误码说明解决方案
101001初始化失败检查配置参数是否正确
101002媒体ID无效确认媒体ID正确
101003媒体密钥无效确认媒体密钥正确
101004Context为空传入有效的Context
101005配置为空传入有效的TapAdConfig

网络相关错误 (102XXX)

错误码说明解决方案
102001网络异常检查网络连接,确保设备可以访问互联网
102002网络超时检查网络质量,可以稍后重试
102003无网络连接提示用户开启网络
102004DNS解析失败检查网络配置
102005SSL证书错误检查系统时间和证书
102006服务器错误稍后重试

广告加载错误 (103XXX)

错误码说明解决方案
103001加载失败重试或检查网络
103002无广告填充正常情况,稍后重试即可
103003广告位ID无效确认广告位ID正确
103004请求过于频繁降低广告请求频率,建议至少间隔30秒
103005广告已过期重新加载广告
103006缓存失败检查存储空间

广告展示错误 (104XXX)

错误码说明解决方案
104001展示失败检查广告状态是否有效
104002Activity为空传入有效的Activity
104003容器视图为空传入有效的容器
104004容器不可见确保容器已添加到布局且可见
104005应用横竖方向与广告位不匹配检查Activity的screenOrientation配置是否与广告位设置匹配
104006广告未就绪等待广告加载完成后再展示
104007广告已展示重新加载新广告

广告交互错误 (105XXX)

错误码说明解决方案
105001点击失败重试点击操作
105002落地页错误检查落地页配置
105003下载失败检查网络和存储空间
105004安装失败检查安装权限
105005深度链接失败检查目标应用是否已安装

资源相关错误 (106XXX)

错误码说明解决方案
106001资源加载失败检查网络连接
106002图片加载失败重试或使用降级方案
106003视频加载失败检查网络带宽和存储空间
106004存储空间不足提示用户清理存储空间
106005内存不足释放内存资源或降级处理

权限相关错误 (107XXX)

错误码说明解决方案
107001权限被拒绝请求相应权限
107002安装权限被拒绝引导用户开启安装权限
107003存储权限被拒绝请求存储权限
107004网络权限被拒绝在AndroidManifest中添加网络权限

兼容旧版本错误码

以下是旧版本SDK的错误码(SDK 4.0.0 之前),仍然保持支持:

错误码说明对应新错误码
3001初始化错误101001
3002网络异常102001
3003方向不匹配104005
3004容器无效104003
3005插屏广告异常104001
3006请求频繁103004
6001信息流重复使用100003
9000内部错误100003
9999未知错误100001

Session ID 说明

当发生错误时,SDK会在错误消息(message)中包含 session_id 用于问题排查:

  • 返回方式:session_id 作为 message 参数的一部分返回,错误码通过 code 参数单独返回
  • 用途:联系技术支持时提供 message 中的 session_id 可以快速定位问题
  • 隐私:Session ID 不包含用户敏感信息,仅用于技术排查

错误处理建议

tapAdNative.loadSplashAd(adRequest, new TapAdNative.SplashAdListener() {
@Override
public void onSplashAdLoad(TapSplashAd splashAd) {
// 广告加载成功
}

@Override
public void onError(int code, String message) {
// 记录错误日志
Log.e("DirichletAD", String.format("Ad load failed: code=%d, message=%s", code, message));

// 根据错误码做不同处理
switch (code) {
case 102001: // 网络异常(兼容旧版 3002)
case 102002: // 网络超时
case 102003: // 无网络连接
// 提示用户检查网络
Toast.makeText(context, "网络连接失败,请检查网络设置", Toast.LENGTH_SHORT).show();
break;

case 103004: // 请求频繁(兼容旧版 3006)
// 延迟重试
Log.w("DirichletAD", "请求过于频繁,请稍后再试");
break;

case 103002: // 无广告填充
// 正常情况,不做特殊处理
Log.d("DirichletAD", "暂无广告");
break;

case 100004: // SDK未初始化
Log.e("DirichletAD", "SDK未初始化,请先调用TapAdSdk.init()");
break;

default:
// 其他错误,可以尝试重新加载或使用降级方案
Log.e("DirichletAD", "广告加载失败,错误码: " + code);
break;
}
}
});