菜单

广告素材探测-Android 接入说明

  • 本文档面向接入广告SDK 的开发者,说明如何在开屏/横幅/原生(有容器)插屏/激励视频(无容器) 两种场景下,在展示回调里对广告画面做截帧,用于素材归档、抽检或上报。请结合 广告SDK 的展示 API 与回调,便于直接落地实现。
  • 下载地址:http://info.appsmartsite.com/Material_monitor/Android_MaterialMonitor.zip

1. 模块能力

能力 说明
截帧 广告 View、全屏/overlay 页面,或原生图片 url-onlymeta.image_url)→ JPEG(≤ 可配置 KB,url-only 无本地文件)
元数据 ATAdInfo + 你传入的 AdTimingInput + 设备字段 → meta
上报 POST {baseUploadUrl}/v1/creative/uploadapp_idsignmetaimage
离线队列 SQLite;无网或传输层失败时延后重试(不占 maxUploadAttempts 计数);日配额节流
错误码 端侧 6xxx(§8.1)+ 网关 0 / 1xxx~5xxx(§8.4)

2. Gradle 接入

2.1 作为源码子模块(与本 Demo 相同)

在宿主 settings.gradle 中 include ':material-monitor',在 app 模块:

gradle 复制代码
dependencies {
    implementation project(':material-monitor')
    // 广告 SDK 依赖需保留,保证运行时存在 ATAdInfo
}

将 *_core_*.aar(或与你们版本一致的 core)放到 material-monitor/libs/,与仓库中 material-monitor/build.gradle 的 compileOnly fileTree(dir: 'libs') 一致。

2.2 权限与要求

  • minSdkVersion:本库 build.gradle 为 21;宿主若更高以宿主为准。

  • Java 8+

  • 网络权限:上报需宿主具备 INTERNET。模块已声明 ACCESS_NETWORK_STATE(用于上传前 是否有可用外网 的预检;合并 manifest 后由系统授予「查看网络连接」类权限)。

    plaintext 复制代码
    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android">
        <uses-permission android:name="android.permission.INTERNET" />
        <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    </manifest>
  • Core AAR:将 *_core_*.aar(或与你们版本一致的 core)放到 material-monitor/libs/,与仓库中 material-monitor/build.gradle 的 compileOnly fileTree(dir: 'libs') 一致。


3. 初始化

在首个 Activity.onCreate 调用(内部会注册生命周期回调以跟踪前台 Activity, 参考demo):

java 复制代码
import com.github.material.monitor.MaterialMonitor;
import com.github.material.monitor.MaterialMonitorConfig;

public class FirstActivity extends Activity {
    @Override
    public void onCreate() {
        super.onCreate();
        // 开发者用户协议允许之后自行获取和填充设备信息
        MaterialMonitor.init(this, new MaterialMonitorConfig.Builder()
                .baseUploadUrl("https://your-gateway-host")   // 上传地址
                .appId("YOUR_APP_ID")
                .appKey("YOUR_APP_KEY")                      // 请勿泄漏
                .oaid(oaidString)
                .androidId(androidIdString)
                .gaid(gaidString)
                // .imei(...).mac(...)
                // .maxUploadAttempts(3)
                // .retryDelayMs(3000L, 10000L)
                // .connectTimeoutMs(15000).readTimeoutMs(30000)
                // .debugPerfLogging(BuildConfig.DEBUG)
                .build());
    }
}

3.1 MaterialMonitorConfig.Builder 参数一览

类路径:com.github.material.monitor.MaterialMonitorConfig。构建后可通过** MaterialMonitor.get().getConfig() 读取;isUploadConfigured()** 在 baseUploadUrlappIdappKey 三者均非空时为 true(自动入队上报的前置条件)。

Builder 方法 默认 必填(上报) 说明
baseUploadUrl(String) "" 网关 根地址,仅 host(可带端口),不含路径。客户端会拼 POST {baseUploadUrl}/v1/creative/upload。示例:https://api.example.com\ 或测试环境 http://dev12-cag.toponad.com\。首尾空白会被 trim。
appId(String) "" TopOn 开发者后台分配的 应用 ID,用于 multipart 表单字段 app_id 与签名。
appKey(String) "" 与 appId 配对的 签名密钥(HMAC-MD5,见网关文档 §3)。写入公开仓库或明文日志;推荐远程下发或加固存储。
oaid(String) "" 建议 写入 meta.device_info.oaid。Android 匿名设备标识;须在 用户同意隐私后 由宿主采集并传入。
androidId(String) "" 可选 写入 meta.device_info.android_id
gaid(String) "" 可选 Google Advertising ID,写入 meta.device_info.gaid
imei(String) "" 可选 写入 meta.device_info.imei;受系统版本与权限限制,多数场景可不传。
mac(String) "" 可选 写入 meta.device_info.mac;合规上通常 不建议 采集。
maxUploadAttempts(int) 3 含首次请求 的单任务最大上传次数(3 = 1 次首发 + 最多 2 次重试)。仅对 网关可重试失败(如 4xxx/5xxx)计数;无网延后(6006)不占此预算(§9.2)。耗尽 → RETRY_EXHAUSTED(6007)。最小值为 1
retryDelayMs(long firstMs, long secondMs) 500015000 第 1、2 次 可重试失败 后的等待毫秒数;第 3 次及以后失败 复用 **secondMs**。与 4001 限流时 SDK 会取 max(配置延迟, 1s)
connectTimeoutMs(int) 15000 HttpURLConnection 连接超时(毫秒),内部 下限 3000
readTimeoutMs(int) 30000 HttpURLConnection 读超时(毫秒),内部 下限 3000
debugPerfLogging(boolean) false 为 true 时输出 [frame] / [bitmap] / [storage] / [upload] 等分阶段耗时(Logcat tag 含 MaterialLog@ + 模块版本),联调性能用;Release 建议关闭

仅采集、不上传:可MaterialMonitor.init(this) 则使用默认空配置;此时自动入队 / reportFrameRecord 会因未配置完整上传参数而得到 ErrorCodes.NOT_READY(见 §8)。


4. 何时调用、delayMs 建议与特殊场景

4.1 通用原则

在 广告已展示、目标区域已 layout 完成 且仍 attached 的回调里调用(如 onAdShow、Banner 展示回调、原生绑定数据后)。
FrameOptions.delayMs 表示:从调用时刻起再等待多少毫秒 才真正截屏,用于错开白屏、素材或视频首帧未就绪、弱网加载慢等情况。

4.2 因网络与素材加载的延迟建议(推荐默认值)

结合弱网下视频类素材缓冲更慢、静态或 HTML 类相对更快的差异,建议如下(可在远程配置中下发,按流量分层微调):

广告样式 建议 delayMs 说明
激励视频 3000~5000 ms 视频流与贴片常受网络影响,过短易黑屏或未解码帧;可从 2s 起线上观察完整率,必要时提到 3~5s
开屏 / Banner / 插屏 / 原生等非激励 约 2000 ms 相对激励视频对「首帧就绪」要求略低,2 秒在多数机型与网络上可兼顾合规画面与体验

以上针对「单次展示只截一帧」的常规监测;与 §4.3 的「激励关闭前多帧」可组合使用。

4.3 激励视频:关闭前按需 0 延时、间隔多帧

为更准确识别 违规画面、异常跳转、结束帧诱导 等,可在 广告即将关闭或用户即将离开 前,在 画面已稳定可见 的节点上,使用 **delayMs(0) 做 即时截帧,并按业务间隔 多次调用(例如每隔 5 秒一次,或在 onRewardonClose 前一刻各一次)。

注意

  • delayMs(0) 表示 不额外等待,仍要求调用时 View 已 layout 且 仍附着在窗口上;若调用过早仍可能失败(VIEW_INVALID / 黑帧),请把「0 延时调用」放在 生命周期靠后、内容已展示 的回调里。

  • 每一次 collectFrameFrom* 都会生成 新的 FrameRecord.uploadTaskId(队列幂等键),同一广告展示可多次截帧、多次上报;网关侧展示维度仍以 **ATAdInfo.getShowId() 等与 meta.event_info 一致。

  • 多帧会增加 流量、队列长度与日配额 消耗,请与产品/合规约定 频次上限。若有多帧截取需求,建议5秒一次,按最长边像素(maxLongEdge)1080标准;若有高频需求,则需降低maxLongEdge标准如720、540;高频截帧动作会增加ANR或内存上涨过高风险。

示例(伪代码:在激励关闭前短间隔再采一帧,delayMs 为 0):

java 复制代码
FrameOptions urgent = new FrameOptions.Builder().delayMs(0).maxSizeKb(300).build();
MaterialMonitor.get().collectFrameFromAdContainer(rewardContainer, adInfo, timing, urgent, callback);

4.4 原生自渲染:按素材类型选择采集 API

原生自渲染广告请按 主素材类型 选用 API(Demo 参考 NativeAdActivity 图片、NativePatchVideoActivity 视频):

素材类型 推荐 API 说明
图片(静态大图等) collectFrameFromNativeAdContainer 传入有效 http/https 的 creativeAssetUrl(如 getAdMaterial().getMainImageUrl())时,跳过本地截屏,仅上报 meta.image_url(网关 url-only 路径);无效或非 http(s) URL 会 回退 为对 targetView 截屏
视频 collectFrameFromAdContainer 视频帧在 SurfaceView / 硬件层,需走容器截屏 + PixelCopy不要依赖静态主图 URL
  • creativeAssetUrl:图片场景 有则传;须为 http:// 或 https:// 开头。空白或非法协议不会失败整次调用,而是回退为截屏。

  • url-only 成功时 FrameRecord.file 为 null,multipart 不含 image part;具体必填规则以网关文档为准。


5. API 参考(入参、返回值与用法)

包名:**com.github.material.monitor**。以下若无说明,采集相关回调均在主线程(见对外实施方案中的线程说明)。

5.1 MaterialMonitor.init / get / getConfig

方法 说明
static void init(Application application) 使用默认 MaterialMonitorConfig(无上传参数)。仅适合只落盘、不接网关的场景。
static void init(Application application, MaterialMonitorConfig config) 推荐。config 不可为 null 时用 DEFAULT 等价空配置。
static MaterialMonitor get() 获取单例。未 init 或已 shutdown 时返回 idle 占位实例collect* 等为 no-op 并打 warn 日志),不抛异常
static boolean isReady() 是否已 init 且尚未 shutdown(真实实例可在首次 get() 时懒创建)。
static void shutdown() 释放生命周期回调与 worker;待上传 SQLite 行保留,后续可再次 init 续传。
MaterialMonitorConfig getConfig() 读取初始化时的配置;可调用 isUploadConfigured() 判断是否具备 baseUploadUrl + appId + appKey

5.2 collectFrameFromAdContainer

签名

text 复制代码
void collectFrameFromAdContainer(
    View targetView,
    ATAdInfo adInfo,
    AdTimingInput timing,
    FrameOptions options,
    FrameCallback callback
)
参数 类型 可否 null 说明
targetView View 广告实际渲染区域(容器)。延时结束后会检查 仍 attached;延时期间仅 弱引用持有,避免泄漏。
adInfo ATAdInfo 当前展示对应的 TopOn 广告信息,用于 placementIdshowId、样式枚举 MaterialStyle等。
timing AdTimingInput 请求/填充/展示时间(毫秒),写入网关 event_info(库内转秒)。
options FrameOptions 传 null 时使用 FrameOptions.defaults()
callback FrameCallback 传 null 时无采集/上报回调,一般不推荐。

行为:校验通过后 **postDelayed(delayMs),到时截屏 → 压缩写盘 → 主线程 **onCollectSuccess** → 若上传已配置则 自动 **enqueueReport**。失败走 **onCollectFailure**(不会入队)。

样式目录MaterialStyle 由内部根据 ATAdInfo 解析,用于本地子目录名(如 rewarded_video),与网关 ad_type 含义对应,无需调用方传入。

5.3 collectFrameFromNativeAdContainer

签名

text 复制代码
void collectFrameFromNativeAdContainer(
    View targetView,
    ATAdInfo adInfo,
    AdTimingInput timing,
    FrameOptions options,
    String creativeAssetUrl,
    FrameCallback callback
)
参数 类型 可否 null 说明
targetView / adInfo / timingoptions / callback 同上 同上 与 collectFrameFromAdContainer 一致。
creativeAssetUrl String 可空字符串 有效 http/https URL 写入 FrameRecord.imageUrl 与 meta.image_url,并走 url-only 上报(不截屏、不写 JPEG)。空白或非法协议 回退 为对 targetView 截屏(与 collectFrameFromAdContainer 相同)。

行为:有效 URL 时延时结束后直接 onCollectSuccessfile == null)并入队 url-only 上报;回退路径与容器截屏一致。

5.4 collectFrameFromAdPage

签名

text 复制代码
void collectFrameFromAdPage(
    Activity hostActivity,
    ATAdInfo adInfo,
    AdTimingInput timing,
    FrameOptions options,
    FrameCallback callback
)
参数 类型 可否 null 说明
hostActivity Activity 调用方 当前页面(展示广告前/承载回调的 Activity,如 Demo 页)。用于在延时截屏时 排除 该窗口,避免透明 overlay 或独立 AdActivity 场景误截到宿主页。无效(null / finishing / destroyed)→ PARAM_INVALID
adInfo / timingoptions / callback 同上 同上 与容器采集一致。

延时后的捕获目标(按优先级):

  1. 当前 前台 resumed Activity(常为 SDK 独立广告页);

  2. 否则回退到 pin 住的 hostActivity

  3. 通过 HostOverlayViewLocator 解析 Dialog / 独立 Window / decor 顶层 overlay,而非简单取 android.R.id.content

适用:插屏/激励等 无稳定业务侧广告容器、或全屏覆盖难以取子 View 时(Demo:InterstitialAdActivityRewardVideoAdActivity 传入 this)。
失败常见原因:延时后无可用 Activity / 捕获 View → ACTIVITY_INVALID;弱引用 Activity 被回收等。

示例

java 复制代码
MaterialMonitor.get().collectFrameFromAdPage(
        InterstitialAdActivity.this, adInfo, timing,
        new FrameOptions.Builder().delayMs(3000).build(), callback);

5.5 onAdClosed

签名

text 复制代码
void onAdClosed(ATAdInfo adInfo)
参数 说明
adInfo 当前关闭的广告;按 ATAdInfo.getShowId() 匹配仍在 delayMs 等待中的采集任务。

行为:若同一 showId 的 collectFrameFromAdContainer 或 collectFrameFromAdPage 尚未执行截屏,则 取消 本次采集并回调 onCollectFailure(COLLECT_CANCELLED, …),避免广告已关仍截到空白或宿主页。

何时调用:在广告 关闭回调 中调用(Demo:onInterstitialAdCloseonRewardedVideoAdClosed)。Dialog / overlay / 宿主 Activity 上展示的插屏 建议必调;独立全屏 AdActivity 且生命周期已足够时可省略。

java 复制代码
@Override
public void onInterstitialAdClose(ATAdInfo adInfo) {
    MaterialMonitor.get().onAdClosed(adInfo);
}

5.6 reportFrameRecord

签名

text 复制代码
void reportFrameRecord(FrameRecord record, ATAdInfo adInfo)
void reportFrameRecord(FrameRecord record, ATAdInfo adInfo, ReportCallback callback)
参数 说明
record 截屏路径须含 已存在 的本地 JPEG file;url-only 采集时 file 为 null,由 collectFrameFromNativeAdContainer 自动入队,一般无需手动调用。uploadTaskId 为空时入队会生成  task_id
adInfo 与当时展示一致,用于组装 meta 中广告字段。
callback 仅上报结果:onReportSuccess / onReportSkip / onReportFailure(无 onCollect)。

典型用途:先采集落盘、后择机上传;或采集成功但此前上传失败后的补传(注意 uploadTaskId 与重复入队语义)。

5.7 flushPendingFrames

text 复制代码
void flushPendingFrames()

作用:主动请求模块 尽快处理一次 SQLite 中仍存在的 待上传任务(内部会调度上传执行器里的 drain,与「新任务入队」触发的处理同源)。可从任意线程调用,内部会切到上传线程与主线程 Handler,不会在调用线程上做 HTTP。

典型使用场景(按需选用;与「新任务入队自动 drain」叠加一般无害):

场景 说明
网络从不可用到可用 无网、NETWORK_ERROR 延后路径下任务仍在库中;在 NetworkCallback.onAvailable、或自建「已联网」判断里调用,可缩短等到下一次 约 30s 定时探测的间隔。
用户打开 Wi‑Fi / 蜂窝后回到 App 在 onResume 或网络回调里 flushPendingFrames()
日配额 / 限流解除后 封禁窗口过后可配合业务判断再 flush

一般不必:仅依赖进程内 入队 / init 时的自动 drain 也能在恢复网络后陆续上传;无全局网络监听时,至少在 网络可用回调 + 主 Activity **onResume** 调用即可。

与「无网延后」的关系flush 只唤醒上传队列,不重新截屏;无网时 drain 内仍会预检失败并再次排程,但比干等定时器更及时。

注意flush 绕过日配额门;本地文件已删或任务已终态则无上传可做。无网延后、回调语义等见 §9

5.8 getRecords / deleteRecord

text 复制代码
List<FrameRecord> getRecords(MaterialStyle style)
boolean deleteRecord(FrameRecord record)
方法 说明
getRecords 枚举某 MaterialStyle 对应目录下历史 JPEG 文件;返回的 FrameRecord 部分字段可能为占位(仅保证 style与 file 等文件级信息),不宜当作完整上报元数据唯一来源。
deleteRecord 先取消与该 FrameRecord 的 uploadTaskId 或本地路径匹配的 待上传任务,再删文件,避免队列与磁盘不一致。

**MaterialStyle 枚举:SPLASHBANNERINTERSTITIALREWARDED_VIDEONATIVE(与文件夹名一致,见源码 getFolderName())。


6. FrameOptions 与 AdTimingInput

6.1 FrameOptions.Builder

方法 / 字段 默认 说明
delayMs(long) 500 ≥ 0。建议按 §4.2 调整:激励 2~5s,其他 约 2s;关闭前定点可用 0
maxSizeKb(int) 300 输出 JPEG 上限,与网关「单图 ≤300KB」对齐;允许范围 80, 300(超出会被 clamp)。
maxLongEdge(int) 1080 最长边像素上限;允许 540, 1440(超出会被 clamp)。默认 1080 在 300KB 网关限制与审核可读性之间折中;识别要求更高可调至 1440 并验证 JPEG 体积。若截帧频率高则倾向720 或 更低
keepQualityFirst(boolean) true 优先较高 JPEG 质量再降质量/缩小,直到满足 maxSizeKb

构建:new FrameOptions.Builder().delayMs(2000).maxSizeKb(300).build()

6.2 AdTimingInput

构造 / 工厂 说明
new AdTimingInput(requestTimeMs, fillTimeMs, showTimeMs) 毫秒;写入 meta.event_info 时转为秒。

网关对 request_ts / fill_ts / show_ts 的必填语义以对接文档为准;库内对 ≤0 的项会按 show_ts 等同秒做回填(见 CreativeMetaBuilder),生产环境仍建议传入真实三阶段时间


7. 回调说明(FrameCallback / AbstractFrameCallback

java 复制代码
AbstractFrameCallback() {
            @Override
            public void onCollectSuccess(FrameRecord record) {
                // 主线程:截屏成功时 file 已写好;url-only 时 file 为 null、仅带 image_url
            }

            @Override
            public void onCollectFailure(int errorCode, String message, Throwable cause) {
                // 主线程:未入队上传
            }

            @Override
            public void onReportSuccess(FrameRecord record) {
                // 主线程:上传成功;record.getFile() 通常为 null(库已删 JPEG)
            }

            @Override
            public void onReportSkip(FrameRecord record, String reason) {
                // 主线程:重复 task、配额封禁等
            }

            @Override
            public void onReportFailure(int errorCode, String message, FrameRecord record, Throwable cause) {
                // 主线程:record 可能为 null(终端失败且已清理)
            }
        }
java 复制代码
MaterialMonitor.get().collectFrameFromAdContainer(target, adInfo, AdTimingTracker.mock(), options,
                MaterialMonitorHelper.demoFrameCallback(this));

frameCallback需要持有activity,为避免内存泄漏推荐两种使用路径:

  1. static 内部类 + 引用 **Activity.this**方式:参考MaterialMonitorHelper.demoFrameCallback(activity) 弱引用持有activity;

  2. 匿名 / 非 static 内部类 + 强引用 **Activity.this**方式:可在activity **onDestroy** 对接 传入与 **collect*** 的同一实例 frameCallback

java 复制代码
  MaterialMonitor.get().detachCallback(frameCallback);

8. 错误码速查(com.github.material.monitor.ErrorCodes

SDK 回调里的 errorCode 均为 6xxx 端侧码,与网关 HTTP 响应 JSON 的 **code**(1xxx~5xxx)不是同一套数值。排查网关问题时,请看失败 message 里的 gateway NNNN: … 前缀,并对照 CreativeAuditGateway - SDK对接文档

8.1 端侧错误码一览

常量 回调 终端 含义与处理建议
6001 VIEW_INVALID onCollectFailure 容器为空、未 attach,或 delayMs 后 View 已销毁 → 在 展示且仍 attached 的回调里调用;适当增大 delayMs
6002 ACTIVITY_INVALID onCollectFailure 全屏采集延时后无可用页面 → collectFrameFromAdPage 传入有效 hostActivity;确认广告页仍在前台
6003 COLLECTION_FAILED onCollectFailure 截屏失败(含 PixelCopy 失败)→ 视频类用容器 API;低版本可能只能 View.draw,可增大 delayMs
6004 COMPRESS_FAILED onCollectFailure JPEG 超 maxSizeKb 预算 → 降低 maxLongEdge 或 maxSizeKb,或缩小截帧区域
6005 PARAM_INVALID onCollectFailure / onReportFailure 入参不合法(adInfo/timing/hostActivity 等)或 reportFrameRecord 时本地文件不存在
6006 NETWORK_ERROR onReportFailure 无网或传输失败;任务仍排队,不占重试上限 → 恢复网络后 flushPendingFrames()(§9.2);成功后仍可能 onReportSuccess
6007 RETRY_EXHAUSTED onReportFailure 上传重试耗尽 → 查 message 中网关码;需补传时用新 uploadTaskId 重新 reportFrameRecord 或重新采集
6008 NOT_READY onCollectFailure / onReportFailure 未 init、已 shutdown,或 baseUploadUrl/appId/appKey 未配齐
6009 COLLECT_CANCELLED onCollectFailure 延时未截屏前广告已关(onAdClosed)→ 预期行为;关闭回调中调用 onAdClosed 可避免误采

8.2 回调与错误码

回调 说明
onCollectFailure 采集/写盘失败,或 onAdClosed 取消;不会自动入队上传
onReportFailure 上报链失败;6006 为非终端,其余多为终端(本地任务可能已清理)
onReportSkip 不是错误码;如日配额封禁、重复 uploadTaskId,看 reason 字符串

采集 vs 上报:6001~6004、6009 只出现在 onCollectFailure;6005~6008 主要出现在 onReportFailure(6005 也可能在采集入口触发)。

8.3 网关 code 与端侧 errorCode

你看到的 说明
回调 errorCode(6xxx) SDK 采集链及无 HTTP 响应时的上报错误(如 6006 无网)
回调 errorCode(1xxx~5xxx) 部分 网关终态失败 时,errorCode 可能与响应 body 的 code 相同;仍建议以 **message** 为准
message 中 gateway NNNN: 网关原始协议码与文案,联调时 优先解析此字段
响应 body trace_id 成功/失败均可能返回,联系 TopOn 技术支持时一并提供

不要把 6xxx 端侧码与网关 1xxx~5xxx 混在同一套埋点枚举里。网关码完整表见 §8.4

8.4 网关响应错误码(CreativeAuditGateway)

上传接口 POST …/v1/creative/upload 返回 JSON,**code == 0** 表示成功(HTTP 通常为 200)。失败时 code 为非 0,且 **trace_id** 在成功与失败时均可能返回,请失败时落日志便于排查。

以下与 **document/CreativeAuditGateway - SDK对接文档.md** §八 一致;若网关版本有增删,以在线接口说明为准。

8.4.1 成功

code msg(示例) 说明
0 ok 上传成功;同一 event_info.show_id 重复上报也返回 0(幂等,不重复扣配额)

8.4.2 1xxx — 鉴权错误(不可重试)

code HTTP msg(示例) 说明 建议处理
1001 401 unauthorized 签名校验失败或 app_id 无效 检查 appKey、签名算法、appId
1002 403 forbidden 未开通素材监测能力 联系 TopOn 运营开通

8.4.3 2xxx — 参数 / 图片错误(不可重试)

code HTTP msg(示例) 说明 建议处理
2001 400 invalid params meta 必填字段缺失或格式错误 核对 ATAdInfoAdTimingInput、设备字段
2002 400 image too large JPEG 超过 300KB 降低 maxSizeKb / maxLongEdge
2003 400 invalid image format 非 JPEG 确认截屏输出为 JPEG
2005 400 request body too large 整包超过 512KB 缩小图片或走 url-only

8.4.4 3xxx — 配额错误(当日不再上报)

code HTTP msg(示例) 说明 建议处理
3001 429 account quota exceeded 帐户每日配额用完 当天停止上报;响应或 onReportSkip/reason 中可能有 daily_quota_reset_at
3002 429 app quota exceeded App 每日配额用完 同上,针对单个 App

8.4.5 4xxx — 限流(可重试)

code HTTP msg(示例) 说明 建议处理
4001 429 rate limit exceeded 请求频率过高 等待响应 Header Retry-After(通常 ≥1s)后重试

8.4.6 5xxx — 服务端错误(可重试)

code HTTP msg(示例) 说明 建议处理
5001 500 upload failed 服务端存储异常 SDK 自动重试;仍失败则 RETRY_EXHAUSTED(6007)
5002 500 internal error 服务端内部错误 同上
5003 502 image download failed meta.image_url 下载失败 检查 URL 可访问性(原生 url-only)
5004 503 service unavailable 服务暂不可用 稍后重试

8.4.7 material-monitor 对网关码的处理

网关 code SDK 行为 宿主回调
0 删本地 JPEG 与队列行 onReportSuccess
1001~1002、2001~2005 终端失败,清理本地任务 onReportFailuremessage 含 gateway NNNN: …
3001~3002 写入日配额封禁窗口,清理当前任务 onReportFailure 或后续新任务 onReportSkipreason 含 daily_quota_reset_at
4001、5001~5004 按 maxUploadAttempts 自动重试(4001 至少等待 1s) 重试期间通常  失败回调;耗尽后 onReportFailure(6007, …)
无 HTTP 响应 / 无网 延后约 30s 再试,不占重试次数 onReportFailure(6006, …) 至多一次;恢复网后可 onReportSuccess

9. 网络、无网延后与队列

9.1 队列与线程

  • 采集成功且上传已配置时,任务写入 SQLite,由 单线程 uploadExecutor 顺序上传。

  • 日配额(3001/3002):可能 onReportSkipreason 含 daily_quota_reset_at(见网关文档)。

9.2 无网 / 传输层失败(NETWORK_ERROR = 6006)

上传线程在 真正发起 HTTP 之前 会调用 NetworkReachability.hasInternet(需 ACCESS_NETWORK_STATE,由本模块 manifest 合并进宿主):

  • Android M(API 23)及以上:当前默认网络须具备 NET_CAPABILITY_INTERNET 且 NET_CAPABILITY_VALIDATED(系统已判定可上网),否则视为无网。

  • 更低版本NetworkInfo.isConnected() 为真才继续。

若预检判定无网,或 HttpURLConnection 在收到 HTTP 状态行之前失败(超时、UnknownHost、无路由等,上传结果表现为 **httpCode==0 且 gatewayCode==-1),进入 延后路径

行为
重试计数 增加 retry_count不计入 MaterialMonitorConfig.getMaxUploadAttempts() 的「可重试失败」预算)
数据 保留 DB 行与本地 JPEG
定时再试 约 30 秒 后再次调度 processNextUploadTask 探测队列
**onReportFailure 同一 uploadTaskId 在「持续处于延后状态」期间,**NETWORK_ERROR 只回调一次,避免日志/埋点刷屏
**ReportCallback 生命周期 因该次失败而移除;后续同一任务上传成功时,仍可收到 **onReportSuccess(与「先失败后成功」不矛盾,详见 ReportCallback JavaDoc)

宿主可在 **NetworkCallback.onAvailable**、回到前台的 **onResume** 等处调用 **MaterialMonitor.get().flushPendingFrames()**,缩短「等 30 秒」的空窗(与内部定时叠加无害)。

9.3 flushPendingFrames(摘要)

java 复制代码
MaterialMonitor.get().flushPendingFrames();

主动唤醒一次队列 drain;可从任意线程调用。典型场景见 §5.7 表格。


10. 隐私与合规建议

  • 只截取 广告相关区域 的 View,避免把个人敏感界面截进去。

  • 设备标识(OAID、GAID 等)请遵守当地法律与平台政策。

  • appKey 不建议硬编码在公开的地方。


11. 排错清单

现象 可能错误码 检查项
调用无效果 / warn not initialized 是否已 MaterialMonitor.init;未 init 时 get() 为 idle 实例
延时后采集失败 6001 View 是否仍 attached;调用时机是否过早
插屏/激励全屏失败 6002 collectFrameFromAdPage 是否传入 hostActivity;延时后广告页是否仍可见
黑屏 / 视频画面不对 6003 视频用 collectFrameFromAdContainer;增大 delayMs(§4.2)
图片过大无法压缩 6004 降低 maxLongEdge(540~1440)或 maxSizeKb
广告关后仍想采帧却失败 6009 属预期;未关前应完成采集,或不要调 onAdClosed
一直 NOT_READY 6008 baseUploadUrlappIdappKey 是否齐全
NETWORK_ERROR 后仍 pending 6006 延后上传(§9.2);恢复网络后 flushPendingFrames()
多次失败终态 6007 / 网关码 查 message 中 gateway NNNN: 与 trace_id(§8.4)
重复上报 —(onReportSkip 同一 uploadTaskId 只入队一次
想重新上传同一文件 使用 uploadTaskId 为空的 FrameRecord 调 reportFrameRecord,或重新采集
原生图片无本地 JPEG 有效 URL 走 url-only;视频类用 collectFrameFromAdContainer
插屏截到宿主页 6002 / 6003 传入 hostActivity;关闭时调 onAdClosed

完整错误码表见 §8


最近修改: 2026-07-02Powered by