本文翻译自外文文章。原文链接,原文发表于2021-05-10
前言
很长一段时间内,相比web应用,iOS应用被认为非常轻量,不用考虑性能问题。然而事到如今,iOS应用原来越大、越来越复杂、表面下的工作越来越多。远程监控你的应用如何在不同的设备上运行,显得尤为重要。
一些iOS监控工具已经存在好久了。例如,你可以获知当前设备运行正在使用WiFi还是蜂窝网。还有很多的第三方工具,如Firebase、New Relic,可以帮助你知晓用户真正的体验是什么样的。
有很多信息可以用来帮助iOS开发者。苹果在iOS 13推出了MetricKit,使得从设备获取诊断信息以及远程监控更加容易。在这份指导中,你可以使用Xcode来接收诊断信息,从而探索MetricKit APIs.
了解MetircKit
有了MetricKit,你可以从操作系统获取物理硬件的诊断信息。MetricKit每24小时发送一份JSON格式的运维数据。你可以将数据传送给你的服务器。之后你可以对数据进行可视化和分享,从而改进你的iOS应用。
iOS 14新增API
MetricKit在iOS 14有了很多重大改进。
首先,退出了一个全新payload类型MXDiagnosticPayload
,而在此之前只有MXMetricPayload
一种类型。MXDiagnosticPayload
提供更多信息,如crashes和exceptions。
另外,苹果退出了一种新的metric,叫MXAppExitMetric
,代表了iOS应用进程退出类型,帮你知晓用户为啥退出应用以及应用在退出时的状态。
开始
可以在原文链接中下载本文所用材料。
材料是一个名为Shopping Trolley的应用,展示一个水果购物列表。
注意:MetricKit只能运行在真机上,不支持模拟器。所以需要一个真实设备才能运行材料里的工程。
打开ShoppingListTableViewController.swift,加上如下一行:
import MetricKit
现在,你就可以访问MetricKit framework了。
将下面的代码添加到viewDidLoad()中:
let metricManager = MXMetricManager.shared
metricManager.add(self)
这会访问framework提供的MetricManager
。之后添加self
,也就是将ShoppingListTableViewController
作为metricManager的订阅者,从而收听到系统的metrics payload。
接下来,你需要在ShoppingListTableViewController.swift末尾加上如下代码:
extension ShoppingListTableViewController: MXMetricManagerSubscriber {
func didReceive(_ payloads: [MXMetricPayload]) {
guard let firstPayload = payloads.first else { return }
print(firstPayload.dictionaryRepresentation())
}
func didReceive(_ payloads: [MXDiagnosticPayload]) {
guard let firstPayload = payloads.first else { return }
print(firstPayload.dictionaryRepresentation())
}
}
为ShoppingListTableViewController添加一个extention以遵循MXMetricManagerSubscriber
,这个协议有两个方法从MetricKit接收payload。在本例中,收到payload之后仅仅做了打印。在实际使用中,可以将它们上传到到你的服务器。
理解 MetricKit API
Framework接口都非常简单直接,包括: - 一个manager类和订阅协议 - 每个metric和诊断都有一个类 - payload类 - 度量单位的类,如cellular bar - 展示数据的类,如直方图
理解MXMetricManager
MXMetricManager是MetricKit的核心。这是一个共享对象,用来管理订阅以接收来自硬件的metric日报。
访问MXMetricManager单例后,MetricKit开始为你的应用收集报告。你需要调用add:
方法,并传入实现了MXMetricManagerSubscriber
协议的类来启动接收metric报告。
系统每天至多发送一份报告。每份报告包含了过去24小时内的metric。如果之前报告周期内有发送失败的数据,也会一并包含在本次报告里。
Manager还提供remove:
方法,通过此方法可以随时移除订阅。
实现MXSignpostMetric
使用MetricKit的一大好处是,你可以将自己的metric放进那些苹果提供了“out of box”的应用。这点非常强大,你可以在报告中添加自定义的metric,能让你对性能有更深的探索。
当用户加载ShoppingListTableViewController
时我们添加一个自定义metric:
let fruitsLogHandle = MXMetricManager.makeLogHandle(category: "Fruits")
上面的代码会生成一个handle,类似一个桶,用于装载你的metric。
在viewDidLoad()方法中添加下面的代码:
mxSignpost(
.event,
log: fruitsLogHandle,
name: "Loading Fruits TableViewController")
当ViewController加载完成时,mxSignpost
向fruitsLogHandle内记录了一个自定义metric。这是一个很简单的实例,你自己去扩展。例如,你的应用有一个视频播放器,在流开始和结束时做记录。
实现MXMetricPayload
你可以从Metric中获取两个不同的payload。MXMetricPayload
封装了每日的metric报告。注:必须在真机上才能收到报告。如果你没有真机,我们为你提供了一个示例JSON。
在真机上将工程运行起来之后,在Xcode中点击 Debug ▸ Simulate MetricKit Payloads:
上图中的点击会触发一个示例日报。你可以在控制台中看到打印出的两个payload。
AnyHashable("cellularConditionMetrics"): {
cellConditionTime = {
histogramNumBuckets = 3;
histogramValue = {
0 = {
bucketCount = 20;
bucketEnd = "1 bars";
bucketStart = "1 bars";
};
1 = {
bucketCount = 30;
bucketEnd = "2 bars";
bucketStart = "2 bars";
};
2 = {
bucketCount = 50;
bucketEnd = "3 bars";
bucketStart = "3 bars";
};
};
};
上面的输出来自cellularConditionMetrics
payload。payload的这个部分提供了用户过去24小时内使用你App时的蜂窝网环境数据。代码还告诉你处于一个bar、两个bar、三个bar服务的次数。你可以使用bucketCount
来绘制直方图。这对于知晓用户在特定信号bar上持续的平均时间将非常有用。
理解MXDiagnosticPayload
MXDiagnosticPayload封装了如下设备诊断信息:
- 性能:crash和exception报告
- 响应:应用挂起率
- 磁盘访问:磁盘读写
[AnyHashable("crashDiagnostics"): <__NSArrayM 0x283764390>(
{
callStackTree = {
callStackPerThread = 1;
callStacks = (
{
callStackRootFrames = (
{
address = 74565;
binaryName = testBinaryName;
binaryUUID = "BE6FD323-B011-4E67-925B-A60362A1ADFA";
offsetIntoBinaryTextSegment = 123;
sampleCount = 20;
}
);
threadAttributed = 1;
}
);
};
diagnosticMetaData = {
appBuildVersion = 1;
appVersion = "1.0";
deviceType = "iPhone13,3";
exceptionCode = 0;
exceptionType = 1;
osVersion = "iPhone OS 14.4 (18D52)";
platformArchitecture = arm64e;
regionFormat = GB;
signal = 11;
terminationReason = "Namespace SIGNAL, Code 0xb";
virtualMemoryRegionInfo = "0 is not in any region. Bytes before following region: 4000000000 REGION TYPE START - END [ VSIZE] PRT/MAX SHRMOD REGION DETAIL UNUSED SPACE AT START ---> __TEXT 0000000000000000-0000000000000000 [ 32K] r-x/r-x SM=COW ...pp/Test";
};
version = "1.0.0";
}
上面的输出来自crashDiagnostics
,捕捉到一个用户遇到的crash。其中diagnosticMetaData
包含了系统版本号等有用信息。因为捕捉到的是个crash,所以数据还包含了callStackTree
,下一节将对此做更进一步的说明。
理解MXCallStackTree
对MetricKit探索得越多,你越会发现它对于苹果自带工具有很大的增强,如Xcode Organizer。即使用户离开你的App,在Organizer页面仍旧可以看到MetricKit报告,即使你的App没有引入MetricKit。
如你所见(上图),这个App处于活跃状态并且在Xcode右侧能看到真实数据。因为苹果免费提供了很多数据。不过,要是再能引入MetricKit的话,你就能更充分的利用这些数据并且将它们与你自己的metric关联、更灵活的展示数据。
MXCallStackTree
是使用MetricKit的一大好处,不仅可以知晓crash和exception,还能获得JSON格式的StackTree。对于解决bug非常有帮助。
理解MXAppExitMetric
MXAppExitMetric是iOS14引入的,App退出类型包括:
- 前台退出
- 后台退出
用户退出App的原因有很多。有时是用户有意关闭App,有时是操作系统关闭了App,或是低内存和exception导致App退出。
在Organizer里查阅
苹果在Organizer里提供免费的可视化数据,数据来自于App Store Connect。
尽管你在Organizer里无法获取到使用MetricKit时那么全的数据,但还是能获取到这些: Crash
- 写磁盘
- 电量使用
- 电池使用
- 挂起率
- 加载时间
- 内存
- 滚动
创建表格和报告
上面章节中的内容都可以表现为表格。通常,数据以直方图表示。
上图是一个Scrolling metric的直方图,展示了用户开始滚动的时间。上图中,可以看到在持续下降后,数据突然飙升。也许你应当研究下这个现象的原因,以及为何版本间有如此差异。
上图是一个在App Store上线的App的真实数据。数据有很多细节。你可以看到不同因素对于用电量的影响:Networking、Display等。上图示例中,该App耗电量占每天总量的8.29% 虽然数据不能给出准确的基准值,但是可以给你很多性能改进的依据。
Comments
comments powered by Disqus