# 1-Aftanty SDK集成文档
# 集成前的准备工作
# 应用要满足的前提条件
- 使用 Android Studio 3.2 或更高版本
- 支持 Android X
- 确保您应用的 build 文件使用以下值:
- minSdkVersion 为 16 或更高版本
- compileSdkVersion 为 31 或更高版本
# SDK集成步骤
# 工程配置
# Step1:申请应用的APPID
请在AdsConflux 网盟平台上创建好应用ID和广告位ID
# Step2:导入aar及SDK依赖的jar包
将SDK压缩包内的open_ad_sdk.aar复制到Application Module/libs
文件夹(没有的话须手动创建), 并将以下代码添加到您app的build.gradle
中:
repositories {
// ... other project repositories
mavenCentral()
}
//...
dependencies {
// ... other project dependencies
The SDK will collect 'gaid' for ads after you called this method.
implementation fileTree(dir: "libs", include: ["*.jar", "*.aar"])
}
同时,为支持Java 8,请添加以下代码
android {
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
# Step3:AndroidManifest配置
添加权限
<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.USE_FULL_SCREEN_INTENT" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.EXPAND_STATUS_BAR" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="com.google.android.gms.permission.AD_ID" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGE" />
# Step4:添加 networkSecurityConfig
2020 年 10 月 1 日 - Android 9.0 (API 28) 默认阻止明文(非 HTTPS)流量,这会阻止广告正常投放。为缓解这种情况,其应用在 Android 9.0 或更高版本上运行的发布者应确保添加网络安全配置文件。这样做会将明文流量列入白名单,并允许投放非 HTTPS 广告。
在 AndroidManifest.xml 的 application 中添加 networkSecurityConfig:
<manifest>
<application
...
android:networkSecurityConfig="@xml/network_security_config"
...>
</application>
</manifest>
如果没有 network_security_config.xml
, 在 res/xml 文件夹创建 network_security_config.xml 文件,添加 base-config
并设置 cleartextTrafficPermitted
为 true
,参考如下:
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
...
<base-config cleartextTrafficPermitted="true">
<trust-anchors>
<certificates src="system"/>
</trust-anchors>
</base-config>
...
</network-security-config>
# Step5:添加 meta-data 和 queries
将申请到的 appkey 和 appId 替换 meta-data 中对应的 value 「注意」:gp线上产品com.afanty.channel的value必须填写"GOOGLEPLAY" ,否则可能会返回cdn广告,影响上架状态
<manifest>
<queries>
<intent>
<action android:name="android.intent.action.MAIN" />
</intent>
</queries>
<application>
<meta-data android:name="com.afanty.APP_KEY"
android:value="YOUR_APP_KEY"/>
<meta-data
android:name="com.afanty.APP_ID"
android:value="YOUR_APP_ID" />
<meta-data
android:name="com.afanty.channel"
android:value="GOOGLEPLAY" />
</application>
</manifest>
# Step6:依赖和混淆
使用 aar 集成方式,需要在 build.gradle 中添加以下依赖:
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
implementation 'com.google.android.exoplayer:exoplayer-core:2.16.0'
implementation 'androidx.work:work-runtime:2.7.1'
implementation 'androidx.appcompat:appcompat:1.4.2'
implementation 'com.google.android.material:material:1.3.0'
implementation "com.squareup.okhttp3:okhttp:3.14.9"
implementation "com.squareup.okhttp3:okhttp-urlconnection:3.11.0"
implementation "com.github.bumptech.glide:glide:4.10.0"
implementation "com.github.zjupure:webpdecoder:2.0.4.10.0"
混淆
sdk 内部做了混淆,接入方可以不用处理
# SDK 初始化配置
集成 AFanty SDK 并创建广告位后,您必须在发送任何广告请求之前调用 AftAdSdk.init()。许多新功能需要初始化:
建议在主进程的 Application onCreate() 中初始化,我们不支持多进程。
参考代码如下:
public class MyApplication extends MultiDexApplication {
@Override
public void onCreate() {
super.onCreate();
if (isMainProcess){
val appInfo = CustomBidRequest.App()
.appendAppName("demos")
.appendPkg("com.x.demo")
.appendVerCode(1)
.appendVerName("1.0")
val deviceInfo = CustomBidRequest.DeviceInfo()
.appendUA("Mozilla\\/5.0 (Linux; Android 11; Pixel 4a Build\\/RQ3A.210605.005; wv) AppleWebKit\\/537.36 (KHTML, like Gecko) Version\\/4.0 Chrome\\/106.0.5249.126 Mobile ")
.appendABI("armeabi-v7a")
.appendCPUBit("32")
.appendGaid("b6c5cd19-edf6-4ada-9fee-c9ff3d742fa9")
.appendH(1920)
.appendW(1080)
.appendImei("test-imei")
.appendLanguage("en")
.appendMacAdress("test-mp")
.appendPPI(660)
val adSettings = AftAdSdk.getDefaultAdSettingsBuilder()
.setApp(appInfo)
.setDeviceInfo(deviceInfo)
.setAnalysis(object : IAnalysis {
override fun onEvent(context: Context?, eventId: String?, infoMap: HashMap<String, String>?) {
}
})
.setBidHost("")
.build()
AftAdSdk.init(this, adSettings)
AftAdSdk.setGDPRStatus(this, true)
}
}
}
必须通过setBidHost("")方法传入域名,程序才能正确运行, 域名可填:
https://api.rethinkad.com
# GDPR
什么是 GDPR, 请参考 General Data Protection Regulation (GDPR) (opens new window)
如果用户同意GDPR协议
public class MyApplication extends MultiDexApplication {
@Override
public void onCreate() {
super.onCreate();
if (isMainProcess) {
AftAdSdk.setGDPRStatus(this, true)
AftAdSettings adSettings = AftAdSdk.getDefaultAdSettingsBuilder().build();
AftAdSdk.init(this, adSettings);
}
}
}
不同意GDPR协议
public class MyApplication extends MultiDexApplication {
@Override
public void onCreate() {
super.onCreate();
if (isMainProcess) {
AftAdSdk.setGDPRStatus(this, false)
AftAdSettings adSettings = AftAdSdk.getDefaultAdSettingsBuilder().build();
AftAdSdk.init(this, adSettings);
}
}
}
AftAdSdk.setGDPRStatus(Context, boolean)
可以随时多次调用此方法。特别是当用户的权限状态发生变化时,可以重新调用。 如果您的应用程序针对欧盟用户以外的用户,则需要调用
public class MyApplication extends MultiDexApplication {
@Override
public void onCreate() {
super.onCreate();
if (isMainProcess) {
AftAdSdk.setGDPRStatus(this, true)
AftAdSettings adSettings = AftAdSdk.getDefaultAdSettingsBuilder()
.build();
AftAdSdk.init(this, adSettings);
}
}
}
# 如果需要自定义安装器,可以调用以下方法
// path:the target apk file path
// Map like map "pkg":"com.x"
AftAdSdk.setInstaller(object : IInstaller {
override fun install(path: String?, ext: MutableMap<String, String>?) {
AftAdSdk.getInstallCallback().onStart(ext)
AftAdSdk.getInstallCallback().onProgress(100f,ext);
AftAdSdk.getInstallCallback().onResult(true,"success",ext);
}
});
# 如果需要自定义包名,可以参考以下代码
val appInfo = CustomBidRequest.App()
.appendAppName("demos")
.appendPkg("com.x.demo")
.appendPublisher("x")
.appendVerCode(1)
.appendVerName("1.0")
val adSettings = AftAdSdk.getDefaultAdSettingsBuilder()
.setApp(appInfo)
.build();
AftAdSdk.init(this, adSettings)
# 如果你需要显示促安装弹窗,你需要调用
AftPromotion.showPublisherDialog(Context context)
# AppInfo 和 DeviceInfo
您可以传入应用信息和设备信息,我们将为您匹配最好的广告进行展示。
这是个可选的选项。
public class MyApplication extends MultiDexApplication {
@Override
public void onCreate() {
super.onCreate();
if (isMainProcess) {
val appInfo = CustomBidRequest.App()
.appendAppName("demos")
.appendPkg("com.x.demo")
.appendPublisher("x")
.appendVerCode(1)
.appendVerName("1.0")
val deviceInfo = CustomBidRequest.DeviceInfo()
.appendUA("Mozilla\\/5.0 (Linux; Android 11; Pixel 4a Build\\/RQ3A.210605.005; wv) AppleWebKit\\/537.36 (KHTML, like Gecko) Version\\/4.0 Chrome\\/106.0.5249.126 Mobile ")
.appendABI("armeabi-v7a")
.appendCPUBit("32")
.appendGaid("b6c5cd19-edf6-4ada-9fee-c9ff3d742fa9")
.appendH(1920)
.appendW(1080)
.appendImei("test-imei")
.appendLanguage("en")
.appendMacAdress("test-mp")
.appendPPI(660)
AftAdSettings adSettings = AftAdSdk.getDefaultAdSettingsBuilder().build();
AftAdSdk.init(this, adSettings);
}
}
}
# 配置广告位
您应该已经在 AdsConflux广告后台上创建了一个广告位并收到了一个广告位 ID。您现在将使用它来识别您应用中的广告 tagId,并从 AFanty 请求与您的用户相关的广告。
完成上述步骤后,您可以开始在您的应用程序中展示广告,方法是为您的广告格式配置 tagId,如下面的链接所示:
# Banner Ads
Banner 广告通常出现在应用屏幕的顶部或底部。
# 先决条件
在您的应用中集成横幅广告之前:
- 已经有一个使用横幅格式的 tagId;
- 集成AFanty Ad SDK;
# 获取 Banner 广告
# Step 1. 将广告加载到 Banner 广告位
声明一个 RTBBannerAd
变量
private RTBBannerAd banner;
为 RTBBannerAd
设置 tagId, 然后调用load()
加载广告:
banner = new RTBBannerAd(context, tagId);
banner.setAdSize(AdSize.BANNER);
banner.setAdLoadListener(new IAdObserver.AdLoadCallback() {
@Override
public void onAdLoaded(RTBAd rtbAd) {
//the banner has successfully retrieved an ad.
}
@Override
public void onAdLoadError(AdError adError) {
//the banner has failed to retrieve an ad.
}
});
banner.setAdActionListener(new IAdObserver.AdEventListener() {
@Override
public void onAdImpressionError(AdError error) {
}
@Override
public void onAdImpression() {
//the banner has showed
}
@Override
public void onAdClicked() {
//the user has tapped on the banner.
}
@Override
public void onAdCompleted() {
}
@Override
public void onAdClosed(boolean hasRewarded) {
}
});
banner.load();
# Step 2. 展示 Banner Ad
当调用 onAdLoaded 方法时,您可以使用 getAdView 方法获取 banner view 并将其添加到容器视图 container/ViewGroup 中
banner.getAdView();
# Native 广告
原生广告可让您以与其现有设计一致的方式通过您的应用获利。您可以将广告布局设计为与应用的外观和风格保持一致。 SDK 自动处理图像缓存和指标跟踪,因此您可以专注于展示广告的方式、时间和位置。
# 先决条件
在您的应用中集成横幅广告之前:
- 已经有一个原生广告的 tagId;
- 集成AFanty Ad SDK;
# 获取 Native 广告
# Step 1. 请求 Native Ad
RTBNativeAd native = new RTBNativeAd(context, tagId);
native.setAdLoadListener(new IAdObserver.AdLoadCallback() {
@Override
public void onAdLoaded(RTBAd rtbAd) {
// Called when the ad for the given tagId has loaded.
}
@Override
public void onAdLoadError(AdError adError) {
// Called when a ad fails to load for the given tagId.
}
});
native.setAdActionListener(new IAdObserver.AdEventListener() {
@Override
public void onAdImpressionError(AdError error) {
}
@Override
public void onAdImpression() {
// Called when a ad shown
}
@Override
public void onAdClicked() {
// Called when a ad is clicked
}
@Override
public void onAdCompleted() {
}
@Override
public void onAdClosed(boolean hasRewarded) {
}
});
native.load();//Request ad
# Step 2:创建 XML layout
The Sample:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/native_outer_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/white">
<ImageView
android:id="@+id/native_icon_image"
android:layout_width="64dp"
android:layout_height="64dp"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_marginStart="10dp"
android:layout_marginTop="10dp"
android:background="@null"
android:visibility="gone"
android:contentDescription="@null" />
<TextView
android:id="@+id/native_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_marginEnd="8dp"
android:layout_marginTop="32dp"
android:layout_marginStart="10dp"
android:layout_toEndOf="@+id/native_icon_image"
android:layout_toStartOf="@+id/native_button"
android:textColor="@android:color/darker_gray"
android:textStyle="bold" />
<TextView
android:id="@+id/native_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_marginStart="10dp"
android:layout_marginTop="90dp"
android:textColor="@android:color/darker_gray" />
<com.afanty.ads.view.PlayerView
android:id="@+id/native_main_image"
android:layout_width="match_parent"
android:layout_height="200dp"
android:layout_alignParentStart="true"
android:layout_below="@+id/native_text"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_marginTop="10dp"
android:background="@null"
android:scaleType="centerCrop" />
<Button
android:id="@+id/native_button"
android:layout_width="120dp"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_marginEnd="10dp"
android:layout_marginTop="15dp"
android:background="@drawable/ads_button_bg"
android:clickable="true"
android:ellipsize="end"
android:focusable="true"
android:maxLines="1"
android:textColor="#ffffff"
android:textStyle="bold" />
<FrameLayout
android:id="@+id/ad_choices"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"/>
<ImageView
android:id="@+id/feed_ad_badge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ad_badge" />
</RelativeLayout>
# Step 3:展示 Native Ads
- 获取 BaseNativeAd 展示
TextView title = contentView.findViewById(R.id.native_title);
TextView content = contentView.findViewById(R.id.native_text);
TextView buttonView = contentView.findViewById(R.id.native_button);
ImageView iconImage = contentView.findViewById(R.id.native_icon_image);
PlayerView mediaLayout = contentView.findViewById(R.id.native_main_image);
//text
title.setText(nativeAd.getTitle());
content.setText(nativeAd.getContent());
buttonView.setText(nativeAd.getCallToAction());
//icon
AdViewRenderHelper.loadImage(iconImage.getContext(), nativeAd.getIconUrl(), iconImage);
//media view
mediaLayout.setVideoLifecycleCallbacks(new IAdListener.VideoLifecycleCallbacks() {
@Override
public void onVideoStart() {
}
@Override
public void onVideoPlay() {
}
@Override
public void onVideoPause() {
}
@Override
public void onVideoEnd() {
}
@Override
public void onVideoMute(boolean isMuted) {
}
});
mediaLayout.loadMediaView(
nativeAd.getNativeAd(), VideoOptions.Builder()
.setStartMuted(false)
.setSoundGravity(Gravity.END)
.build()
);
//click list
List clickViews = new ArrayList();
clickViews.add(title);
clickViews.add(content);
clickViews.add(buttonView);
clickViews.add(iconImage);
clickViews.add(mediaLayout);
//prepare
nativeAd.prepare(contentView, clickViews, null);
广告归因 您必须显示广告属性以表示该视图是广告
MediaView MediaView比例,推荐使用16:9,原生广告图片很大一部分尺寸是这个比例
调用 nativeAd.prepare() 一定要调用 prepare 方法,这个方法会监听contentView,如果被遮挡,或者不可见,会被认为无效显示。
# Interstitial Ads 插屏广告
插屏式广告提供全屏体验,通常结合富媒体以提供比横幅广告更高水平的交互性。插屏式广告通常在应用程序的自然过渡期间显示;例如,完成游戏关卡后,或等待加载新视图时。使用 RTBInterstitialAd 对象及其关联的侦听器在您的应用中获取和显示插页式广告。
# 先决条件
- Interstitial 类型的 tagId.
- 集成 AFanty 广告 SDK
# 获取 Interstitial 广告
# Step 1. 创建 Interstitial Ad
RTBInterstitialAd interstitial = new RTBInterstitialAd(context, tagId);
interstitial.setAdLoadListener(new IAdObserver.AdLoadCallback() {
@Override
public void onAdLoaded(RTBAd rtbAd) {
// Called when the ad for the given tagId has loaded and is ready to be shown.
}
@Override
public void onAdLoadError(AdError adError) {
// Called when a ad fails to load for the given tagId.
}
});
interstitial.setAdActionListener(new IAdObserver.AdEventListener() {
@Override
public void onAdImpressionError(AdError error) {
// Called when a ad show failed.
}
@Override
public void onAdImpression() {
// Called when a ad shown
}
@Override
public void onAdClicked() {
// Called when interstitial is clicked
}
@Override
public void onAdCompleted() {
}
@Override
public void onAdClosed(boolean hasRewarded) {
// Called when a interstitial ad is closed.
}
});
interstitial.load();//Request Ad
# Step 2. 展示 Interstitial Ad
如果 isAdReady()
返回 true, 调用 show 展示插屏广告
if (interstitial.isAdReady()){
interstitial.show();
}
# Step 3:销毁广告
当插页式广告关闭时使用 destroy() 销毁
interstitial.destroy();
# 激励视频广告
激励视频广告是一种让用户与您的应用保持互动并获得广告收入的好方法。奖励通常以游戏内货币(金币、硬币、道具等)的形式出现,并在视频成功完成后分发给用户。
# 先决条件
Rewarded
类型的 tagId.- 集成 AFanty 广告 SDK
# 获取激励视频广告
# Step 1: 请求 RTBRewardAd
RTBRewardAd rewardedAd = new RTBRewardAd(context, tagId);
rewardedAd.setAdLoadListener(new IAdObserver.AdLoadCallback() {
@Override
public void onAdLoaded(RTBAd rtbAd) {
// Called when the video for the given tagId has loaded.
}
@Override
public void onAdLoadError(AdError adError) {
// Called when a video fails to load for the given tagId.
}
});
rewardedAd.setAdActionListener(new IAdObserver.AdEventListener() {
@Override
public void onAdImpressionError(AdError error) {
}
@Override
public void onAdImpression() {
// Called when a rewarded video starts playing.
}
@Override
public void onAdClicked() {
// Called when a rewarded video is clicked.
}
@Override
public void onAdCompleted() {
// Called when a rewarded video is completed and the user should be rewarded.
}
@Override
public void onAdClosed(boolean hasRewarded) {
// Called when a rewarded video is closed.
}
});
rewardedAd.load();//Request ad
# Step 2:展示激励视频广告
如果 isAdReady()
返回 true, 调用show()
展示激励视频广告
if (rewardedAd.isAdReady()) {
rewardedAd.show();
}
# Step 3:销毁
当激励视频消失时调用 destroy()
rewardedAd.destroy();
# Error Code
error code | description |
---|---|
1000 | network error |
1001 | no fill |
1002 | The condition is not satisfied |
1003 | parammeter error |
2000 | server error |
2001 | internal error |
2002 | timeout |
3000 | unknow |
3001 | no vast content |
3002 | download vast error |
3003 | un support type |
3004 | download video error |
3005 | ad expired |
# Change Log
# 1.0.0
Initial version
# 1.0.1
Delete useless fields