metrickit-diagnostics

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

MetricKit Diagnostics

MetricKit 诊断指南

Collect aggregated performance metrics and crash diagnostics from production devices using MetricKit. The framework delivers daily metric payloads (CPU, memory, launch time, hang rate, animation hitches, network usage) and immediate diagnostic payloads (crashes, hangs, disk-write exceptions) with full call-stack trees for triage.
使用MetricKit从生产环境设备收集聚合的性能指标与崩溃诊断信息。该框架每日推送指标载荷(包含CPU、内存、启动时间、卡顿率、动画掉帧、网络使用情况),并实时推送诊断载荷(包含崩溃、卡顿、磁盘写入异常),且附带完整调用栈树用于问题排查。

Contents

目录

Subscriber Setup

订阅者配置

Register a subscriber as early as possible — ideally in
application(_:didFinishLaunchingWithOptions:)
or
App.init
. MetricKit starts accumulating reports after the first access to
MXMetricManager.shared
.
swift
import MetricKit

final class MetricsSubscriber: NSObject, MXMetricManagerSubscriber {
    static let shared = MetricsSubscriber()

    func subscribe() {
        MXMetricManager.shared.add(self)
    }

    func unsubscribe() {
        MXMetricManager.shared.remove(self)
    }

    func didReceive(_ payloads: [MXMetricPayload]) {
        // Handle daily metrics
    }

    func didReceive(_ payloads: [MXDiagnosticPayload]) {
        // Handle diagnostics (crashes, hangs, disk writes)
    }
}
尽早注册订阅者——理想情况下在
application(_:didFinishLaunchingWithOptions:)
App.init
中完成。MetricKit在首次访问
MXMetricManager.shared
后开始累积报告。
swift
import MetricKit

final class MetricsSubscriber: NSObject, MXMetricManagerSubscriber {
    static let shared = MetricsSubscriber()

    func subscribe() {
        MXMetricManager.shared.add(self)
    }

    func unsubscribe() {
        MXMetricManager.shared.remove(self)
    }

    func didReceive(_ payloads: [MXMetricPayload]) {
        // 处理每日指标
    }

    func didReceive(_ payloads: [MXDiagnosticPayload]) {
        // 处理诊断信息(崩溃、卡顿、磁盘写入)
    }
}

UIKit Registration

UIKit 注册方式

swift
func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
    MetricsSubscriber.shared.subscribe()
    return true
}
swift
func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
    MetricsSubscriber.shared.subscribe()
    return true
}

SwiftUI Registration

SwiftUI 注册方式

swift
@main
struct MyApp: App {
    init() {
        MetricsSubscriber.shared.subscribe()
    }
    var body: some Scene {
        WindowGroup { ContentView() }
    }
}
swift
@main
struct MyApp: App {
    init() {
        MetricsSubscriber.shared.subscribe()
    }
    var body: some Scene {
        WindowGroup { ContentView() }
    }
}

Receiving Metric Payloads

接收指标载荷

MXMetricPayload
arrives approximately once per 24 hours containing aggregated metrics. The array may contain multiple payloads if prior deliveries were missed.
swift
func didReceive(_ payloads: [MXMetricPayload]) {
    for payload in payloads {
        let begin = payload.timeStampBegin
        let end = payload.timeStampEnd
        let version = payload.latestApplicationVersion

        // Persist raw JSON before processing
        let jsonData = payload.jsonRepresentation()
        persistPayload(jsonData, from: begin, to: end)

        processMetrics(payload)
    }
}
Availability:
MXMetricPayload
— iOS 13.0+, macOS 10.15+, visionOS 1.0+
MXMetricPayload
约每24小时推送一次,包含聚合后的指标数据。若之前有未推送的载荷,数组中可能包含多个条目。
swift
func didReceive(_ payloads: [MXMetricPayload]) {
    for payload in payloads {
        let begin = payload.timeStampBegin
        let end = payload.timeStampEnd
        let version = payload.latestApplicationVersion

        // 处理前先持久化原始JSON
        let jsonData = payload.jsonRepresentation()
        persistPayload(jsonData, from: begin, to: end)

        processMetrics(payload)
    }
}
兼容性
MXMetricPayload
— iOS 13.0+, macOS 10.15+, visionOS 1.0+

Receiving Diagnostic Payloads

接收诊断载荷

MXDiagnosticPayload
delivers crash, hang, CPU exception, disk-write, and app-launch diagnostics. On iOS 15+ and macOS 12+, diagnostics arrive immediately rather than bundled with the daily report.
swift
func didReceive(_ payloads: [MXDiagnosticPayload]) {
    for payload in payloads {
        let jsonData = payload.jsonRepresentation()
        persistPayload(jsonData)

        if let crashes = payload.crashDiagnostics {
            for crash in crashes {
                handleCrash(crash)
            }
        }
        if let hangs = payload.hangDiagnostics {
            for hang in hangs {
                handleHang(hang)
            }
        }
        if let diskWrites = payload.diskWriteExceptionDiagnostics {
            for diskWrite in diskWrites {
                handleDiskWrite(diskWrite)
            }
        }
        if let cpuExceptions = payload.cpuExceptionDiagnostics {
            for cpuException in cpuExceptions {
                handleCPUException(cpuException)
            }
        }
        if let launchDiags = payload.appLaunchDiagnostics {
            for launchDiag in launchDiags {
                handleSlowLaunch(launchDiag)
            }
        }
    }
}
Availability:
MXDiagnosticPayload
— iOS 14.0+, macOS 12.0+, visionOS 1.0+
MXDiagnosticPayload
推送崩溃、卡顿、CPU异常、磁盘写入及应用启动诊断信息。在iOS 15+和macOS 12+系统中,诊断信息会实时推送,而非与每日报告捆绑发送。
swift
func didReceive(_ payloads: [MXDiagnosticPayload]) {
    for payload in payloads {
        let jsonData = payload.jsonRepresentation()
        persistPayload(jsonData)

        if let crashes = payload.crashDiagnostics {
            for crash in crashes {
                handleCrash(crash)
            }
        }
        if let hangs = payload.hangDiagnostics {
            for hang in hangs {
                handleHang(hang)
            }
        }
        if let diskWrites = payload.diskWriteExceptionDiagnostics {
            for diskWrite in diskWrites {
                handleDiskWrite(diskWrite)
            }
        }
        if let cpuExceptions = payload.cpuExceptionDiagnostics {
            for cpuException in cpuExceptions {
                handleCPUException(cpuException)
            }
        }
        if let launchDiags = payload.appLaunchDiagnostics {
            for launchDiag in launchDiags {
                handleSlowLaunch(launchDiag)
            }
        }
    }
}
兼容性
MXDiagnosticPayload
— iOS 14.0+, macOS 12.0+, visionOS 1.0+

Key Metrics

核心指标

Launch Time — MXAppLaunchMetric

启动时间 — MXAppLaunchMetric

swift
if let launch = payload.applicationLaunchMetrics {
    let firstDraw = launch.histogrammedTimeToFirstDraw
    let optimized = launch.histogrammedOptimizedTimeToFirstDraw
    let resume = launch.histogrammedApplicationResumeTime
    let extended = launch.histogrammedExtendedLaunch
}
swift
if let launch = payload.applicationLaunchMetrics {
    let firstDraw = launch.histogrammedTimeToFirstDraw
    let optimized = launch.histogrammedOptimizedTimeToFirstDraw
    let resume = launch.histogrammedApplicationResumeTime
    let extended = launch.histogrammedExtendedLaunch
}

Run Time — MXAppRunTimeMetric

运行时间 — MXAppRunTimeMetric

swift
if let runTime = payload.applicationTimeMetrics {
    let fg = runTime.cumulativeForegroundTime    // Measurement<UnitDuration>
    let bg = runTime.cumulativeBackgroundTime
    let bgAudio = runTime.cumulativeBackgroundAudioTime
    let bgLocation = runTime.cumulativeBackgroundLocationTime
}
swift
if let runTime = payload.applicationTimeMetrics {
    let fg = runTime.cumulativeForegroundTime    // Measurement<UnitDuration>
    let bg = runTime.cumulativeBackgroundTime
    let bgAudio = runTime.cumulativeBackgroundAudioTime
    let bgLocation = runTime.cumulativeBackgroundLocationTime
}

CPU, Memory, and Responsiveness

CPU、内存与响应性

swift
if let cpu = payload.cpuMetrics {
    let cpuTime = cpu.cumulativeCPUTime              // Measurement<UnitDuration>
}
if let memory = payload.memoryMetrics {
    let peakMemory = memory.peakMemoryUsage           // Measurement<UnitInformationStorage>
}
if let responsiveness = payload.applicationResponsivenessMetrics {
    let hangTime = responsiveness.histogrammedApplicationHangTime
}
if let animation = payload.animationMetrics {
    let scrollHitchRate = animation.scrollHitchTimeRatio  // Measurement<Unit>
}
swift
if let cpu = payload.cpuMetrics {
    let cpuTime = cpu.cumulativeCPUTime              // Measurement<UnitDuration>
}
if let memory = payload.memoryMetrics {
    let peakMemory = memory.peakMemoryUsage           // Measurement<UnitInformationStorage>
}
if let responsiveness = payload.applicationResponsivenessMetrics {
    let hangTime = responsiveness.histogrammedApplicationHangTime
}
if let animation = payload.animationMetrics {
    let scrollHitchRate = animation.scrollHitchTimeRatio  // Measurement<Unit>
}

Network and Cellular

网络与蜂窝数据

swift
if let network = payload.networkTransferMetrics {
    let wifiUp = network.cumulativeWifiUpload          // Measurement<UnitInformationStorage>
    let wifiDown = network.cumulativeWifiDownload
    let cellUp = network.cumulativeCellularUpload
    let cellDown = network.cumulativeCellularDownload
}
swift
if let network = payload.networkTransferMetrics {
    let wifiUp = network.cumulativeWifiUpload          // Measurement<UnitInformationStorage>
    let wifiDown = network.cumulativeWifiDownload
    let cellUp = network.cumulativeCellularUpload
    let cellDown = network.cumulativeCellularDownload
}

App Exit Metrics

应用退出指标

swift
if let exits = payload.applicationExitMetrics {
    let fg = exits.foregroundExitData
    let bg = exits.backgroundExitData
    // Inspect normal, abnormal, watchdog, memory, etc.
}
swift
if let exits = payload.applicationExitMetrics {
    let fg = exits.foregroundExitData
    let bg = exits.backgroundExitData
    // 检查正常退出、异常退出、看门狗终止、内存不足等情况
}

Call Stack Trees

调用栈树

MXCallStackTree
is attached to each diagnostic (crash, hang, CPU exception, disk write, app launch). Use
jsonRepresentation()
to extract and symbolicate.
swift
func handleCrash(_ crash: MXCrashDiagnostic) {
    let tree = crash.callStackTree
    let treeJSON = tree.jsonRepresentation()

    let exceptionType = crash.exceptionType
    let signal = crash.signal
    let reason = crash.terminationReason

    uploadDiagnostic(
        type: "crash",
        exceptionType: exceptionType,
        signal: signal,
        reason: reason,
        callStack: treeJSON
    )
}

func handleHang(_ hang: MXHangDiagnostic) {
    let tree = hang.callStackTree
    let duration = hang.hangDuration  // Measurement<UnitDuration>
    uploadDiagnostic(type: "hang", duration: duration, callStack: tree.jsonRepresentation())
}
The JSON structure contains an array of call stack frames with binary name, offset, and address. Symbolicate using
atos
or upload dSYMs to your analytics service.
Availability:
MXCallStackTree
— iOS 14.0+, macOS 12.0+, visionOS 1.0+
MXCallStackTree
会附加到每个诊断信息(崩溃、卡顿、CPU异常、磁盘写入、应用启动)中。使用
jsonRepresentation()
提取并符号化数据。
swift
func handleCrash(_ crash: MXCrashDiagnostic) {
    let tree = crash.callStackTree
    let treeJSON = tree.jsonRepresentation()

    let exceptionType = crash.exceptionType
    let signal = crash.signal
    let reason = crash.terminationReason

    uploadDiagnostic(
        type: "crash",
        exceptionType: exceptionType,
        signal: signal,
        reason: reason,
        callStack: treeJSON
    )
}

func handleHang(_ hang: MXHangDiagnostic) {
    let tree = hang.callStackTree
    let duration = hang.hangDuration  // Measurement<UnitDuration>
    uploadDiagnostic(type: "hang", duration: duration, callStack: tree.jsonRepresentation())
}
JSON结构包含一组调用栈帧,包含二进制名称、偏移量和地址。可使用
atos
工具或上传dSYM文件至分析服务进行符号化。
兼容性
MXCallStackTree
— iOS 14.0+, macOS 12.0+, visionOS 1.0+

Custom Signpost Metrics

自定义Signpost指标

Use
mxSignpost
with a MetricKit log handle to capture custom performance intervals. These appear in the daily
MXMetricPayload
under
signpostMetrics
.
结合MetricKit日志句柄使用
mxSignpost
捕获自定义性能区间。这些指标会出现在每日
MXMetricPayload
signpostMetrics
字段中。

Creating a Log Handle

创建日志句柄

swift
let metricLog = MXMetricManager.makeLogHandle(category: "Networking")
swift
let metricLog = MXMetricManager.makeLogHandle(category: "Networking")

Emitting Signposts

发送Signpost

swift
import os

func fetchData() async throws -> Data {
    let signpostID = MXSignpostIntervalData.makeSignpostID(log: metricLog)

    mxSignpost(.begin, log: metricLog, name: "DataFetch", signpostID: signpostID)
    let data = try await URLSession.shared.data(from: url).0
    mxSignpost(.end, log: metricLog, name: "DataFetch", signpostID: signpostID)

    return data
}
swift
import os

func fetchData() async throws -> Data {
    let signpostID = MXSignpostIntervalData.makeSignpostID(log: metricLog)

    mxSignpost(.begin, log: metricLog, name: "DataFetch", signpostID: signpostID)
    let data = try await URLSession.shared.data(from: url).0
    mxSignpost(.end, log: metricLog, name: "DataFetch", signpostID: signpostID)

    return data
}

Reading Custom Metrics from Payload

从载荷中读取自定义指标

swift
if let signposts = payload.signpostMetrics {
    for metric in signposts {
        let name = metric.signpostName       // "DataFetch"
        let category = metric.signpostCategory // "Networking"
        let count = metric.totalCount
        if let intervalData = metric.signpostIntervalData {
            let avgMemory = intervalData.averageMemory
            let cumulativeCPUTime = intervalData.cumulativeCPUTime
        }
    }
}
The system limits the number of custom signpost metrics per log to reduce on-device overhead. Reserve custom metrics for critical code paths.
swift
if let signposts = payload.signpostMetrics {
    for metric in signposts {
        let name = metric.signpostName       // "DataFetch"
        let category = metric.signpostCategory // "Networking"
        let count = metric.totalCount
        if let intervalData = metric.signpostIntervalData {
            let avgMemory = intervalData.averageMemory
            let cumulativeCPUTime = intervalData.cumulativeCPUTime
        }
    }
}
系统会限制每个日志的自定义Signpost指标数量,以降低设备端开销。请仅为关键代码路径添加自定义指标。

Exporting and Uploading Payloads

载荷导出与上传

Both payload types conform to
NSSecureCoding
and provide
jsonRepresentation()
for easy serialization.
swift
func persistPayload(_ jsonData: Data, from: Date? = nil, to: Date? = nil) {
    let fileName = "metrics_\(ISO8601DateFormatter().string(from: Date())).json"
    let url = FileManager.default.temporaryDirectory.appending(path: fileName)
    try? jsonData.write(to: url)
}

func uploadPayloads(_ jsonData: Data) {
    Task.detached(priority: .utility) {
        var request = URLRequest(url: URL(string: "https://api.example.com/metrics")!)
        request.httpMethod = "POST"
        request.setValue("application/json", forHTTPHeaderField: "Content-Type")
        request.httpBody = jsonData
        _ = try? await URLSession.shared.data(for: request)
    }
}
两种载荷类型均遵循
NSSecureCoding
协议,并提供
jsonRepresentation()
方法用于序列化。
swift
func persistPayload(_ jsonData: Data, from: Date? = nil, to: Date? = nil) {
    let fileName = "metrics_\(ISO8601DateFormatter().string(from: Date())).json"
    let url = FileManager.default.temporaryDirectory.appending(path: fileName)
    try? jsonData.write(to: url)
}

func uploadPayloads(_ jsonData: Data) {
    Task.detached(priority: .utility) {
        var request = URLRequest(url: URL(string: "https://api.example.com/metrics")!)
        request.httpMethod = "POST"
        request.setValue("application/json", forHTTPHeaderField: "Content-Type")
        request.httpBody = jsonData
        _ = try? await URLSession.shared.data(for: request)
    }
}

Retrieving Past Payloads

检索历史载荷

If the subscriber was not registered when payloads arrived, retrieve them using
pastPayloads
and
pastDiagnosticPayloads
. These return reports generated since the last allocation of the shared manager.
swift
let pastMetrics = MXMetricManager.shared.pastPayloads
let pastDiags = MXMetricManager.shared.pastDiagnosticPayloads
若注册订阅者时已有载荷推送,可使用
pastPayloads
pastDiagnosticPayloads
检索这些数据。它们会返回自共享管理器上次分配以来生成的报告。
swift
let pastMetrics = MXMetricManager.shared.pastPayloads
let pastDiags = MXMetricManager.shared.pastDiagnosticPayloads

Extended Launch Measurement

扩展启动时间测量

Track post-first-draw setup work (loading databases, restoring state) as part of the launch metric using extended launch measurement.
swift
let taskID = MXLaunchTaskID("com.example.app.loadDatabase")

MXMetricManager.shared.extendLaunchMeasurement(forTaskID: taskID)
// Perform extended launch work...
await database.load()
MXMetricManager.shared.finishExtendedLaunchMeasurement(forTaskID: taskID)
Extended launch times appear under
histogrammedExtendedLaunch
in
MXAppLaunchMetric
.
使用扩展启动时间测量功能,将首次绘制后的设置工作(如加载数据库、恢复状态)纳入启动指标。
swift
let taskID = MXLaunchTaskID("com.example.app.loadDatabase")

MXMetricManager.shared.extendLaunchMeasurement(forTaskID: taskID)
// 执行扩展启动工作...
await database.load()
MXMetricManager.shared.finishExtendedLaunchMeasurement(forTaskID: taskID)
扩展启动时间会显示在
MXAppLaunchMetric
histogrammedExtendedLaunch
字段中。

Xcode Organizer Integration

Xcode Organizer集成

Xcode Organizer shows the same MetricKit data aggregated across all users who have opted in to share diagnostics. Use Organizer for trend analysis:
  • Metrics tab: Battery, performance, and disk-write metrics over time
  • Regressions tab: Automatic detection of metric regressions per version
  • Crashes tab: Crash logs with symbolicated stack traces
MetricKit on-device collection complements Organizer by letting you route raw data to your own backend for custom dashboards, alerting, and filtering by user cohort.
Xcode Organizer会展示所有选择共享诊断信息的用户的MetricKit聚合数据。可使用Organizer进行趋势分析:
  • 指标标签页:电池、性能与磁盘写入指标的时间趋势
  • 回归标签页:自动检测各版本的指标回归情况
  • 崩溃标签页:带有符号化栈追踪的崩溃日志
设备端MetricKit收集的数据与Organizer互补,可将原始数据发送至自有后端,用于自定义仪表盘、告警及用户群体筛选。

Common Mistakes

常见错误

DON'T: Subscribe to MXMetricManager too late

错误做法:过晚订阅MXMetricManager

The system may deliver pending payloads shortly after launch. Subscribing late (e.g., in a view controller) risks missing them entirely.
swift
// WRONG — subscribing in a view controller
override func viewDidLoad() {
    super.viewDidLoad()
    MXMetricManager.shared.add(self)
}

// CORRECT — subscribe in application(_:didFinishLaunchingWithOptions:)
func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions opts: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
    MXMetricManager.shared.add(metricsSubscriber)
    return true
}
系统可能在启动后不久推送待处理载荷。若过晚订阅(如在视图控制器中),可能会完全错过这些载荷。
swift
// 错误示例——在视图控制器中订阅
override func viewDidLoad() {
    super.viewDidLoad()
    MXMetricManager.shared.add(self)
}

// 正确示例——在application(_:didFinishLaunchingWithOptions:)中订阅
func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions opts: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
    MXMetricManager.shared.add(metricsSubscriber)
    return true
}

DON'T: Ignore MXDiagnosticPayload

错误做法:忽略MXDiagnosticPayload

Only handling
MXMetricPayload
means you miss crash, hang, and disk-write diagnostics — the most actionable data MetricKit provides.
swift
// WRONG — only implementing metric callback
func didReceive(_ payloads: [MXMetricPayload]) { /* ... */ }

// CORRECT — implement both callbacks
func didReceive(_ payloads: [MXMetricPayload]) { /* ... */ }
func didReceive(_ payloads: [MXDiagnosticPayload]) { /* ... */ }
仅处理
MXMetricPayload
会错过崩溃、卡顿和磁盘写入诊断信息——这些是MetricKit提供的最具可操作性的数据。
swift
// 错误示例——仅实现指标回调
func didReceive(_ payloads: [MXMetricPayload]) { /* ... */ }

// 正确示例——实现两个回调
func didReceive(_ payloads: [MXMetricPayload]) { /* ... */ }
func didReceive(_ payloads: [MXDiagnosticPayload]) { /* ... */ }

DON'T: Process payloads without persisting first

错误做法:未持久化就处理载荷

The system delivers each payload once. If your subscriber crashes during processing, the data is lost permanently.
swift
// WRONG — process inline, crash loses data
func didReceive(_ payloads: [MXDiagnosticPayload]) {
    for p in payloads {
        riskyProcessing(p)  // If this crashes, payload is gone
    }
}

// CORRECT — persist raw JSON first, then process
func didReceive(_ payloads: [MXDiagnosticPayload]) {
    for p in payloads {
        let json = p.jsonRepresentation()
        try? json.write(to: localCacheURL())   // Safe on disk
        Task.detached { self.processAsync(json) }
    }
}
系统仅推送每个载荷一次。若订阅者在处理过程中崩溃,数据会永久丢失。
swift
// 错误示例——直接处理,崩溃会丢失数据
func didReceive(_ payloads: [MXDiagnosticPayload]) {
    for p in payloads {
        riskyProcessing(p)  // 若此处崩溃,载荷将丢失
    }
}

// 正确示例——先持久化原始JSON,再处理
func didReceive(_ payloads: [MXDiagnosticPayload]) {
    for p in payloads {
        let json = p.jsonRepresentation()
        try? json.write(to: localCacheURL())   // 安全存储到磁盘
        Task.detached { self.processAsync(json) }
    }
}

DON'T: Do heavy work synchronously in didReceive

错误做法:在didReceive中同步执行繁重工作

The callback runs on an arbitrary thread. Blocking it with heavy processing or synchronous network calls delays delivery of subsequent payloads.
swift
// WRONG — synchronous upload in callback
func didReceive(_ payloads: [MXMetricPayload]) {
    for p in payloads {
        let data = p.jsonRepresentation()
        URLSession.shared.uploadTask(with: request, from: data).resume()  // sync wait
    }
}

// CORRECT — persist and dispatch async
func didReceive(_ payloads: [MXMetricPayload]) {
    for p in payloads {
        let json = p.jsonRepresentation()
        persistLocally(json)
        Task.detached(priority: .utility) {
            await self.uploadToBackend(json)
        }
    }
}
回调运行在任意线程。若在此处执行繁重处理或同步网络请求,会延迟后续载荷的推送。
swift
// 错误示例——在回调中同步上传
func didReceive(_ payloads: [MXMetricPayload]) {
    for p in payloads {
        let data = p.jsonRepresentation()
        URLSession.shared.uploadTask(with: request, from: data).resume()  // 同步等待
    }
}

// 正确示例——持久化后异步分发
func didReceive(_ payloads: [MXMetricPayload]) {
    for p in payloads {
        let json = p.jsonRepresentation()
        persistLocally(json)
        Task.detached(priority: .utility) {
            await self.uploadToBackend(json)
        }
    }
}

DON'T: Expect immediate data in development

错误做法:在开发环境中期望立即获取数据

MetricKit aggregates data over 24-hour windows. Payloads do not arrive immediately after instrumenting. Use Xcode Organizer or simulated payloads for faster iteration during development.
MetricKit会在24小时窗口内聚合数据。 instrumentation后不会立即推送载荷。开发期间可使用Xcode Organizer或模拟载荷加快迭代速度。

Review Checklist

检查清单

  • MXMetricManager.shared.add(subscriber)
    called in
    application(_:didFinishLaunchingWithOptions:)
    or
    App.init
  • Subscriber conforms to
    MXMetricManagerSubscriber
    and inherits
    NSObject
  • Both
    didReceive(_: [MXMetricPayload])
    and
    didReceive(_: [MXDiagnosticPayload])
    implemented
  • Raw
    jsonRepresentation()
    persisted to disk before processing
  • Heavy processing dispatched asynchronously off the callback thread
  • MXCallStackTree
    JSON uploaded with dSYMs for symbolication
  • Custom signpost metrics limited to critical code paths
  • pastPayloads
    and
    pastDiagnosticPayloads
    checked on launch for missed deliveries
  • Extended launch tasks call both
    extendLaunchMeasurement
    and
    finishExtendedLaunchMeasurement
  • Analytics backend accepts and stores MetricKit JSON format
  • Xcode Organizer reviewed for regression trends alongside on-device data
  • application(_:didFinishLaunchingWithOptions:)
    App.init
    中调用
    MXMetricManager.shared.add(subscriber)
  • 订阅者遵循
    MXMetricManagerSubscriber
    协议并继承自
    NSObject
  • 实现
    didReceive(_: [MXMetricPayload])
    didReceive(_: [MXDiagnosticPayload])
    两个方法
  • 处理前先将原始
    jsonRepresentation()
    持久化到磁盘
  • 将繁重处理异步分发到回调线程外执行
  • 上传
    MXCallStackTree
    JSON时附带dSYM文件以支持符号化
  • 仅为关键代码路径添加自定义Signpost指标
  • 启动时检查
    pastPayloads
    pastDiagnosticPayloads
    以获取遗漏的推送数据
  • 扩展启动任务同时调用
    extendLaunchMeasurement
    finishExtendedLaunchMeasurement
  • 分析后端支持接收并存储MetricKit JSON格式数据
  • 结合设备端数据,通过Xcode Organizer检查回归趋势

References

参考资料