| 文档版本 | 修订日期 | 修订说明 |
|---|---|---|
| v2.8.1 | 2025-02-11 | 修复已知问题; |
| v2.8.1 | 2024-02-14 | 修复已知问题; |
| v2.8.0 | 2024-10-10 | 修复已知问题; |
| v2.7.9 | 2024-08-12 | 修复已知问题,更新适配联盟SDK; |
| v2.7.8 | 2024-06-14 | 修复已知问题; |
| v2.7.7 | 2024-04-19 | 修复已知问题,优化广告加载逻辑,更新适配联盟SDK; |
| v2.7.6 | 2024-02-01 | 修复已知问题; |
| v2.7.5 | 2023-12-14 | 修复已知问题;自渲染交互样式调整;插屏支持自动关闭及刷新 |
| v2.7.4 | 2023-11-22 | 合规优化;更新联盟广告适配 |
| v2.7.3 | 2023-10-26 | 修复已知问题; 优化广告加载逻辑; 合规优化;更新联盟广告适配 |
| v2.7.2 | 2023-08-29 | 调整原生、模板广告加载策略;修复已知问题 |
| v2.7.1 | 2023-07-18 | 更新适配广告联盟SDK版本;优化广告策略 |
| v2.7.0 | 2023-07-06 | 新增原生混合广告 |
| v2.6.9 | 2023-06-20 | 修复已知问题 |
| v2.6.8 | 2023-05-19 | 优化广告逻辑;修复已知问题 |
| v2.6.7 | 2023-04-12 | 新增广告样式;修复已知问题 |
| v2.6.6 | 2023-03-27 | 修复已知问题 |
| v2.6.5 | 2023-03-08 | 竞价广告支持缓存控制 |
| v2.6.4 | 2023-02-17 | 新增预加载广告功能;修复已知问题 |
| v2.6.3 | 2023-01-04 | 新增缓存广告数据统计;修复已知问题 |
| v2.6.2 | 2022-12-05 | 缓存优化、请求逻辑优化,增加响应速度,修复已知问题 |
| v2.6.1 | 2022-11-18 | 支持快手服务端竞价,支持填充失败分析 |
| v2.6.0 | 2022-11-07 | api广告支持下载二次弹窗,联盟自渲染增加下载五要素透传 |
使用Funlink SDK前必须满足以下条件。
目前聚合广告SDK需要的参数为各广告联盟平台的APPID和各广告位对应ID,请在广告联盟官方指定平台申请或联系具体负责人!
| 广告联盟 | 开屏广告 | 原生广告 | 模板广告 | 横幅广告 | 插屏广告 | 全屏视频广告 | 激励视频广告 |
|---|---|---|---|---|---|---|---|
| 穿山甲 | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
| 优量汇 | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
| 快手 | ✔️ | ✔️ | ✔️ | ❌ | ✔️ | ✔️ | ✔️ |
| 京准通 | ✔️ | ✔️ | ❌ | ❌ | ✔️ | ❌ | ❌ |
| 百度联盟 | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
| Sigmob | ✔️ | ✔️ | - | ❌ | ✔️ | ✔️ | ✔️ |
| 趣盟 | ✔️ | ✔️ | - | - | ✔️ | - | ✔️ |
| MTG | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
| Adhub | ✔️ | - | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
| 华为 | ❌ | ❌ | - | ✔️ | ✔️ | - | ✔️ |
| OPPO | ❌ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
| 米盟 | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
接入方需事先在各三方广告联盟SDK平台申请相关广告参数,然后在Funlink聚合平台进行配置。在Funlink聚合平台配置之后,才能正常使用本SDK的聚合功能。
app目录下的build.gradle文件添加依赖
x
android { ... defaultConfig { ...
// 向下兼容版本为21 minSdkVersion 21 ... }}
// 引用 aarrepositories { flatDir { dirs 'libs' }}
dependencies { // 广告 implementation fileTree(include: ['*.jar', '*.aar'], dir: 'libs_yd/ad') //美数(汇盈)需要 implementation 'com.squareup.okhttp3:okhttp:3.12.1' implementation 'com.google.code.gson:gson:2.8.5' implementation 'com.googlecode.android-query:android-query:0.25.9' implementation 'com.android.support:cardview-v7:27.1.1' //优推需要 implementation 'com.squareup.okhttp3:okhttp:3.12.1' implementation 'com.squareup.okhttp3:logging-interceptor:3.12.0' implementation 'com.google.code.gson:gson:2.8.5' implementation 'com.github.bumptech.glide:glide:4.8.0' implementation 'com.google.android.exoplayer:exoplayer-core:2.13.3' implementation 'com.google.android.exoplayer:exoplayer-ui:2.13.3' implementation 'commons-codec:commons-codec:1.15' //快手需要 implementation 'com.android.support:design:28.0.0' implementation 'com.android.support:recyclerview-v7:28.0.0'
//oppo需要,如使用oppo广告需要引用 implementation 'androidx.appcompat:appcompat:1.0.2'//注意500版本之后强要求依赖 implementation 'androidx.recyclerview:recyclerview:1.0.0'//注意500版本之后强要求依赖 implementation 'androidx.legacy:legacy-support-v4:1.0.0' implementation 'com.squareup.okio:okio:2.5.0' implementation 'org.jetbrains.kotlin:kotlin-android-extensions-runtime:1.3.72' implementation 'android.arch.persistence:db-framework:1.1.1'//410版本新增 implementation 'androidx.palette:palette:1.0.0'//490版本新增 //由于可能与接入业务产生冲突,故由开发者决定依赖的版本,wechat sdk区分wechat-sdk-android与wechat-sdk-android-without-mta,由开发者决定依赖版本 implementation "com.tencent.mm.opensdk:wechat-sdk-android-without-mta:5.5.8"//注意480版本新增,可以提升广告效果 //米盟需要,如使用米盟广告需要引用 implementation 'com.google.code.gson:gson:2.8.5' }SDK所需权限如下:
xxxxxxxxxx<!--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" />
2、以下权限为可选权限,申请以下权限用于防作弊功能以及有助于广告平台投放广告
xxxxxxxxxx<!--可选权限,申请后用于防作弊功能以及有助于广告平台投放广告--><uses-permission android:name="android.permission.READ_PHONE_STATE" /><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /><uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /><uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" /><uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /><uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
部分广告平台的SDK中带有so库,各平台使用的so文件支持的架构如下:(开发者按需选择以下架构)
穿山甲:arm64-v8a、armeabi-v7a
快手广告:armeabi、arm64-v8a、armeabi-v7a、x86_64、x86 (3.3.15后不支持armeabi)
建议:在build.gradle中添加如下配置,可基本支持大部分手机架构:
xxxxxxxxxxdefaultConfig {...ndk{abiFilters 'armeabi-v7a','arm64-v8a'}}
请在用户授权后在合适的位置进行初始化,请求广告前必须先执行初始化。
xxxxxxxxxxpublic class MyApplication extends Application { public void onCreate() { super.onCreate(); // 参数1:上下文 Context // 参数2:appid,Funlink平台创建应用时获取,必填 YdConfig.getInstance().init(this,appid); // 参数1:上下文 Context // 参数2:appid,Funlink平台创建应用时获取,必填 // 参数3:渠道ID String,和后台对应渠道后可以分渠道配置流量,如不需要传空字符串 // 参数4:是否开启Debug Boolean,建议在开发阶段打开Debug,方便定位问题。正式环境请关闭 //YdConfig.getInstance().init(this,appid, "渠道id", false); ... } }
| aar名称 | 作用 |
|---|---|
| funlink_1.0.x | Funlink核心包,必选 |
| funlink_adapter_bd_1.0.x | 百度适配器,如使用百度广告必选 |
| funlink_adapter_jzt_1.0.x | 京准通适配器,如使用京准通广告必选 |
| funlink_adapter_ks_1.0.x | 快手适配器,如使用快手广告必选 |
| funlink_adapter_csj_1.0.x | 穿山甲适配器,如使用穿山甲广告必选 |
| funlink_adapter_gdt_1.0.x | 优量汇适配器,如使用优量汇广告必选 |
| funlink_adapter_sb_1.0.x | Sigmob适配器,如使用Sigmob广告必选 |
| funlink_adapter_qtt_1.0.x | 趣盟适配器,如使用趣盟广告必选 |
| funlink_adapter_mtg_1.0.x | MTG适配器,如使用MTG广告必选 |
下面广告请求中需要传入Context的地方都需要传入activity。
展示开屏页的位置:冷启动进入应用时,加载开屏页广告,广告展示完毕,根据各应用的逻辑跳转到相应页面。建议将应用的logo放到广告页的下面,高度不超过200个像素(详见demo),或者将logo页作为广告的背景,有广告返回时广告盖住logo,无广告返回时继续展示logo。
特别注意:当用户点击广告跳转到广告详情页面后onAdclose()方法仍然会被调用,此时开发者还不能打开自己的App主页,当从广告落地页返回以后才可以跳转。所以使用canJump字段配合页面生命周期辅助判断正确的跳转时机。
xxxxxxxxxxprivate YdSpread ydSpread;private boolean canJump;/*** 加载开屏页* * context 上下文* setKey 运营分配的媒体位* setScreenPercentage 开屏广告展示区域占屏幕高度的比例,不设置默认为1即全屏高度。* 取值范围为0.75到1。如果设计的开屏不是铺满全屏需要计算此值传入。* setSpreadLoadListener 请求成功监听* setSpreadListener 回调监听*/
private void loadSplashAd() { ydSpread = new YdSpread.Builder(this) .setKey(String) .setScreenPercentage(1)//此方法可不调用,具体说明见上面注释 .setSpreadLoadListener(new SpreadLoadListener() { public void onADLoaded(final SpreadAd spreadAd) { // 广告请求成功回调该方法 spreadAd.show(mAdContainer); } }) .setSpreadListener(new AdViewSpreadListener() { public void onAdDisplay() { // 广告展示时回调该方法 }
public void onAdFailed(YdError error) { // 广告异常、失败,回调该方法 }
public void onAdClick() { // 广告被点击时回调该方法 } public void onAdClose() { // 广告关闭时回调该方法 jumpToMain(); } }) .build(); ydSpread.requestSpread(); }
/** * 先判断canJump的值,如果为false说明当前页面已不可见不进行跳转 * 修改canJump值为true等再次返回此页面后再跳转 */private void jumpToMain() { if (canJump) { doJump(); } else { canJump = true; }}
/*** 通过onPause()和onResume()方法和canJump变量,控制广告关闭后* 以及从广告详情返回时页面的跳转*/protected void onPause() { super.onPause(); canJump = false;}
/*** 通过onPause()和onResume()方法和canJump变量,控制广告关闭后* 以及从广告详情返回时页面的跳转*/protected void onResume() { super.onResume(); if (canJump) { doJump(); } canJump = true;}
protected void onDestroy() { super.onDestroy(); if (ydSpread != null) { ydSpread.destroy(); }}
//禁止用户返回键退出APP,以免影响广告的曝光和计费public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_HOME) { return true; } return super.onKeyDown(keyCode, event);}备注:自定义跳过按钮样式时,不要将跳过按钮置于展示广告的容器内,否则会被移除。应该将跳过按钮与展示广告的容器平级设置,可参考Demo的布局方式
插屏广告一般用于离开当前页时或者游戏角色死亡时弹出的广告,可自行传入宽高值,但最终插屏广告的宽高只能接近传入的数值,并不是1:1完全符合。请求插屏广告的时间相对较久(2s左右),为了更好的体验,所以请提前请求,展示的时候只需要show即可
xxxxxxxxxxYdInterstitial ydInterstitial; /*** 请求插屏广告* context 上下文* setKey 运营分配的媒体位* setWidth 请求广告的宽,单位dp,最终以实际宽度为准* setHeight 请求广告的高,单位dp,最终以实际高度为准* setIconListener 回调监听*/private void loadAd() { ydInterstitial = new YdInterstitial.Builder(this) .setKey(String) .setWidth(Integer) .setHeight(Integer) .setInterstitialListener(new AdViewInterstitialListener() { public void onAdReady() { //请求成功时回调。可以在此处调用展示 showAd(); }
public void onAdDisplay() { //广告展示时回调 }
public void onAdClick() { //广告被点击时回调 }
public void onAdClosed() { //广告关闭时回调 }
public void onAdFailed(YdError error) { //广告请求失败时回调 }
}) .build(); ydInterstitial.requestInterstitial(); }
// 展示广告。展示方法只在onAdReady回调后调用有效private void showAd() { if (ydInterstitial != null && ydInterstitial.isReady()) { ydInterstitial.show(activity); }}
protected void onDestroy() { super.onDestroy(); ydInterstitial.destroy();}Banner的宽度一般是屏幕的宽度,高度在100-150像素之间。Banner广告请求成功后,会有View返回,接入方将其展示在屏幕中即可
xxxxxxxxxxYdBanner ydBanner; /*** 加载banner* context 上下文* setKey 运营分配的媒体位* setBannerListener 回调监听*/private void loadBannerAd() { ydBanner = new YdBanner.Builder(Activity) .setKey(String) // 设置banner的宽度,单位dp,默认值为屏幕宽度,采用默认值时可不用设置 // .setExpressWidth(int) // 设置banner的高度,单位dp,默认值为宽度1/6.4,采用默认值时可不用设置 // .setExpressHeight(int) .setBannerListener(new AdViewBannerListener() { public void onReceived(View view) { // 请求广告成功,返回banner }
public void onAdClick() { // 广告被点击时回调该方法 }
public void onAdFailed(YdError error) { // 广告加载出错时回调该方法 } }) .build(); ydBanner.requestBanner(); }
protected void onDestroy() { super.onDestroy(); ydBanner.destroy();}激励视频是一种收益较高的广告类型,广告播放过程中,不能中途关闭,只有广告播放完毕后才会出现关闭按钮,选择使用时需慎重
xxxxxxxxxx
/*** 请求激励视频* @param String 运营分配的key* @param AdViewVideoListener 回调*/
private void loadRewardVideoAd() { ydVideo = new YdVideo.Builder(this) .setKey(String) //不使用服务端校验无须设置,如使用服务端校验必须设置,且此值不能为空 .setUserId("唯一id") .setCustomData("自定义数据")//不使用服务端校验无须设置,如使用服务端校验选择设置 //不使用服务端校验无须设置,如使用服务端校验必须设置 .setAdViewVideoCheckListener(new AdViewVideoCheckListener() { public void onVideoCheckReward(String transID) { //返回校验用订单id,如开启服务端校验,会在onVideoReward回调前给此回调,如未开启服务端校验无需设 置此监听 } }) .setVideoListener(new AdViewVideoListener() {
public void onAdShow() { // 视频展示回调 }
public void onAdClose() { // 视频关闭回调 }
public void onVideoPrepared() { // 视频加载完成回调 // 需要在此回调后调用视频播放方法 showVideo(); }
public void onVideoReward() { // 视频播放奖励回调 }
public void onVideoCompleted() { // 视频播放完毕回调 }
public void onAdClick() { // 视频点击回调 }
public void onAdFailed(YdError error) { // 视频请求失败回调 } }) .build(); ydVideo.requestRewardVideo();}
/*** 播放视频广告*/
public void showVideo() { if (ydVideo != null && ydVideo.isReady()) { ydVideo.show(); }}
protected void onDestroy() { super.onDestroy(); if (ydVideo != null) { ydVideo.destroy(); }}
全屏视频在广告形式上类似激励视频,区别在于广告播放开始或者几秒钟后可以选择关闭,全屏视频没有额外获取奖励的回调。
xxxxxxxxxx private YdFullVideo ydFullVideo;
ydFullVideo = new YdFullVideo.Builder(this) .setKey(String)//广告id .setVideoListener(new AdViewFullVideoListener() {
public void onAdFailed(YdError error) { //请求失败时调用 }
public void onAdClicked() { //广告点击时调用 }
public void onPageDismiss() { //广告关闭时调用 }
public void onVideoPrepared() { // 视频加载完成时调用 //可以在视频加载完成回调后择机展示 if (ydFullVideo != null && ydFullVideo.isReady()) { ydFullVideo.show();//展示全屏视频 } }
public void onVideoPlayStart() { // 视频展示时调用 }
}) .build(); ydFullVideo.requestFullVideo();//请求全屏视频广告原生混合广告是将自渲染信息流广告,模版信息流广告,Draw信息流广告封装到同一个API中的广告请求方式。开发者可以在同一个广告位中配置上述不同的广告样式混用。
xxxxxxxxxxpublic class YdSDK { /** * 加载原生混合广告请求对象 * * @param context 请使用Activity作为上下文 * @param params 广告请求的参数配置 * @param listener 广告加载回调监听 */ public static void loadMixNative(Context context, AdParams params, NativeLoadListener listener)}
/** * 原生混合广告请求的参数配置 */public class AdParams {
/** * 原生混合广告配置构造器 */ public static class Builder {
/** * 构造函数 * * @param posId 广告位Id */ public Builder(String posId)
/** * 设置模板广告的期望宽度,优量汇、穿山甲、京准通、OPPO、Vivo等广告联盟需要。 * 优量汇可配置为宽度适配父控件宽度,参见{@link #setExpressFullWidth}方法。 * * @param width 模板广告的期望宽度,单位dp * @return {@link AdParams.Builder} */ public Builder setExpressWidth(float width)
/** * 设置模板广告的期望高度,优量汇、穿山甲、京准通、OPPO、Vivo等广告联盟需要。 * 优量汇、穿山甲、Vivo支持高度自适应,参见{@link #setExpressAutoHeight}方法。 * * @param height 模板广告的期望高度,单位dp * @return {@link AdParams.Builder} */ public Builder setExpressHeight(float height)
/** * 设置自渲染广告期望的图片素材宽度。穿山甲,京准通需要。 * * @param width 渲染广告期望的图片素材宽度,单位px * @return {@link AdParams.Builder} */ public Builder setImageAcceptedWidth(int width)
/** * 设置自渲染广告期望的图片素材高度。穿山甲,京准通需要。 * * @param height 渲染广告期望的图片素材高度,单位px * @return {@link AdParams.Builder} */ public Builder setImageAcceptedHeight(int height)
/** * 模板广告高度自适应,优量汇、穿山甲、Vivo支持。 * * @return {@link AdParams.Builder} */ public Builder setExpressAutoHeight()
/** * 模板广告宽度最大程度的使用其父控件给予的宽度,优量汇支持。 * * @return {@link AdParams.Builder} */ public Builder setExpressFullWidth()
/** * 生成{@link AdParams}对象。 * * @return {@link AdParams} */ public AdParams build() }}
/** * 原生混合广告加载监听回调 */public interface NativeLoadListener { /** * 广告请求成功 * @param nativeAd 请求成功的原生混合广告对象 */ void onNativeAdLoaded(NativeAd nativeAd); /** * 广告请求错误 * @param error 错误原因 */ void onAdFailed(YdError error);}
xxxxxxxxxx/** * 原生混合广告对象,广告请求成功返回此对象 */public interface NativeAd { /** * 是否为模板渲染类型的广告 * * @return false:自渲染广告,ture:模板广告 */ boolean isNativeExpress();
/** * 绑定展示广告的容器 * * @param nativeAdView 展示广告的容器,广告必须在此容器中,必须为{@link NativeAdView} * @param selfRenderView {@link #isNativeExpress()}返回false时(即自渲染广告)需传入开发者自定义的广告view; * 返回ture时(即模板广告)可传null。 */ void renderAdContainer(NativeAdView nativeAdView, View selfRenderView);
/** * 渲染展示广告 * * @param prepareInfo 自渲染广告需绑定广告组件配置,用于配置广告点击控件、关闭按钮等等。 * <p> * {@link #isNativeExpress()}返回ture时(即模板广告)可传null。 * 对于模板广告,穿山甲广告需要处理关闭按钮必须设置Activity */ void prepare(NativePrepareInfo prepareInfo);
/** * 绑定视频控件的状态,在Activity的onResume时调用(主要针对部分广告平台的视频广告) */ void onResume();
/** * 绑定视频控件的状态,在Activity的onPause时调用(主要针对部分广告平台的视频广告) */ void onPause();
/** * 获取广告素材或广告view */ NativeMaterial getAdMaterial();
/** * 获取广告的ECPM * * @return ECPM值,单位:分。 */ int getECPM();
/** * 设置广告事件监听 * @param listener 广告事件监听器 */ void setNativeEventListener(NativeEventListener listener);
/** * 销毁当前的广告对象(执行之后该广告无法再进行展示) */ void destroy();}
/** * 自渲染广告需绑定广告组件配置 */public class NativePrepareInfo { /** * 可为null,设置关闭按钮,仅穿山甲、京准通支持。设置后支持{@link NativeEventListener}中的广告关闭回调。 * 在支持的广告联盟渲染后调用方不可对其设置点击事件监听。 * * @param closeView 关闭按钮 */ public void setCloseView(View closeView)
/** * 设置创意点击区(Action),点击事件将有SDK处理,渲染后调用方不可对其设置点击事件监听。 * * @param ctaViews 创意点击区(Action)View */ public void setCtaView(View... ctaViews)
/** * 设置可点击View,点击事件将有SDK处理,渲染后调用方不可对其设置点击事件监听。 * * @param clicks 可点击View */ public void setClickView(View... clicks)
/** * 设置图片展示控件 * * @param views 图片展示控件 */ public void setImageView(View... views)
/** * 设置展示广告时的Activity * * @param activity 广告时的Activity */ public void setActivity(Activity activity)}
xxxxxxxxxx/** * 原生混合广告的事件监听回调 */public interface NativeEventListener { /** * 广告展示回调 */ void onAdImpressed(NativeAdView adView);
/** * 广告点击回调 */ void onAdClicked(NativeAdView adView);
/** * 广告视频播放开始 */ void onAdVideoStart(NativeAdView adView);
/** * 用户点击关闭按钮,收到需调用方将广告View{@link NativeAdView}移除界面,部分广告联盟会自动移除广告View。 * 模板广告均支持此回调,穿山甲广告渲染时需绑定Activity后支持; * 自渲染广告仅穿山甲、京准通绑定closeView后,支持此回调。 */ void onAdClose(NativeAdView adView);
/** * 广告视频播放开始 */ void onAdVideoEnd(NativeAdView adView);
/** * 广告视频播放进度,仅部分广告联盟支持 */ void onAdVideoProgress(NativeAdView adView, long progress);
/** * 广告渲染异常或视频播放异常 */ void onAdFailed(NativeAdView adView, YdError error);}
xxxxxxxxxx/** * 原生混合广告的素材对象 */public interface NativeMaterial {
/** * 获取素材类型: * {@link NativeAdConst#AD_TYPE_UNKNOWN}:未知类型; * {@link NativeAdConst#AD_TYPE_SINGLE_IMG}:单图; * {@link NativeAdConst#AD_TYPE_GROUP_IMG}:组图; * {@link NativeAdConst#AD_TYPE_VIDEO}:视频。 * * @return 素材类型 */ int getAdType();
/** * 获取主图,可能为null,仅部分广告联盟有值。 * * @return 图片的URL地址 */ String getMainImageUrl();
/** * 获取图片列表,部分广告联盟可能返回null或空列表。 * * @return 图片的URL地址List */ List<String> getImageUrlList();
/** * 获取广告标题 * * @return 广告标题 */ String getTitle();
/** * 获取广告描述 * * @return 广告描述 */ String getDescription(); /** * 获取广告的创意文案,部分广告联盟可能返回null。 * * @return 返回创意文案 */ String getCallToAction();
/** * 获取广告的ICON图标URL地址,部分广告联盟可能返回null。 * * @return 广告的ICON图标URL地址 */ String getIconUrl();
/** * 获取广告的MediaView * * @return 自渲染广告返回视频的View,模板广告返回广告的View */ View getAdMediaView();
/** * 获取视频的URL地址,请优先使用{@link #getAdMediaView()}展示视频 * * @return 视频的URL地址 */ String getVideoUrl();
/** * 已过时 * 获取广告标示,可能为null,仅部分广告联盟有值 * * @return 广告标示的Bitmap对象 */ Bitmap getAdLogo();
/** * 获取广告标示,标识中不带广告二字,可能为null,仅部分广告联盟有值 * 预先判断此方法,如果此方法没有返回再通过getAdLogoUrl获取 * * @return 广告标示的Bitmap对象 */ Bitmap getAdLogoBitmap();
/** * 获取广告标示,可能为null,仅部分广告联盟有值 * * @return 广告标示的URL地址 */ String getAdLogoUrl();
/** * 返回视频时长,不支持获取视频时长的广告联盟返回0。 * * @return 视频时长 */ double getVideoDuration();
/** * 返回合规六要素。 * * @return 应用信息对象 */ NativeAdAppInfo getAdAppInfo();}xxxxxxxxxx/** * 合规六要素对象 */public interface NativeAdAppInfo { /** * @return 应用名称 */ String getAppName();
/** * @return 开发者公司名称 */ String getPublisher();
/** * @return 应用版本号 */ String getAppVersion();
/** * @return 隐私协议url */ String getAppPrivacyUrl();
/** * @return 权限列表url */ String getAppPermissionUrl();
/** * @return 产品功能url */ String getFunctionUrl();
/** * @return 权限列表点击 */ ClickEvent getPermissonClick();
/** * @return 隐私点击 */ ClickEvent getPrivacyClick();
/** * @return 功能页面点击 */ ClickEvent getFunctionClick();
interface ClickEvent { void onClick(); }}
xxxxxxxxxx// 1. 构造请求参数int width = DeviceUtil.px2dip(container.getWidth());int imageW = DeviceUtil.dip2px(240);int imageH = DeviceUtil.dip2px(130);
AdParams params = new AdParams.Builder(BuildConfig.MixNative) // 期望模板宽高,优量汇、穿山甲、京准通、OPPO、Vivo等广告联盟需要 // 优量汇可配置为宽度适配父控件宽度,优量汇、穿山甲、Vivo支持高度自适应 .setExpressHeight(100) // 期望模板高度 .setExpressWidth(width) // 期望模板宽度 .setExpressAutoHeight() // 模板高度自适应,优量汇、穿山甲、Vivo支持 .setExpressFullWidth() // 模板宽度适配父控件宽度,优量汇支持 // 自渲染广告期望的图片素材宽高,穿山甲,京准通需要 .setImageAcceptedHeight(imageH) .setImageAcceptedWidth(imageW) .build();// 2. 发起请求YdSDK.loadMixNative(this, params, new NativeLoadListener() { public void onNativeAdLoaded(NativeAd nativeAd) { // 3. 渲染请求成功广告 inflateAd(nativeAd); } public void onAdFailed(YdError error) { // 4. 请求失败处理 String msg = String.format(Locale.getDefault(), "onAdFailed, code:%d,msg:%s", error.getCode(), error.getMsg()); Toast.makeText(MixNativeActivity.this, msg, Toast.LENGTH_LONG).show(); }});
// 渲染广告private void inflateAd(NativeAd nativeAd) { setNativeEvent(nativeAd); FrameLayout container = findViewById(R.id.container_ad); container.removeAllViews(); // 构造NativeAdViewd对象,广告View均需在此ViewGroup中 NativeAdView nativeAdView = new NativeAdView(this); container.addView(nativeAdView, new FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT)); // 判断是否为模板广告 if (nativeAd.isNativeExpress()) { // 对于模板广告只需获取MediaView填充到广告容器中即可 View mediaView = nativeAd.getAdMaterial().getAdMediaView(); nativeAdView.addView(mediaView, new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT)); // 绑定模板广告容器,对于模板广告,第二参数selfRenderView可为null nativeAd.renderAdContainer(nativeAdView, null); NativePrepareInfo prepareInfo = new NativePrepareInfo(); // 渲染模板需绑定Activity prepareInfo.setActivity(this); // 渲染模板广告 nativeAd.prepare(prepareInfo); return; } // 以下为自渲染广告 // 媒体自定义的广告View View adView = View.inflate(this, R.layout.ad, null); nativeAdView.addView(adView, new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT)); // 绑定广告容器,第一个参数NativeAdView必须为广告的父容器;第二参数为自定义的广告view,不可为空 nativeAd.renderAdContainer(nativeAdView, adView);
// 获取自定义广告的展示控件 ImageView ivLogo = adView.findViewById(R.id.img_logo); TextView tvTitle = adView.findViewById(R.id.text_name); TextView tvDesc = adView.findViewById(R.id.text_desc); ImageView pic = adView.findViewById(R.id.img_poster); TextView btnOperate = adView.findViewById(R.id.btn_text); FrameLayout flMediaView = adView.findViewById(R.id.fl_mediaview); // 获取广告素材,并填充广告素材 NativeMaterial nativeMaterial = nativeAd.getAdMaterial(); tvTitle.setText(nativeMaterial.getTitle()); tvDesc.setText(nativeMaterial.getDescription()); if (!TextUtils.isEmpty(nativeMaterial.getIconUrl())) { Glide.with(getApplicationContext()).load(nativeMaterial.getIconUrl()).into(ivLogo); } // 判断广告素材类型,对于视频广告需获取MediaView填充 if (nativeMaterial.getAdType() == AD_TYPE_VIDEO && nativeMaterial.getAdMediaView() != null) { pic.setVisibility(View.GONE); flMediaView.addView(nativeMaterial.getAdMediaView(), new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT)); } else { flMediaView.setVisibility(View.GONE); if (!TextUtils.isEmpty(nativeMaterial.getMainImageUrl())) { Glide.with(getApplicationContext()).load(nativeMaterial.getMainImageUrl()).into(pic); } else { String imgUrl = Check.findFirstNonNull(nativeMaterial.getImageUrlList()); if (!TextUtils.isEmpty(imgUrl)) { Glide.with(getApplicationContext()).load(imgUrl).into(pic); } } } if (nativeMaterial.getAdLogo() != null) { adLogo.setImageBitmap(nativeMaterial.getAdLogo()); } else if (!TextUtils.isEmpty(nativeMaterial.getAdLogoUrl())) { Glide.with(getApplicationContext()).load(nativeMaterial.getAdLogoUrl()).into(adLogo); } // 准备渲染广告时需要绑定的控件 NativePrepareInfo prepareInfo = new NativePrepareInfo(); prepareInfo.setActivity(this); prepareInfo.setCtaView(btnOperate); prepareInfo.setClickView(adView); prepareInfo.setImageView(pic); // 渲染广告 nativeAd.prepare(prepareInfo);}
private void setNativeEvent(NativeAd nativeAd) { // 设置广告事件监听 nativeAd.setNativeEventListener(new NativeEventListener() { public void onAdImpressed(NativeAdView adView) { // 广告展示成功 } public void onAdClicked(NativeAdView adView) { // 广告被点击 } /** * 用户点击关闭按钮,收到需调用方将广告View{@link NativeAdView}移除界面,部分广告联盟会自动移除广告View。 * 模板广告均支持此回调,穿山甲广告渲染时需绑定Activity后支持; * 自渲染广告仅穿山甲、京准通绑定closeView后,支持此回调。 */ public void onAdClose(NativeAdView adView) { // 广告被关闭, } public void onAdVideoStart(NativeAdView adView) { // 视频播放开始 } public void onAdVideoEnd(NativeAdView adView) { // 视频播放结束 } public void onAdVideoProgress(NativeAdView adView, long progress) { // 视频播放进度,仅部分广告联盟支持 } public void onAdFailed(NativeAdView adView, YdError error) { // 广告渲染异常 } });}
详细实现自定义Adapter的示例可查看Demo
开发者需要根据自身需求继承相应广告形式的类(参照下表)并重写所有抽象方法,在相应的方法中调用广告平台的API,并通过类成员变量mLoadListener回调加载的结果,通过类成员变量mImpressionEventListener回调广告展示、点击、关闭等事件结果
| 广告形式 | 类名 |
|---|---|
| 激励视频 | com.yd.saas.base.custom.rewardvideo.CustomRewardVideoAdapter |
| 插屏广告 | com.yd.saas.base.custom.Interstitial.CustomInterstitialAdapter |
| 全屏视频 | com.yd.saas.base.custom.fullvideo.CustomFullVideoAdapter |
| 横幅广告 | com.yd.saas.base.custom.banner.CustomBannerAdapter |
| 原生模板 | com.yd.saas.base.custom.template.CustomTemplateAdapter |
| 原生自渲染 | com.yd.saas.base.custom.nativead.CustomNativeAdapter |
| 开屏广告 | com.yd.saas.base.custom.spread.CustomSpreadAdapter |
开发者只需要继承相关类并重写相关方法,自定义Adapter中的所有方法都不需要开发者进行调用,当Funlink后台的广告位下配置好自定义广告平台的广告源后,SDK内部会在合适的时机调用自定义Adapter中的相关方法。
开发者调用Funlink SDK的load API加载广告,Funlink SDK会根据后台配置的类名通过反射创建出自定义Adapter的类,并调用loadCustomNetworkAd()进行广告的请求,自定义广告平台的广告加载结果需要通过调用CustomLoadListener的方法通知Funlink SDK,最终Funlink SDK会通过Funlink的回调方法通知开发者
自定义广告平台加载广告时所需要的参数(AppID、AppKey、PlacementID等)需以Json字符串的形式配置在Funlink后台的该广告平台的广告源中,例如:
xxxxxxxxxx{"appId":"xxxxx","placeId":"xxxxxxxxx"}
Funlink SDK拉取到后台策略时,会将此Json字符串转化为Map,传给loadCustomNetworkAd(Context context, Map<String, Object> serverExtra, Map<String, Object> localExtra)方法,开发者可通过serverExtra参数获取到相关参数(AppID、AppKey、PlacementID等)
开发者调用Funlink SDK的isAdReady API时,会调用到自定义Adapter的isAdReady()方法
开发者调用Funlink SDK的show API时,会调用到自定义Adapter的show()方法
Funlink后台添加自定义广告平台时,Adapter类名需配置全路径类名(包名+类名),否则加载广告时Adapter类将不能正常被创建
因为SDK内部是通过反射new出Adapter的类,所以在构建release包时,必须确保Adapter类不能被混淆。混淆规则示例如下:
xxxxxxxxxx# 将 <Adapter类名> 改为开发者自己的Adapter类名-keep class <Adapter类名> { *;}-keepclassmembers public class <Adapter类名> {public *;}
2.6.4以上版本支持广告预加载功能。提升广告响应速度。
使用方法:需要在主activity页面,调用相应方法,对广告进行预加载。
xxxxxxxxxxYdConfig.getInstance().setActivityAndPreloadAd(this);
以下是所有的混淆规则,但需要根据实际所依赖的aar进行选择配置:
xxxxxxxxxx-keep class com.fl.** {*;}
在调用SDK初始化方法 YdConfig.getInstance().init()前务必先调用YdSDK.setInternationalLocale()方法设置运行环境。
xxxxxxxxxx// 配置国际化运行环境,务必最先调用YdSDK.setInternationalLocale();// SDK 初始化在后YdConfig.getInstance().init()接入方需自行判断用户是否在欧盟地区或是否需要设置GDPR。SDK提供两种方式配置GDPR:
xxxxxxxxxx// GDPR等级YdGDPRAuth.GDPR_UNKNOWN; // 未知等级YdGDPRAuth.GDPR_AGREE; // 已授权上报设备信息YdGDPRAuth.GDPR_REFUSE; // 拒绝上报设备信息
// 方式1,在需要设置GDPR等级时,通过YdSDK.getGDPRLevel()方法获取SDK记录的等级,// 当为GDPR_UNKNOWN等级时,应展示授权页设置页,并通过YdSDK.setGDPRLevel()方法设置授权结果
// 获取SDK记录的GDPR等级YdSDK.getGDPRLevel();// 直接设置GDPR等级YdSDK.setGDPRLevel();
// 方式2,是否需要展示授权页同方式1,当需要展示授权页时通过调用YdSDK.showGdprAuth()方法打开授权页,// 结果通过YdGDPRAuth.AuthReslut回调给接入方。YdSDK.showGdprAuth(Activity, YdGDPRAuth.AuthReslut{ // 用户授权结果 void onAuthFinish(int reslut); // 授权页加载失败 void onPageLoadFail();});(特别说明:原生样式中包含有模版和自渲染两种渲染类型,确定好您是按照哪种方式来对接的,在我们平台创建原生混合广告位时后面备注好是自渲染还是模版,然后联系我们配置成对应的形式。否则我们平台默认返回的都是自渲染类型。)
Topon自定义广告接入地址:https://docs.toponad.com/#/zh-cn/android/NetworkAccess/customnetwork/customnetwork
自定义广告源adapter参数
| 广告类型 | 广告类名称 | 服务端配置参数 |
|---|---|---|
| 激励视频 | com.fl.saas.s2s.topon.FLTopOnRewardVideoAdapter | {"app_id":"应用id","slot_id":"广告位id"} |
| 插屏 | com.fl.saas.s2s.topon.FLTopOnInterstitialAdapter | {"app_id":"应用id","slot_id":"广告位id"} |
| 横幅 | com.fl.saas.s2s.topon.FLTopOnBannerAdapter | {"app_id":"应用id","slot_id":"广告位id"} |
| 原生 | com.fl.saas.s2s.topon.FLTopOnNativeAdapter | {"app_id":"应用id","slot_id":"广告位id"} |
| 开屏 | com.fl.saas.s2s.topon.FLTopOnSplashAdapter | {"app_id":"应用id","slot_id":"广告位id"} |
(特别说明:原生样式中包含有模版和自渲染两种渲染类型,确定好您是按照哪种方式来对接的,在我们平台创建原生混合广告位时后面备注好是自渲染还是模版,然后联系我们配置成对应的形式。否则我们平台默认返回的都是自渲染类型。)
自定义广告源adapter参数:
应用维度参数:appId=应用ID(特别注意I为大写)
自定义配置信息:{"placementId":"广告位id"}
| 广告类型 | 广告类全路径 |
|---|---|
| 初始化类 | com.fl.saas.s2s.tobid.FLToBidCustomerProxy |
| 激励视频 | com.fl.saas.s2s.tobid.FLToBidVideoAdapter |
| 插屏 | com.fl.saas.s2s.tobid.FLToBidInterstitialAdapter |
| 横幅 | com.fl.saas.s2s.tobid.FLToBidBannerAdapter |
| 原生 | com.flsaas.s2s.tobid.FLToBidNativeAdapter |
| 开屏 | com.fl.saas.s2s.tobid.FLToBidSplashAdapter |
(特别说明:原生样式中包含有模版和自渲染两种渲染类型,确定好您是按照哪种方式来对接的,在我们平台创建原生混合广告位时后面备注好是自渲染还是模版,然后联系我们配置成对应的形式。否则我们平台默认返回的都是自渲染类型。)
自定义广告源adapter参数:
| 广告类型 | 广告类全路径 |
|---|---|
| 初始化类 | com.fl.saas.s2s.gromore.FLGromoreCustomInit |
| 激励视频 | com.fl.saas.s2s.gromore.FLGromoreRewardVideoLoader |
| 全屏视频 | com.fl.saas.s2s.gromore.FLGromoreFullVideoLoader |
| 插屏 | com.fl.saas.s2s.gromore.FLGromoreInterstitialLoader |
| Banner | com.fl.saas.s2s.gromore.FLGromoreBannerLoader |
| 原生 | com.fl.saas.s2s.gromore.FLGromoreNativeLoader |
| 开屏 | com.fl.saas.s2s.gromore.FLGromoreSplashLoader |
YdSpread,YdInterstitial,YdBanner,YdVideo,YdFullVideo,NativeAd 调用biddingResultUpload(boolean isWinner, int price, int secondPrice)方法回传竞价结果
YdSpread,YdInterstitial,YdBanner,YdVideo,YdFullVideo,NativeAd通过getECPM方法可以获取,单位为分。
| 错误码 | 说明 |
|---|---|
| 20400 | 获取广告配置异常,请检查广告位ID是否正确,广告位中是否正确配置了广告 |
| 20401 | 广告没有填充,请检查广告位中是否正确配置了广告,或者换台测试设备进行测试 |
| 20402 | 没有初始化SDK,请先初始化SDK再请求广告 |
| 20403 | 网络请求异常,请假查设备网络连接 |
| 20404 | context传入异常,检查请求展示广告传入的context是否正常 |
| 20405 | 素材渲染失败 |
| 20406 | 请求过于频繁,请检查广告位是否配置了频率控制并达到了展示上限 |
| 20407 | 展示广告异常 |
| 20408 | 请求超时 |
| 20409 | 开屏容器为null,请传入正确的开屏广告容器 |
| 20410 | 内部错误,请打印日志联系官方工作人员查看处理 |
| 20411 | 广告位id异常,请检查广告位ID中快手广告是否正确配置 |
xxxxxxxxxxYdConfig.getInstance().setPersonalizedState(false);//是否支持个性化广告YdConfig.getInstance().setEnableCollectAppInstallStatus(false);//是否允许获取应用安装列表YdConfig.getInstance().init(this, BuildConfig.APIKey, "", new YdParamConfig.Builder() .setCanUseAndroid(false)//是否允许获取AndroidId .setCustomAndroidId("测试自定义androidID") .setCanUseMac(false)//是否允许获取Mac地址 .setCustomMac("测试自定义mac") .setCanUseIMEI(false)//是否允许获取IMEI .setCustomIMEI("测试自定义imei") .setCanUseIMSI(false)//是否允许获取IMSI .setCanUseBootID(false)//是否允许获取BootID .setCanUseLocation(false)//是否允许获取Location .setCanUseUserAgent(false)//是否允许获取UserAgent .setCanUseSensor(false)//是否允许使用传感器 .build(), true);//YdParamConfig中各项设置参数true为允许获取,false为不获取demo仅供参考,具体以文档为准。如有疑问,请联系开发人员,谢谢~
| 文档版本 | 修订日期 | 修订说明 |
|---|---|---|
| v2.7.9 | 2024-09-28 | 更新双十一SDK |
| v2.7.8 | 2024-06-28 | 优化信息流 |
| v2.7.7 | 2024-04-19 | 优化激励视频广告转化,适配iOS17隐私设置 |
| v2.7.6 | 2024-02-23 | 优化广告链路,修复已知问题 |
| v2.7.5 | 2023-12-22 | 优化广告交互显示 |
| v2.7.4 | 2023-11-23 | 新增素材监测,新增全自动开屏对接 |
| v2.7.3 | 2023-10-17 | 穿山甲 SDK 使用二合一版本 |
| v2.7.2 | 2023-08-04 | SDK后缀更改为 .xcframework,支持了x86_64模拟器架构 |
| v2.7.1 | 2023-07-18 | 修复已知问题,新增原生混合广告 |
| v2.7.0 | 2023-05-23 | 针对618优化 |
| ...... | ...... | ...... |
使用本SDK前必须满足以下条件。具体详情请联系官方指定负责人或到指定平台申请!
目前聚合广告SDK需要的参数为APPID和各广告位对应ID,请在官方指定平台申请或联系具体负责人!
| 广告联盟 | 开屏广告 | 原生广告 | 模板广告 | 横幅广告 | 插屏广告 | 全屏视频广告 | 激励视频广告 |
|---|---|---|---|---|---|---|---|
| 穿山甲 | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
| 优量汇 | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
| 快手 | ✔️ | ✔️ | ✔️ | ❌ | ✔️ | ✔️ | ✔️ |
| 京准通 | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ❌ | ❌ |
| 百度联盟 | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
| Sigmob | ✔️ | ✔️ | - | ❌ | ✔️ | ✔️ | ✔️ |
| Mintegral | ✔️ | ✔️ | - | ❌ | ✔️ | ✔️ | ✔️ |
| Tanx | ✔️ | ✔️ | ✔️ | ❌ | ✔️ | ❌ | ✔️ |
| 广告联盟 | 开屏广告 | 原生广告 | 横幅广告 | 插屏广告 | 激励视频广告 |
|---|---|---|---|---|---|
| Pangle | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
| Mintegral | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
| Admob | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
| Meta | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
| UnityAD | ❌ | ❌ | ✔️ | ✔️ | ✔️ |
| VungleAD | ✔️ | ❌ | ✔️ | ✔️ | ✔️ |
| Applovin | ✔️ | ❌ | ✔️ | ✔️ | ✔️ |
| Ironsource | ❌ | ❌ | ✔️ | ✔️ | ✔️ |
| Inmobi | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
| Bigo | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
接入方需事先在各三方SDK平台申请相关广告参数,然后在聚合平台进行配置。在聚合平台配置之后,才能正常使用本SDK的聚合功能。
| 接入模块 | 包体影响(M) |
|---|---|
| FLAdSaas.framework | 0.4 |
聚合SDK依赖于被聚合的三方SDK,故在接入本SDK之前请确保项目已经接入了参与聚合的第三方广告联盟SDK。
| 三方联盟SDK | 需要导入的联盟包 | 需要导入的广告桥接包 |
|---|---|---|
| 穿山甲 | BUAdSDK.xcframework BURelyFoundation.xcframework CSJAdSDK.bundle | FLAdPangolinAdapter.xcframework |
| 优量汇 | libGDTMobSDK.a | FLAdGdtAdapter.xcframework |
| 快手 | KSAdSDK.xcframework | FLAdKsAdapter.xcframework |
| 京准通 | JADYun.framework | FLAdJztAdapter.xcframework |
| 百度联盟 | BaiduMobAdSDK.framework baidumobadsdk.bundle | FLAdBaiduAdapter.xcframework |
| Sigmob | WindFoundation.xcframework WindSDK.xcframework | FLAdSigmobAdapter.xcframework |
| Mintegral | MTGSDK.xcframework MTGSDKBanner.xcframework MTGSDKBidding.xcframework MTGSDKInterstitial.xcframework MTGSDKInterstitialVideo.xcframework MTGSDKNativeAdvanced.xcframework MTGSDKNewInterstitial.xcframework MTGSDKReward.xcframework MTGSDKSplash.xcframework | FLAdMtgAdapter.xcframework |
| Tanx | TNXASDK.framework TanxSDK.framework TanxID.bundle | FLAdTbAdapter.xcframework |
| 三方联盟SDK | 需要导入的联盟包 | 需要导入的广告桥接包 |
|---|---|---|
| Pangle | PAGAdSDK.bundle BURelyFoundation_Global.xcframework PAGAdSDK.xcframework BURelyAdSDK.xcframework | FLAdPangleAdapter.xcframework |
| Meta | FBAudienceNetwork.xcframework | FLAdMetaAdapter.xcframework |
| Unity | UnityAds.xcframework | FLAdUnityAdapter.xcframework |
| Vungle | VungleSDK.xcframework | FLAdVungleAdapter.xcframework |
| AdMob | nanopb.xcframework GoogleAppMeasurementIdentitySupport.xcframework UserMessagingPlatform.xcframework GoogleMobileAds.xcframework FBLPromises.xcframework GoogleAppMeasurement.xcframework GoogleUtilities.xcframework | FLAdMobAdapter.xcframework |
| Mintegral | MTGSDKBanner.xcframework MTGSDKBidding.xcframework MTGSDKInterstitial.xcframework MTGSDKInterstitialVideo.xcframework MTGSDKNativeAdvanced.xcframework MTGSDK.xcframework MTGSDKNewInterstitial.xcframework MTGSDKReward.xcframework MTGSDKSplash.xcframework | FLAdMtgAdapter.xcframework |
| Applovin | AppLovinSDK.xcframework AppLovinSDKResources.bundle | FLAdApplovinAdapter.xcframework |
| Ironsource | IronSource.xcframework | FLAdIronsourceAdapter.xcframework |
| Inmobi | InMobiSDK.xcframework | FLAdInmobiAdapter.xcframework |
| Bigo | BigoADS.xcframework OMSDK_Bigosg.xcframework BigoADSRes.bundle | FLAdBigoAdapter.xcframework |
开发者需在平台创建应用和广告位,生成对应的应用ID和广告位ID。
xxxxxxxxxx# FLAD主包pod 'FLAD/FLAdSaas'# Adapter插件,根据实际按需拖入:# 国内广告主# 穿山甲广告主适配包pod 'FLAD/FLAdCsjAdapter'# 广点通广告主适配包pod 'FLAD/FLAdGdtAdapter'# 快手广告主适配包pod 'FLAD/FLAdKsAdapter'# 京准通广告主适配包pod 'FLAD/FLAdJztAdapter'# 百度广告主适配包pod 'FLAD/FLAdBaiduAdapter'# 倍孜广告主适配包pod 'FLAD/FLAdBeiziAdapter'# Sigmob 广告主适配包pod 'FLAD/FLAdSigmobAdapter'# Tanx 广告主适配包pod 'FLAD/FLAdTbAdapter'# 海外广告主# Mintegral 广告主适配包pod 'FLAD/FLAdMtgAdapter'# AdMob 广告主适配包pod 'FLAD/FLAdMobAdapter'# Vungle 广告主适配包pod 'FLAD/FLAdVungleAdapter'# Unity 广告主适配包pod 'FLAD/FLAdUnityAdapter'# Meta 广告主适配包pod 'FLAD/FLAdMetaAdapter'# Pangle 广告主适配包pod 'FLAD/FLAdPangleAdapter'# Applovin 广告主适配包pod 'FLAD/FLAdApplovinAdapter'# Ironsource 广告主适配包pod 'FLAD/FLAdIronsourceAdapter'# Inmobi 广告主适配包pod 'FLAD/FLAdInmobiAdapter'# Bigo 广告主适配包pod 'FLAD/FLAdBigoAdapter'
获取相应版本的framework库,导入项目工程即可。
聚合SDK的framework库结构如下:
聚合SDK:
Adapter插件,根据实际按需拖入:
拖入时请按以下方式选择:

注意要添加的系统库
添加 App Transport Security Settings,先点击左侧展开箭头,再点右侧加号,Allow Arbitrary Loads 选项自动加入,修改值为 YES。 SDK API 已经全部支持HTTPS,但是广告主素材存在非HTTPS情况。
xxxxxxxxxx<key>NSAppTransportSecurity</key> <dict> <key>NSAllowsArbitraryLoads</key> <true/> </dict>具体操作如图:

具体操作如图:

引入快手SDK编译崩溃怎么办?

您遇到这个崩溃是因为快手sdk为动态库,需要将KSAdSDK.xcframework的Embed修改为Embed&Sign即可


在修改完Embed之后,若是编译还是报错,如下:

解决方法:Build Settings中的Validate Workspace修改为 YES
京准通SDK为Swift和OC混编,所以集成时需要配置混编环境!
SDK中包含获取IDFA的权限,所以需要在info.plist中添加IDFA权限,如图所示:
xxxxxxxxxx<key>NSUserTrackingUsageDescription</key><string>该标识符将用于向您投放个性化广告</string>
SKAdNetwork 的正确运行(可自行添加对应联盟SDK的SKAdNetwork),如图所示:xxxxxxxxxx<key>SKAdNetworkItems</key> <array> <dict> <key>SKAdNetworkIdentifier</key> // SKAdNetwork方案的穿山甲SKAdNetwork id <string>238da6jt44.skadnetwork</string> </dict> <dict> <key>SKAdNetworkIdentifier</key> // SKAdNetwork方案的穿山甲SKAdNetwork id <string>x2jnk7ly8j.skadnetwork</string> </dict> <dict> <key>SKAdNetworkIdentifier</key> // SKAdNetwork方案的穿山甲SKAdNetwork id <string>22mmun2rn5.skadnetwork</string> </dict> <dict> <key>SKAdNetworkIdentifier</key> // SKAdNetwork方案的优量汇SKAdNetwork id <string>f7s53z58qe.skadnetwork</string> </dict> <dict> <key>SKAdNetworkIdentifier</key> <string>r3y5dwb26t.skadnetwork</string> </dict> </array>
使用SKAdNetwork跟踪转化
使用Apple的转化跟踪SKAdNetwork,这意味着即使IDFA不可用,广告平台也可以通过这个获取应用安装归因。请参阅Apple的SKAdNetwork文档,以了解更多信息。
要启用此功能,您需要在info.plist中添加SKAdNetworkItems。开发者根据集成的情况,可分别添加对应平台的SKAdNetwork标识符。
【重要说明】 因三方广告平台的SKAdNetwork ID可能不定期更新,为尽可能降低收入损失风险,建议从下述链接处获取各平台最新的SKAdNetwork ID List。 同时,为方便开发者,在SDK下载页面提供了 SKAdNetwork IDs代码,可直接复制使用。
三方广告平台SKAdNetwork获取链接
【重要说明】UnityAds的SKAdNetwork ID每个项目均不相同,具体以UnityAds后台生成为准,位置参考

为了提高广告 ADX的收益效果,建议您复制以下代码到您App的info.plist文件:
xxxxxxxxxx<key>LSApplicationQueriesSchemes</key><array> <string>tbopen</string> <string>openapp.jdmobile</string> <string>imeituan</string> <string>pinduoduo</string> <string>youku</string> <string>iqiyi</string> <string>alipays</string> <string>vipshop</string> <string>tmall</string> <string>sinaweibo</string> <string>zhihu</string> <string>jdmobile</string> <string>autohome</string> <string>taobaolite</string> <string>taobaoliveshare</string> <string>eleme</string></array>以下依赖库已整合所有联盟广告主所需的依赖库
工程需要在TARGETS -> Build Phases中找到Link Binary With Libraries,点击“+”,依次添加下列依赖库
具体操作如图所示:

从iOS 14开始,只有在获得用户明确许可的前提下,应用才可以访问用户的IDFA数据并向用户投放定向广告。在应用程序调用 App Tracking Transparency 框架向最终用户提出应用程序跟踪授权请求之前,IDFA将不可用。如果某个应用未提出此请求,则读取到的IDFA将返回全为0的字符串。
以下提供中英文描述说明示例,开发者可参考添加其中一种即可:
xxxxxxxxxx<key>NSUserTrackingUsageDescription</key><string>该标识符将用于向您投放个性化广告。</string>

xxxxxxxxxx<key>NSUserTrackingUsageDescription</key><string>This identifier will be used to deliver personalized ads to you.</string>

想要获取授权,需要使用requestTrackingAuthorizationWithCompletionHandler:。我们建议您在初始化FLAD SDK之前获取授权,以便如果用户授予允许跟踪权限,FLAD SDK则可以在广告请求中使用IDFA。
xxxxxxxxxx#import <AppTrackingTransparency/AppTrackingTransparency.h>if (@available(iOS 14, *)) {//iOS 14[ATTrackingManager requestTrackingAuthorizationWithCompletionHandler:^(ATTrackingManagerAuthorizationStatus status) {//to do something,like preloading// load AD}];} else {// load AD}
描述说明将会显示在App Tracking Transparency授权对话框中,如下:

注意:
iOS 15对 AppTrackingTransparency 框架做了调整,需要满足以下 2 点:
当满足以上 2 点后,再检查 ATTrackingManagerAuthorizationStatus 和请求授权。因此,可以在以下的选项中选择一个作为调整方案:
参考链接:https://developer.apple.com/forums/thread/690607
集成Admob广告平台SDK,平台要求在xcode项目的Info.plist中添加 GADApplicationIdentifier 配置你们Admob的AppID,否则会crash。参考如下,请使用你们的Admob的identifier进行替换:
xxxxxxxxxx<key>GADApplicationIdentifier</key><string>ca-app-pub-9488501426181082~7319780494</string><key>GADIsAdManagerApp</key><true/>
因Meta平台的要求,测试Meta广告需要在测试手机中下载并登录Facebook客户端才能填充广告
目前个性化开关设置支持的广告平台如下: (1)国内:穿山甲,优量汇,快手,百度,Sigmob (2)海外:Meta,Admob,Mintegral,Pangle,UnityAds,Vungle
默认情况是全部开启广告个性化推荐,如果手动设置关闭之后则全部广告平台关闭个性化推荐。 针对海外平台,如果关闭个性化推荐,涉及用户隐私的数据将不会被收集,可能会影响广告平台功能的正常使用,请谨慎设置。
xxxxxxxxxx/// 个性化推荐广告设置 YES:关闭个性化推荐 NO:打开个性化推荐 默认为NO[FLAdSDKManager setPersonalizedState:NO];
建议开发者的集成流程如下
1、 APP启动后,开发者判断用户是否在欧盟(开发者自行实现是否在欧盟的判断方法)
2、判断[FLAdSDKManager defaultManager]的dataConsentSet是否为FLGDPRConsentSetUnknown
3、调用[FLAdSDKManager defaultManager]的presentDataConsentDialogInViewController:dismissalCallback方法(由用户设置GDPR等级)
使用以下代码段设置GDPR:
xxxxxxxxxxif ([FLAdSDKManager defaultManager].dataConsentSet == FLGDPRConsentSetUnknown) {[[FLAdSDKManager defaultManager] presentDataConsentDialogInViewController:self dismissalCallback:^(FLGDPRConsentSet dataConsentSet) {// 请求广告}];}
展示如图:

4、初始化SDK
重要提示:
如果你的应用同时获取了App Tracking Transparency授权弹窗,我们强烈建议参考如下图所示流程来获取App Tracking Transparency授权弹窗与GDPR弹窗,否则有提审被拒的风险!

SDK的开屏广告建议在 AppDelegate 的方法 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 里
当window指定root控制器并显示之后最先进行初始化
xxxxxxxxxx// 国内环境初始化设置[FLAdSDKManager registerAppId:@"从后台获取的应用ID"];// 海外环境初始化设置[FLAdSDKManager registerAppId:@"从后台获取的应用ID" Environment:FLADEnvironmentOther];
在 AppDelegate 的方法 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 里,当window指定rootViewController之后可直接调用:
xxxxxxxxxx[self.window fl_showSplashADWithConfig:^(FLSplashADConfig * _Nonnull config) {UIImage *splashBg = [UIImage imageNamed:@"splashBg"];config.mediaID = splash_id;config.backgroundImage = splashBg;config.backgroundColor = [UIColor whiteColor];config.contentMode = UIViewContentModeScaleAspectFit;config.timeout = 8.0;config.bottomView = [[UIImageView alloc] initWithImage:splashBg];} completion:^(FLSplashADType type, NSError *error) {switch (type) {case FLSplashADTypeStart:NSLog(@"Block方式:开屏广告请求流程开启");break;case FLSplashADTypeRequestAD:NSLog(@"Block方式:开始请求广告");break;case FLSplashADTypeLoadAD:NSLog(@"Block方式:广告加载成功");break;case FLSplashADTypeFail:NSLog(@"Block方式:广告加载失败");break;case FLSplashADTypeShow:NSLog(@"Block方式:广告展示");break;case FLSplashADTypeClick:NSLog(@"Block方式:广告点击");break;case FLSplashADTypeClose:NSLog(@"Block方式:广告关闭");break;default:break;}}];
xxxxxxxxxxxxxxxxxxxx<FLSplashDelegate>xxxxxxxxxx_manager = [FLSplashManager new];_manager.delegate = self;_manager.mediaId = @"获取的广告位";_manager.showAdController = self.window.rootViewController;[_manager loadAdData];xxxxxxxxxx//bottom 为含logo的viewUILabel *bottom = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height * 0.2)];bottom.text = @"AD Demo";bottom.textAlignment = NSTextAlignmentCenter;bottom.font = [UIFont systemFontOfSize:35];bottom.userInteractionEnabled = YES;bottom.backgroundColor = [UIColor whiteColor];
_manager = [FLSplashManager new];_manager.delegate = self;_manager.mediaId = @"获取的广告位";_manager.bottomView = bottom;_manager.showAdController = self.window.rootViewController;[_manager loadAdData];xxxxxxxxxx/** * 广告数据:加载成功 */- (void)splashAdDidLoad;/** * 广告数据:加载失败 * @param error : 错误信息 */- (void)splashAdDidFailed:(NSError *)error;/** * 广告成功展示 */- (void)splashAdDidVisible;/** * 广告视图:点击 * @param urlStr 媒体自定义广告时,返回的落地页链接 */- (void)splashAdDidClickedWithUrlStr:(NSString *_Nullable)urlStr;/** * 落地页或者appstoe返回事件 */-(void)splashAdDidCloseOtherController;/** * 广告视图:关闭 */- (void)splashAdDidShowFinish;/** * 广告成功渲染 */- (void)splashAdDidRender;xxxxxxxxxx[self.manager showSplashAdWithWindow:[UIApplication sharedApplication].keyWindow];
建议等待时间设置为5秒,展示时间设置为5秒。 App在从后台5分钟后到前台时 建议也加上开屏广告。
xxxxxxxxxxxxxxxxxxxx<FLInterstitialDelegate>xxxxxxxxxxself.interstitialAd = [FLInterstitialManager new];self.interstitialAd.mediaId = @"获取的广告位";self.interstitialAd.showAdController = self;self.interstitialAd.delegate = self;[self.interstitialAd loadAdData];xxxxxxxxxx/** * 广告数据:加载成功 */- (void)interstitialAdDidLoad;/** * 广告数据:加载失败 * @param error : 错误信息 */- (void)interstitialAdDidFailed:(NSError *)error;/** * 广告视图:展示 */- (void)interstitialAdDidVisible;/** * 广告视图:点击 */- (void)interstitialAdDidClick;/** * 落地页或者appstoe返回事件 */- (void)interstitialAdDidCloseOtherController;/** * 广告视图:关闭 */- (void)interstitialAdDidClose;xxxxxxxxxx[self.interstitialAd showInterstitialAd];
xxxxxxxxxxxxxxxxxxxx<FLRewardVideoDelegate>xxxxxxxxxx@property (nonatomic, strong) FLRewardVideoManager *motivationVideo;xxxxxxxxxxself.motivationVideo = [FLRewardVideoManager new];self.motivationVideo.mediaId = @"获取的广告位";self.motivationVideo.delegate = self;[self.motivationVideo loadAdDataWithExtra:nil];xxxxxxxxxx/** * 激励视频广告-视频-加载成功 */- (void)rewardedVideoDidLoad;
/** * 激励视频广告素材加载失败 * @param error 错误对象 */- (void)rewardedVideoDidFailWithError:(NSError *)error;
/** * 激励视频广告成功展示 */- (void)rewardedVideoDidVisible;
/** * 激励视频广告点击 */- (void)rewardedVideoDidClick;
/** * 激励视频广告播放达到激励条件 * @param extra 额外参数,即初始化传入的extra */- (void)rewardedVideoDidRewardEffectiveWithExtra:(NSDictionary*)extra;
/** * 激励视频广告已经关闭 */- (void)rewardedVideoDidClose;xxxxxxxxxx[self.motivationVideo showRewardVideoAdWithController:self];
xxxxxxxxxxxxxxxxxxxx<FLBannerDelegate>xxxxxxxxxxself.banner = [FLBannerManager new];self.banner.size = self.bannerView.bounds.size;self.banner.delegate = self;self.banner.mediaId = @"获取的广告位";self.banner.showAdController = self;[self.banner loadAdData];xxxxxxxxxx/** * 广告数据:加载成功 */- (void)bannerAdDidLoad;/** * 广告数据:加载失败 * @param error : 错误信息 */- (void)bannerAdDidFailed:(NSError *)error;/** * 广告视图:展示 */- (void)bannerAdDidVisible;/** * 广告视图:点击 */- (void)bannerAdDidClick;/** * 落地页或者appstoe返回事件 */-(void)bannerAdDidCloseOtherController;/** * 广告视图:关闭 */- (void)bannerAdDidClose;xxxxxxxxxx[self.banner showBannerAdWithView:self.bannerView];
xxxxxxxxxxxxxxxxxxxx<FLNativeDelegate>xxxxxxxxxx@property (nonatomic, strong) FLNativeManager *nativeManager;xxxxxxxxxxFLNativeManager *manager = [[FLNativeManager alloc] init];manager.mediaId = @"获取的广告位";manager.adCount = 1;manager.size = CGSizeMake(FL_ScreenW, 0);manager.showAdController = self;manager.delegate = self;[manager loadAdData];self.nativeManager = manager;xxxxxxxxxx/** * 广告数据:加载成功 */- (void)nativeAdDidLoadDatas:(NSArray<__kindof FLFeedAdData *> *)datas;/** * 广告数据:加载失败 * @param error : 错误信息 */- (void)nativeAdDidFailed:(NSError *)error;/** * 广告视图:展示 */- (void)nativeAdDidVisible;/** * 广告视图:点击 */- (void)nativeAdDidClicked;/** * 落地页或者appstoe返回事件 */- (void)nativeAdDidCloseOtherController;/** * 视频广告播放状态更改回调 * @param status 视频广告播放状态 */- (void)nativeAdVideoPlayerStatusChanged:(FLMediaPlayerStatus)status;
//当为模板广告时有以下回调/** * 广告视图:渲染成功 */- (void)nativeAdDidRenderSuccessWithADView:(UIView *)nativeAdView;/** * 广告视图:关闭 */- (void)nativeAdDidCloseWithADView:(UIView *)nativeAdView;在加载成功的回调(- (void)nativeAdDidLoadDatas:(NSArray<__kindof FLFeedAdData *> *)datas;)中,判断是否是模板广告:
xxxxxxxxxxfor (FLFeedAdData *adData in datas) { if (adData.adView) { //模板广告 } else { //自渲染广告 }}
每类广告都包含如下两个方法,在FLAD作为竞价接入时,需上报:
/// ** 媒体竞价展示广告时需要上报,需要在调用广告 show 之前调用 **
/** * ======= 我方竞胜后需要回传第二价 ======= * @param secondPrice 媒体二价 (单位: 分) */
xxxxxxxxxx- (void)sendWinNotificationWithInfo:(CGFloat)secondPrice;
/** * ======= 我方竞败后需要回传最高价以及竞败原因 ======= * @param firstPrice 媒体一价 (单位: 分) * @param errorType 竞败原因:(1 输给Mediatom其它广告位, 2 输给第三方ADN, 3 输给自售广告主) */
xxxxxxxxxx- (void)sendLossNotificationWith:(CGFloat)firstPrice fail:(NSInteger)errorType;
SDK支持自定义适配器,可以自行创建对应广告类型的适配器,在服务端进行类名和参数的配置后,即可进行调用。
自定义一个类,使之继承自SDK的FLBaseManager类,具体可参考demo的CustomWMSplashManager类!
实现加载广告和展示广告的方法
xxxxxxxxxx// 必须实现请求广告的方法- (void)loadADWithModel:(FLConfigModelAd_Sources *)model{//model为服务器返回的配置的广告信息/*/// 自定义广告返回的参数,json格式 @property (nonatomic, copy) NSString *ext;//广告主key值@property (nonatomic, copy) NSString *app_key;//广告主应用ID@property (nonatomic, copy) NSString *app_id;//广告源广告位id@property (nonatomic, copy) NSString *tagid;*/ // 下面为示例的请求开屏的广告代码 [[XAdWangMaiSDk sharedInstance] initWithAppToken:dic[@"token"] appKey:dic[@"app_key"] appId:dic[@"app_id"] universalLink:dic[@"universal_link"]]; self.WMad = [[XAdSplashAd alloc] initWithAdSlotId:dic[@"place_id"]]; self.WMad.delegate = self; [self.WMad preloadAdData];}xxxxxxxxxx// 必须实现的开屏展示广告的方法- (void)showSplashAdInWindow:(UIWindow *)window withBottomView:(UIView *)bottomView{ [self.WMad showAdInWindow:window];}在自定义广告的回调里面,通过block回调传递函数信息,这样在FLSplashManager遵守代理的情况下,可收到广告的代理回调
xxxxxxxxxx// 以下为block回调的示例代码(其中type代表的函数名为://1:广告加载成功 2:广告加载失败 3:广告点击 4:从落地页返回 5:广告关闭 6:素材成功展示 7:激励视频获得奖励回调 8:素材渲染成功,这些函数不一定全部实现,具体以对应的广告类的代理方法为主)self.baseModel.type = blockType;if (self.successBlock) { self.successBlock(self.baseModel);}在对应的广告类请求广告时(如果是新的广告平台,在后台创建后,可以直接正常调用),如下所示:
xxxxxxxxxxFLSplashManager *manager = [FLSplashManager new];manager.delegate = self;manager.mediaId = splash_id;[manager loadAdData];self.manager = manager;此时,广告流程将走自定义广告请求类!Done!
下面是各种ErrorCode的值
| code | 说明 |
|---|---|
| 20400 | 请求广告配置为空 |
| 20401 | 解析的数据没有广告 |
| 20402 | 未注册APP ID,请在应用初始化时注册APP ID |
| 20403 | 请检查广告位ID |
| 20404 | 广告请求时间已超过平台配置时间 |
| 20405 | 广告配置请求错误,请联系广告运营人员查看广告配置 |
| 20406 | 素材渲染失败 |
| 20407 | 广告请求失败,可能原因是有广告未配置,配置的广告位ID与APPID不匹配,广告未填充,网络请求失败等原因之一,具体错误原因,请查看错误详情! |
| 20408 | 广告的主流程已结束 |
| 20409 | 此广告位设置了展示间隔限制,当前时间距离上次展示广告时间未达到配置的最低要求,请稍后再试 |
| 20410 | 此广告位设置了一小时内广告展示频次限制,当前小时内广告展示已达设置的最大频次,请稍后再试 |
| 20411 | 此广告位设置了一天内广告展示频次限制,今天广告展示已达设置的最大频次,请明天再试 |
| code | 说明 |
|---|---|
| 40001 | 没有网络 |
| 40002 | 数据解析失败 |
| 40003 | 广告数据为空 |
| 40004 | 缓存视频资源失 |
| 100001 | 参数有误 |
| 100002 | 服务器错误 |
| 100003 | 不允许的操作 |
| 100004 | 服务不可用 |
| 310001 | appId未注册 |
| 310002 | appId无效 |
| 310003 | appId已封禁 |
| 310004 | packageName与注册的packageName不一致 |
| 310005 | 操作系统与注册的不一致 |
| 320002 | appId对应账号无效 |
| 320003 | appId对应账号已封禁 |
| 330001 | posId未注册 |
| 330002 | posId无效 |
| 330003 | posId已封禁 |
| 330004 | posid与注册的appId信息不一致 |
| 错误码 | 解释 |
|---|---|
| 0 | 广告返回 |
| 0103010 | 应用ID信息缺失 |
| 0103011 | 应用ID信息错误,百度联盟(百青藤)未收录 |
| 0103012 | 应用ID信息无效,百度联盟(百青藤)上未生效 |
| 0103060 | 应用包名信息错误,请保证注册包名和实际请求包名一致 |
| 0107001 | 广告位ID未收录 |
| 0107002 | 广告位ID未启用 |
| 0107003 | 广告位ID与APPSID不匹配 |
| 1020001 | 网络连接失败 |
| 1040001 | 请求时使用了错误的参数,比如使用错误的广告位ID |
| 1040003 | 请求超时 |
| 3030002 | 缓存物料失败 |
| 3040001 | 广告展现标准不达标 |
xxxxxxxxxx答:接入SDK需要很多的配置工作,请按照文档说明配置齐全,保证没有遗漏!
xxxxxxxxxx答:联系广告运营获取。
xxxxxxxxxx答:广告收益一般在第二天会在后台系统显示,节假日顺延,如果还是没看到,请确保广告位是否使用正确,如果误用测试广告位,这个是没有广告收益的!
xxxxxxxxxx答:FLAD主包根据我们demo打包后的计算为0.7MB左右,其他广告主依赖包请参考联盟接入文档,具体大小会根据导入的功能有所差别,实际情况以集成后的包大小为主。