用户体验监控提供了一系列SDK配置项,让您能够通过设置参数来满足额外需求。本文介绍iOS应用常用的SDK配置。
启动配置
设置 Endpoint 地址
每个应用都需要关联对应的Endpoint地址,该接口需要在调用start:前设置。
@objc
public static func setEndpoint(_ endpoint: String)参数 | 说明 | 参数限制 | 失败结果 |
endpoint | Endpoint 地址 | 字符串长度大于0且小于2083 | 接口调用失败,SDK 初始化失败 |
设置 Workspace 地址
每个应用都需要关联对应的Workspace,该接口需要在调用start:前设置。
@objc
public static func setWorkspace(_ workspace: String)参数 | 说明 | 参数限制 | 失败结果 |
workspace | Workspace 地址 | 字符串长度大于0且小于2083 | 接口调用失败,SDK 初始化失败 |
启动接口
您需要调用start: 方法初始化 SDK。
@objc(start:)
public static func start(_ serviceId: String)参数 | 说明 | 参数限制 | 失败结果 |
serviceId | ServiceId | 由用户体验监控平台生成的应用唯一ID | 接口调用失败,SDK 初始化失败 |
设置自定义设备ID
可以通过此方法设置自定义设备ID,设置成功后,SDK将不再使用默认获取的设备ID。
@objc
public static func setDeviceID(_ deviceID: String)参数 | 说明 | 参数限制 | 失败结果 |
deviceID | 自定义的设备ID | 字符串长度大于0且小于256,且不包含特殊字符(仅支持字母、数字、冒号、空格、下划线_、链接符-、英文句号、@) | 接口调用失败,当次设置无效 |
设置自定义App版本号
通过此方法设置了自定义App版本号,那么SDK将会上报此版本号,不再使用默认获取的版本号。
@objc
public static func setAppVersion(_ appVersion: String)参数 | 说明 | 参数限制 | 失败结果 |
appVersion | 自定义的App版本号 | 字符串长度大于0且小于64。 | 接口调用失败,当次设置无效。 |
设置用户渠道ID
区分应用发布的渠道。
@objc
public static func setChannelID(_ channelID: String)参数 | 说明 | 参数限制 | 失败结果 |
channelID | 自定义的渠道号 | 字符串长度大于0且小于256。 | 接口调用失败,当次设置无效。 |
屏蔽特定类
将指定类名加入 swizzle 排除集合,匹配到的类将跳过自动分析和插桩。当不期望采集某个类的数据,或遇到特定类的兼容性问题时,可以通过调用该方法设置排除的类。该方法支持多次调用。SDK 基于“子串匹配”的类名排除策略实现。
注意:该方法必须在 SDK 初始化之前调用。请谨慎定义排除关键字,以免因包含关系导致非预期的类被误拦截。
@objc(excludeClassFromTracking:)
public static func excludeClassFromTracking(_ className: String)参数 | 说明 | 参数限制 | 失败结果 |
className | 需要排除的类名。 | 类名不能为空。 | 当次设置无效。 |
示例:
// 屏蔽所有包含 StoreKit2ViewController 类
[AlibabaCloudRUM excludeClassFromTracking:@"StoreKit2ViewController"];
// 屏蔽所有包含 BTDemoStoreKit2MixedBridge 类
[AlibabaCloudRUM excludeClassFromTracking:@"BTDemoStoreKit2MixedBridge"];禁用/开启模块
SDK 支持禁用或开启指定的采集模块。本地配置的生效优先级会高于远程配置。多次调用会累积。
注意:该方法必须在 SDK 初始化之前调用。本地配置的生效优先级会高于远程配置,请谨慎配置。
@objc(disableModule:)
public static func disableModule(_ module: AlibabaCloudModule)
@objc(enableModule:)
public static func enableModule(_ module: AlibabaCloudModule)
@objc(AlibabaCloudModule)
public enum AlibabaCloudModule: Int {
case crash = 0
case network = 1
case view = 2
case action = 3
case webView = 4
case longTask = 5
case appLaunch = 6
case appState = 7
case netState = 8
case customEvent = 9
case customLog = 10
case customMetric = 11
}参数 | 说明 | 参数限制 | 失败结果 |
module | 需要禁用/开启的采集模块。 | 需要为 AlibabaCloudModule 类型 | 当次设置无效。 |
示例:
// 屏蔽网络库数据采集模块
[AlibabaCloudRUM disableModule:AlibabaCloudModuleNetwork];设置应用环境
区分应用的环境。通过此方法可以指定应用的环境,如LOCAL、DAILY、PROD等。
@objc
public static func setEnvironment(_ env: Env)参数 | 说明 | 参数限制 | 失败结果 |
env | 应用环境的枚举值。需要在 | Env枚举值:
| 接口调用失败,当次设置无效。 |
资源快照采集
SDK支持采集HTTP请求/响应的headers 和 payload 信息。SDK 默认不采集任何资源的快照数据,您需要通过下文中提供的API显示启用。
需要通过设置ResourceSnapshotProvider显示启用HttpClient库的快照信息采集。
void setResourceSnapshotProvider(ResourceSnapshotProvider? provider)参数 | 说明 | 参数限制 | 失败结果 |
onRequestHeaders | HttpClientRequest | Map<String, Object>? | 返回要采集的请求头,null表示不采集 |
onRequestPayload | HttpClientRequest | String? | 返回要采集的请求体,null表示不采集 |
onResponseHeaders | HttpClientResponse | Map<String, Object>? | 返回要采集的响应头,null表示不采集 |
onResponsePayload | HttpClientResponse | String? | 返回要采集的响应体,null表示不采集。 |
ResourceSnapshotUtils 工具类
由于 HttpClientRequest 是只写流、HttpClientResponse 是只读流,需要使用工具类进行缓存。
方法 | 说明 |
| 缓存请求体,在 |
| 获取缓存的请求体 |
| 缓存响应体,在读取响应流后调用 |
| 获取缓存的响应体 |
受 HttpClient 库和 SDK 采集实现的限制,当前暂不支持 response body 信息的采集。
您可以需要借助
ResourceSnapshotUtils完成 request payload 信息的采集。
示例:
AlibabaCloudRUM().setResourceSnapshotProvider(
ResourceSnapshotProvider(
onRequestHeaders: (request) {
return {
'content-type': request.headers.value('content-type') ?? '',
};
},
onRequestPayload: (request) {
// 由于 request 中没有保存 payload 相关的接口,因此,您需要通过 ResourceSnapshotUtils 类,
// 在请求发起时主动调用 ResourceSnapshotUtils.cacheRequestBody 方法完成 payload 数据的缓存
final body = ResourceSnapshotUtils.getCachedRequestBody(request);
if (body == null) return null;
// 注意,数据需做脱敏处理
return body.replaceAll(RegExp(r'"password":\s*"[^"]*"'), '"password":"***"');
},
onResponsePayload: (response) {
// 当前暂不支持 response payload 数据的采集
return null;
},
),
);注意事项
SDK 默认不采集任何 headers/palyload 数据,必须通过上述API显示启用。
SDK 调用者负责数据脱敏,SDK 不会自动过滤任何敏感信息(包括但不限于:密码、用户个人信息等)。
自定义信息
自定义用户名称
SDK支持设置与用户相关的信息,从而完成与实际用户相关联的数据分析需求场景。
@objc
public static func setUserName(_ userID: String)参数 | 说明 | 参数限制 | 失败结果 |
userID | 用户名称标识 | 字符串可为null或空串。 字符串小于等于256,且不包含特殊字符,只允许数字、字母、英文半角冒号(:)、空格、正斜线(/)、下划线(_)、英文半角连接号(-)、英文半角句号(.)和@。 | 接口调用失败,当次设置无效。 |
自定义用户扩展信息
SDK支持设置与用户相关的信息,从而完成数据分析与实际用户相关联的需求场景。
@objc(setUserExtraInfo:)
public static func setUserExtraInfo(_ extraInfo: [String: AnyObject])参数 | 说明 | 参数限制 | 失败结果 |
extraInfo | 用户扩展信息 | Map可为空或空集。 转JSON后长度在7000字符以内,否则接口调用失败。 | 接口调用失败,当次设置无效。 |
自定义全局属性
自定义全局属性设置后,新产生的数据会自动携带该业务属性信息,用于分析与业务属性相关联的需求。
@objc(setExtraInfo:)
public static func setExtraInfo(_ extraInfo: [String: AnyObject])
@objc(addExtraInfo:)
public static func addExtraInfo(_ extraInfo: [String: AnyObject])参数 | 说明 | 参数限制 | 失败结果 |
extraInfo | 属性信息 | Map可为空或空集。转JSON后长度在7000字符以内,否则接口调用失败。 | 接口调用失败,当次设置无效。 |
调用 setExtraInfo 方法时会清空历史设置的属性信息。如您需要追加新的属性信息,建议您通过 addExtraInfo 方法。
自定义异常
调用自定义异常接口,并传入相应的参数,可完成自定义异常数据的统计功能。
@objc(setCustomException:causeBy:errorDump:)
public static func setCustomException(_ exceptionType: String, _ causeBy: String, _ errorDump: String)参数 | 说明 | 参数限制 | 失败结果 |
exceptionType | 异常类型(必要) | 字符串长度大于0且小于等于256。 | 接口调用失败,当次设置无效。 |
causeBy | 异常原因 | 字符串可为null或空串。 字符串小于等于512,超长会截取。 | 不涉及 |
errorDump | 异常信息 | 字符串可为null或空串。 字符串小于等于10000,超长会截取。 | 不涉及 |
自定义事件
SDK支持上报自定义事件。调用相应的接口,并传入相应的参数,可完成自定义事件数据的统计功能。
@objc(setCustomEvent:)
public static func setCustomEvent(_ name: String)参数 | 说明 | 参数限制 | 失败结果 |
name | 事件名称(必要) | 字符串长度大于0且小于等于256 | 接口调用失败,当次设置无效 |
@objc(setCustomEvent:group:)
public static func setCustomEvent(_ name: String, group: String? = nil)参数 | 说明 | 参数限制 | 失败结果 |
name | 事件名称(必要) | 字符串长度大于0且小于等于256 | 接口调用失败,当次设置无效 |
group | 事件分组 | 字符串可为 字符串小于等于256,超长会截取。 | 不涉及 |
@objc(setCustomEvent:group:snapshots:)
public static func setCustomEvent(_ name: String, group: String? = nil, snapshots: String? = nil)参数 | 说明 | 参数限制 | 失败结果 |
name | 事件名称(必要) | 字符串长度大于0且小于等于256 | 接口调用失败,当次设置无效 |
group | 事件分组 | 字符串可为 字符串小于等于256,超长会截取。 | 不涉及 |
snapshots | 事件快照 | 字符串可为 字符串小于等于7000,超长会截取。 | 不涉及 |
@objc(setCustomEvent:group:value:)
public static func setCustomEvent(_ name: String, group: String? = nil, value: Double = 0)参数 | 说明 | 参数限制 | 失败结果 |
name | 事件名称(必要) | 字符串长度大于0且小于等于256 | 接口调用失败,当次设置无效 |
group | 事件分组 | 字符串可为 字符串小于等于256,超长会截取。 | 不涉及 |
value | 事件值 | double类型 | 不涉及 |
@objc(setCustomEvent:group:info:)
public static func setCustomEvent(_ name: String, group: String? = nil, info: [String: String]? = nil)参数 | 说明 | 参数限制 | 失败结果 |
name | 事件名称(必要) | 字符串长度大于0且小于等于256 | 接口调用失败,当次设置无效 |
group | 事件分组 | 字符串可为 字符串小于等于256,超长会截取。 | 不涉及 |
info | 事件附加信息 | Map可为空或空集。转JSON后长度在7000字符以内,否则接口调用失败。 | 不涉及 |
@objc(setCustomEvent:group:snapshots:value:)
public static func setCustomEvent(_ name: String, group: String? = nil, snapshots: String? = nil, value: Double = 0) 参数 | 说明 | 参数限制 | 失败结果 |
name | 事件名称(必要) | 字符串长度大于0且小于等于256。 | 接口调用失败,当次设置无效 |
group | 事件分组 | 字符串可为 字符串小于等于256,超长会截取。 | 不涉及 |
snapshots | 事件快照 | 字符串可为 字符串小于等于7000,超长会截取。 | 不涉及 |
value | 事件值 | double类型。 | 不涉及 |
@objc(setCustomEvent:group:snapshots:info:)
public static func setCustomEvent(_ name: String, group: String? = nil, snapshots: String? = nil, info: [String: String]? = nil)参数 | 说明 | 参数限制 | 失败结果 |
name | 事件名称(必要) | 字符串长度大于0且小于等于256 | 接口调用失败,当次设置无效 |
group | 事件分组 | 字符串可为 字符串小于等于256,超长会截取。 | 不涉及 |
snapshots | 事件快照 | 字符串可为 字符串小于等于7000,超长会截取。 | 不涉及 |
info | 事件附加信息 | Map可为空或空集。转JSON后长度在7000字符以内,否则接口调用失败。 | 不涉及 |
@objc(setCustomEvent:group:value:info:)
public static func setCustomEvent(_ name: String, group: String? = nil, value: Double = 0, info: [String: String]? = nil) 参数 | 说明 | 参数限制 | 失败结果 |
name | 事件名称(必要) | 字符串长度大于0且小于等于256 | 接口调用失败,当次设置无效 |
group | 事件分组 | 字符串可为 字符串小于等于256,超长会截取。 | 不涉及 |
value | 事件值 | double类型 | 不涉及 |
info | 事件附加信息 | Map可为空或空集。转JSON后长度在7000字符以内,否则接口调用失败。 | 不涉及 |
@objc(setCustomEvent:group:snapshots:value:info:)
public static func setCustomEvent(_ name: String, group: String? = nil, snapshots: String? = nil, value: Double = 0, info: [String: String]? = nil)参数 | 说明 | 参数限制 | 失败结果 |
name | 事件名称(必要) | 字符串长度大于0且小于等于256 | 接口调用失败,当次设置无效 |
group | 事件分组 | 字符串可为 字符串小于等于256,超长会截取。 | 不涉及 |
snapshots | 事件快照 | 字符串可为 字符串小于等于7000,超长会截取。 | 不涉及 |
value | 事件值 | double类型 | 不涉及 |
info | 事件附加信息 | Map可为空或空集。转JSON后长度在7000字符以内,否则接口调用失败。 | 不涉及 |
自定义日志
SDK支持上报自定义日志信息。调用相应的接口,并传入相应的参数,可完成自定义日志数据的统计功能。
@objc(setCustomLog:)
public static func setCustomLog(_ logInfo: String)参数 | 说明 | 参数限制 | 失败结果 |
logInfo | 日志信息(必要) | 字符串长度大于0且小于等于10000,超长会被截取。 | 接口调用失败,当次设置无效。 |
@objc(setCustomLog:name:)
public static func setCustomLog(_ logInfo: String, name: String? = nil) 参数 | 说明 | 参数限制 | 失败结果 |
logInfo | 日志信息(必要) | 字符串长度大于0且小于等于10000,超长会被截取。 | 接口调用失败,当次设置无效。 |
name | 日志名称 | 字符串长度大于0且小于等于256。 | 不涉及 |
@objc(setCustomLog:name:snapshots:)
public static func setCustomLog(_ logInfo: String, name: String? = nil, snapshots: String? = "") 参数 | 说明 | 参数限制 | 失败结果 |
logInfo | 日志信息(必要) | 字符串长度大于0且小于等于10000,超长会被截取。 | 接口调用失败,当次设置无效。 |
name | 日志名称 | 字符串长度大于0且小于等于256。 | 不涉及 |
snapshots | 日志快照 | 字符串可为null或空串。 字符串小于等于7000,超长会截取。 | 不涉及 |
@objc(setCustomLog:name:snapshots:level:info:)
public static func setCustomLog(_ logInfo: String, name: String? = nil, snapshots: String? = "", level: String? = "INFO", info: [String: String]? = nil)参数 | 说明 | 参数限制 | 失败结果 |
logInfo | 日志信息(必要) | 字符串长度大于0且小于等于10000,超长会被截取。 | 接口调用失败,当次设置无效。 |
name | 日志名称 | 字符串长度大于0且小于等于256。 | 不涉及 |
snapshots | 日志快照 | 字符串可为null或空串。 字符串小于等于7000,超长会截取。 | 不涉及 |
level | 日志等级 | 字符串长度大于0且小于等于256,默认为INFO。 | 不涉及 |
info | 日志附加信息 | Map可为空或空集。 转JSON后,字符串长度与logInfo共享,否则接口调用失败。 | 不涉及 |
自定义资源
SDK支持上报自定义网络资源请求数据,可以记录 HTTP/HTTPS 等类型请求的详细信息,包括请求状态、性能指标和链路追踪信息。SDK 提供了两个重载版本,分别适用于基础场景和高级场景。
基础场景
@objc(setCustomResource:success:url:method:statusCode:errorMessage:)
public static func setCustomResource(_ type: String, success: Bool, url: String, method: String, statusCode: Int, errorMessage: String?) -> Bool参数 | 类型 | 说明 | 参数限制 |
type | String | 资源类型,例如: | 字符串长度大于0且小于等于64,超长截取。 |
success | Bool | 请求是否成功 | true,成功;false,失败。 |
url | String | 请求的完整 URL 地址 | 字符串长度大于0且小于等于1024,超长截取。 |
method | String | HTTP 请求方法,如: | 字符串长度大于0且小于等于24,超长截取。 |
statusCode | Int | HTTP 响应状态码 | HTTP 状态码,如:200、404、500等。 |
errorMessage | String? | 错误信息描述,仅在请求失败时填写 | 字符串长度大于0且小于等于256,超长截取。可为 |
返回值:Bool - 接口调用是否成功,true 表示调用成功,false 表示调用失败(如 SDK 未初始化或参数错误)。
使用示例:
// Swift - 成功的 GET 请求
let result = AlibabaCloudRUM.setCustomResource(
"AP",
success: true,
url: "https://api.example.com/users",
method: "GET",
statusCode: 200,
errorMessage: nil
)
// Swift - 失败的 POST 请求
let result2 = AlibabaCloudRUM.setCustomResource(
"API",
success: false,
url: "https://api.example.com/login",
method: "POST",
statusCode: 401,
errorMessage: "Unauthorized access"
)// Objective-C - 成功的 GET 请求
BOOL result = [AlibabaCloudRUM setCustomResource:@"API"
success:YES
url:@"https://api.example.com/users"
method:@"GET"
statusCode:200
errorMessage:nil];
// Objective-C - 失败的 POST 请求
BOOL result2 = [AlibabaCloudRUM setCustomResource:@"API"
success:NO
url:@"https://api.example.com/login"
method:@"POST"
statusCode:401
errorMessage:@"Unauthorized access"];
高级场景
高级场景支持性能和链路追踪的配置。
@objc(setCustomResource:success:url:method:statusCode:errorMessage:provider:tracing:measure:)
public static func setCustomResource(_ type: String, success: Bool, url: String, method: String, statusCode: Int, errorMessage: String?, provider: String?, tracing: AlibabaCloudTracingContext?, measure: AlibabaCloudResourceMeasure?) -> Bool参数 | 类型 | 参数说明 | 参数限制 |
type | String | 资源类型 | 字符串长度大于0且小于等于64,超长截取。 |
success | Bool | 请求是否成功 | true,成功;false,失败。 |
url | String | 请求的完整 URL 地址 | 字符串长度大于0且小于等于1024,超长截取。 |
method | String | HTTP 请求方法 | 字符串长度大于0且小于等于24,超长截取。 |
statusCode | Int | HTTP 响应状态码 | HTTP 状态码,如:200、404、500等。 |
errorMessage | String? | 错误信息描述 | 字符串长度大于0且小于等于256,超长截取。可为 |
provider | String? | 服务提供商标识,如: | 字符串长度大于0且小于等于256,超长截取。可为 |
tracing | AlibabaCloudTracingContext? | 链路追踪上下文信息 | AlibabaCloudTracingContext 类型,可为 |
measure | AlibabaCloudResourceMeasure? | 资源性能指标 | AlibabaCloudResourceMeasure 类型,可为 |
返回值:Bool - 接口调用是否成功,true 表示调用成功,false 表示调用失败。
使用示例:
// Swift - 创建性能指标对象
let measure = AlibabaCloudResourceMeasure.measure()
measure.duration = 850
measure.size = 10240
measure.dnsDuration = 30
measure.connectDuration = 80
measure.sslDuration = 120
measure.firstByteDuration = 250
measure.downloadDuration = 370
// 创建链路追踪上下文
let traceId = AlibabaCloudTraceGenerator.generateTraceId(.SkywalkingV3)
let spanId = AlibabaCloudTraceGenerator.generateTraceId(.SkywalkingV3)
let tracing = AlibabaCloudTracingContext(traceId: traceId, spanId: spanId, tracingProtocol: .SkywalkingV3)
// 上报完整的资源信息
let result = AlibabaCloudRUM.setCustomResource(
"HTTPS",
success: true,
url: "https://api.example.com/v2/data",
method: "POST",
statusCode: 200,
errorMessage: nil,
provider: "Aliyun",
tracing: tracing,
measure: measure
)// Objective-C - 创建性能指标对象
AlibabaCloudResourceMeasure *measure = [AlibabaCloudResourceMeasure measure];
measure.duration = 850;
measure.size = 10240;
measure.dnsDuration = 30;
measure.connectDuration = 80;
measure.sslDuration = 120;
measure.firstByteDuration = 250;
measure.downloadDuration = 370;
// 创建链路追踪上下文
NSString *traceId = [AlibabaCloudTracingGenerator generateTraceId:AlibabaCloudTracingProtocolW3C];
NSString *spanId = [AlibabaCloudTracingGenerator generateSpanId:AlibabaCloudTracingProtocolW3C];
AlibabaCloudTracingContext *tracing = [AlibabaCloudTracingContext contextWithTraceId:traceId
spanId:spanId
protocol:AlibabaCloudTracingProtocolW3C
];
// 上报完整的资源信息
BOOL result = [AlibabaCloudRUM setCustomResource:@"HTTPS"
success:YES
url:@"https://api.example.com/v2/data"
method:@"POST"
statusCode:200
errorMessage:nil
provider:@"Aliyun"
tracing:tracing
measure:measure];辅助类型说明
AlibabaCloudTracingContext
用于分布式链路追踪的上下文信息,支持 W3C Trace Context 和 SkyWalking V3 协议。
创建方法:
// Swift - 生成 TraceId 和 SpanId
let traceId = AlibabaCloudTracingGenerator.generateTraceId(.SkywalkingV3)
let spanId = AlibabaCloudTracingGenerator.generateSpanId(.SkywalkingV3)
// Swift - 生成 Trace 上下文
let tracingContext = AlibabaCloudTracingContext(traceId: traceId, spanId: spanId, protocol: .SkywalkingV3)// Objective-C - 生成 TraceId 和 SpanId
NSString *traceId = [AlibabaCloudTracingGenerator generateTraceId:AlibabaCloudTracingProtocolW3C];
NSString *spanId = [AlibabaCloudTracingGenerator generateSpanId:AlibabaCloudTracingProtocolW3C];
// Objective-C - 生成上下文
AlibabaCloudTracingContext *context = [AlibabaCloudTracingContext contextWithTraceId:traceId
spanId:spanId
tracingProtocol:AlibabaCloudTracingProtocolW3C
];支持的协议:
W3C:W3C Trace Context 标准协议。SkywalkingV3:Apache SkyWalking V3 协议。
AlibabaCloudResourceMeasure
用于记录网络请求性能指标。
属性名 | 类型 | 说明 |
duration | NSUInteger | 总耗时(毫秒) |
size | NSUInteger | 响应数据大小(字节) |
connectDuration | NSUInteger | TCP 连接耗时(毫秒) |
sslDuration | NSUInteger | SSL/TLS 握手耗时(毫秒) |
dnsDuration | NSUInteger | DNS 解析耗时(毫秒) |
redirectDuration | NSUInteger | 重定向耗时(毫秒) |
firstByteDuration | NSUInteger | 首字节耗时(毫秒) |
downloadDuration | NSUInteger | 下载耗时(毫秒) |
创建方法:
// Swift
let measure = AlibabaCloudResourceMeasure.measure()
measure.duration = 1200
measure.size = 5120
measure.dnsDuration = 50
measure.connectDuration = 100
measure.sslDuration = 150
measure.firstByteDuration = 300
measure.downloadDuration = 600// Objective-C
AlibabaCloudResourceMeasure *measure = [AlibabaCloudResourceMeasure measure];
measure.duration = 1200;
measure.size = 5120;
measure.dnsDuration = 50;
measure.connectDuration = 100;
measure.sslDuration = 150;
measure.firstByteDuration = 300;
measure.downloadDuration = 600;注意事项
返回值检查:建议检查方法返回值,如果返回
false,说明接口调用失败。异步上报:接口调用成功(返回
true)仅表示 SDK 已接受该数据,实际数据上报为异步操作。