不限制
未配置、待确认或未获得检测结果时放行。
REMAX SDK · EXTERNAL INTEGRATION
面向宿主业务和外部检测 SDK:配置 Ad_Risk_Config、读取设备风险处置策略、限制广告平台,并接收广告收益与点击数据。
以下版本来自当前仓库的发布配置。Risk 不向宿主传递 Bill,外部业务应显式声明三项依赖,避免依赖解析结果不一致。
// app/build.gradle.kts
dependencies {
implementation("com.github.toukaremax:core:1.0.15")
implementation("com.github.toukaremax:bill:support_risk_1.0.9")
implementation("com.github.toukaremax:ad-risk:1.0.8")
}
远程配置逻辑 Key 固定为 Ad_Risk_Config。设备环境处置字段与行为风控字段放在同一份扁平 JSON 中。SDK 启动时先使用缓存、Assets 或硬编码默认值,再异步拉取远程配置;合法的远程配置会即时生效并写入缓存。
{
"behavior_mode": 2,
"mistake_click_time": 20,
"mistake_click_count": 2,
"restrict_interval": 1800,
"close_click_count": 3,
"close_activity_class_names": [],
"limits": {
"app_open": { "request_limit": 0, "show_limit": 0, "click_limit": 0, "fill_fail_limit": 0 },
"interstitial": { "request_limit": 0, "show_limit": 0, "click_limit": 0, "fill_fail_limit": 0 },
"native": { "request_limit": 0, "show_limit": 0, "click_limit": 0, "fill_fail_limit": 0 },
"banner": { "request_limit": 0, "show_limit": 0, "click_limit": 0, "fill_fail_limit": 0 },
"rewarded": { "request_limit": 0, "show_limit": 0, "click_limit": 0, "fill_fail_limit": 0 }
},
"vpn_ad_config": -1,
"dns_ad_config": -1,
"ip_ad_config": -1,
"simulator_ad_config": -1,
"adb_ad_config": -1,
"sim_ad_config": -1,
"no_gp_ad_config": -1,
"sys_9_low_ad_config": -1,
"play_ad_config": -1
}
| 字段 | 默认值 / 范围 | 含义 |
|---|---|---|
behavior_mode | 2;0、1、2 | 0 关闭:不计数、不限制、不强关;1 执行:计数、上报并真正应用冷却/强关;2 观察:计数和上报,但不限制、不强关。模式变化会清空行为风控状态。 |
mistake_click_time | 20 秒;整数 ≥ 0 | 点击广告后 App 进程进入后台并返回,耗时小于等于该值时判定为误触。值为 0 不是关闭开关。 |
mistake_click_count | 2;整数 ≥ 0 | 同一“广告类型 + position”的误触累计到第 N 次时触发;0 表示不触发限制,但仍可上报误触事件。 |
restrict_interval | 1800 秒;整数 ≥ 0 | 执行模式下命中阈值后的冷却时长;0 表示冷却立即结束。 |
close_click_count | 3;整数 ≥ 0 | 同一插页广告 session 第 N 次点击时触发;执行模式会强关及冷却,观察模式只计数和上报。仅插页生效,0 表示关闭强关。 |
close_activity_class_names | [];非空字符串数组 | 追加允许 SDK 内置关闭的 Activity 完整类名。命中后在主线程调用 finish();本地默认 AdMob Activity 始终保留。 |
behavior_mode 为 1 或 2。用户未点击广告而直接关闭时,不进入误触判断。
leave_time;若停留时长不超过 mistake_click_time,则判定并上报误触。leave_time=0 结算,并判定、上报误触。<type> 支持 app_open、interstitial、native、banner、rewarded。当前行为风控只处理 AdMob;同类型 position 共用阈值,但分别计数和冷却。
| 字段 | 默认值 | 触发规则 |
|---|---|---|
limits.<type>.request_limit | 0 | 最多允许 N 次业务请求,第 N+1 次触发;0 不限制。预加载不计入业务请求。 |
limits.<type>.show_limit | 0 | 最多允许 N 次实际曝光,第 N+1 次触发;0 不限制。 |
limits.<type>.click_limit | 0 | 最多允许 N 次点击,第 N+1 次触发;0 不限制。 |
limits.<type>.fill_fail_limit | 0 | 连续加载失败到第 N 次时触发,加载成功会清零;0 不限制,预加载结果也参与。 |
| JSON 字段 | AdRisk.signalConfig 属性 | 外部检测场景 |
|---|---|---|
vpn_ad_config | vpnAdConfig | 设备正在使用 VPN |
dns_ad_config | dnsAdConfig | 设备命中 DNS 代理风险 |
ip_ad_config | ipAdConfig | 设备命中异常 IP 风险 |
simulator_ad_config | simulatorAdConfig | 模拟器设备 |
adb_ad_config | adbAdConfig | 设备处于 ADB 调试状态 |
sim_ad_config | simAdConfig | 设备没有 SIM 卡 |
no_gp_ad_config | noGpAdConfig | 设备没有 Google Play |
sys_9_low_ad_config | sys9LowAdConfig | Android 9 以下设备 |
play_ad_config | playAdConfig | 外部 XM SDK 服务端核验结果 |
未配置、待确认或未获得检测结果时放行。
外部检测命中后禁用 AdMob,其他广告平台仍可承接。
外部检测命中后禁用 AdMob、GAM、Pangle 和 TopOn。
-1 / 0 / 1。远程 JSON 非法时不会部分应用,而是继续使用当前有效配置。import com.android.common.risk.AdRisk
import kotlinx.coroutines.flow.collectLatest
// 同步读取当前完整快照
val current = AdRisk.signalConfig.value
val vpnPolicy = current.vpnAdConfig
// 推荐:监听缓存、Assets 和在线配置的后续变化
applicationScope.launch {
AdRisk.signalConfig.collectLatest { config ->
val latestVpnPolicy = config.vpnAdConfig
// 保存最新值,或通知业务重新执行检测处置
}
}
signalConfig 是只读 StateFlow<AdRiskSignalConfig>。初始快照全部为 -1,随后应用缓存 / Assets,并可能被远程配置更新;需要跟随在线配置时不要只读取一次。外部检测确认设备正在使用 VPN 后,只需读取 vpnAdConfig 并按值处理:
import com.android.common.bill.ads.config.AdPlatform
import com.android.common.risk.AdRestrictionScope
import com.android.common.risk.AdRisk
import com.android.common.risk.AdRiskSignalConfig
if (vpnDetected) {
when (AdRisk.signalConfig.value.vpnAdConfig) {
AdRiskSignalConfig.BLOCK_ADMOB -> {
// 0:只禁用 AdMob
AdRisk.updatePlatformRestriction(
AdPlatform.ADMOB,
AdRestrictionScope.PROCESS,
true
)
}
AdRiskSignalConfig.BLOCK_ALL_ADS -> {
// 1:禁用全部广告平台
AdPlatform.entries.forEach { platform ->
AdRisk.updatePlatformRestriction(
platform,
AdRestrictionScope.PROCESS,
true
)
}
}
AdRiskSignalConfig.NOT_CONFIGURED -> Unit // -1:不处理
}
}
DNS、异常 IP、模拟器等检测的处理方式完全相同,只需把 vpnAdConfig 换成对应的配置字段。检测状态恢复正常后,用相同平台和 Scope 调用 restricted=false 解除本业务设置的限制;存在多项风险时,应在所有相关风险都解除后再清除。
| Scope | 保存方式 | 自动失效 | 主动清除 |
|---|---|---|---|
AdRestrictionScope.PROCESS | 仅内存 | 当前应用进程结束 | 同一平台和 Scope 再传 restricted=false |
AdRestrictionScope.TODAY | 本地持久化 | 设备本地自然日变化 | 同一平台和 Scope 再传 restricted=false |
PROCESS 与 TODAY 独立;只清除其中一个,另一个仍会继续限制。ADMOB、GAM、PANGLE、TOPON。updatePlatformRestriction 返回 false 表示 Risk 尚未完成自动初始化,本次没有应用;应稍后重试。behavior_mode、行为计数和广告位冷却相互独立。广告库通过 BillConfig 暴露两个可选回调,参数类型均为 RevenueAdData。建议在 Application.onCreate() 中完成赋值。
import com.android.common.bill.BillConfig
BillConfig.onAdRevenue = { data ->
// 每次广告展示产生收益时回调(impression 级)
analytics.logAdRevenue(
value = data.revenue.value,
currency = data.revenue.currencyCode,
platform = data.platform,
network = data.adRevenueNetwork,
adUnitId = data.adRevenueUnit,
adSourceId = data.adSourceId,
placement = data.adRevenuePlacement,
format = data.adFormat
)
}
BillConfig.onAdClick = { data ->
// 用户点击广告时回调
analytics.logAdClick(
platform = data.platform,
network = data.adRevenueNetwork,
adUnitId = data.adRevenueUnit,
adSourceId = data.adSourceId,
placement = data.adRevenuePlacement,
format = data.adFormat,
value = data.revenue.value,
currency = data.revenue.currencyCode
)
}
// 不再接收时可清除
// BillConfig.onAdRevenue = null
// BillConfig.onAdClick = null
| 字段 | 类型 | 含义 / 可能值 |
|---|---|---|
revenue.value | Double | 单次展示收益金额;点击回调携带当前广告已知的收益值,平台未提供时可能为 0。 |
revenue.currencyCode | String | 货币代码,通常为 USD;SDK 不做汇率换算,使用金额前应同时检查该字段。 |
platform | String | 聚合平台:Admob、GAM、Pangle、TopOn。 |
adRevenueNetwork | String | 实际广告网络 / 底层广告源名称;拿不到时回退为聚合平台名称。 |
adRevenueUnit | String | 本次请求使用的聚合广告位 ID(Ad Unit / Placement ID)。 |
adSourceId | String | 底层广告源或实例 ID;拿不到时回退为 adRevenueUnit。 |
adRevenuePlacement | String | 平台提供的 placement、scenario 或实例名称;平台未提供时可能为空字符串。 |
adFormat | String | Splash、Interstitial、Native、Banner、FullNative、Rewarded。 |
BillConfig.onAdRevenue 或 BillConfig.onAdClick 赋值会替换之前的回调。通过 AdSourceController.setCurrentSource(...) 设置 Bill 当前使用的聚合平台。建议在 Application.onCreate() 中、首次广告请求之前完成设置。
import com.android.common.bill.ads.bidding.AdSourceController
import com.android.common.bill.ads.bidding.AdSourceController.AdSource
// 固定使用 AdMob;也可改为 GAM、PANGLE 或 TOPON
AdSourceController.setCurrentSource(AdSource.ADMOB)
// 读取当前设置
val currentSource = AdSourceController.getCurrentSource()
// BIDDING 为默认模式:由 Bill 在所有可用平台中竞价选择
AdSourceController.setCurrentSource(AdSource.BIDDING)
| AdSource | 行为 |
|---|---|
ADMOB | 固定使用 AdMob |
GAM | 固定使用 Google Ad Manager |
PANGLE | 固定使用 Pangle |
TOPON | 固定使用 TopOn |
BIDDING | 恢复默认竞价模式,由可用平台参与选择 |
AdSource.BIDDING。