PerformanceSuite
PerformanceSuite 是一个用于测量和收集 iOS 应用性能和质量指标的 iOS Swift 库。
与其他解决方案(如 MetricKit、Firebase Performance、Instabug、Sentry 等)相比,它提供额外的灵活性。然而,它专注于性能监控的原生部分。对于存储和可视化您的指标,构建监控图,以及设置警报,您需要有您自己的后端。
此库用于 主 Booking.com iOS 应用程序,该应用程序由数以百万计的用户每天使用。
我们还开源了类似的 Android PerformanceSuite 代码。
优点
- 性能事件实时传递到您的代码中,允许进行全面分析。
- 您可以在 A/B 测试中监控性能。
- 您具有构建任何实时性能图表,并设置自定义警报的灵活性。
缺点
- 需要一个自定义后端来收集指标,显示图表和设置警报。
支持的功能
- TTI(可交互时间)对屏幕的监控。
- 冻结时间渲染性能对屏幕的监控。
- 整体应用的冻结时间监控。
- 启动时间监控。
- 有堆栈跟踪的致命和非致命 挂起。
- 看门狗 终止(内存或CPU终止)。
- 记录所有UIKit控制器事件以简化调试。
Wiki 了解更多信息。
查阅我们的请注意,PerformanceSuite 当前不支持跟踪标准崩溃。您需要额外的工具来收集崩溃的堆栈跟踪(例如,Firebase Crashlytics)。
如何工作
PerformanceSuite
监控应在您的应用启动时激活,通过提供设置用于处理性能指标的的对象。随着您的应用继续运行,您将接收到回调以传递这些指标。
func startupTimeReceived(_ data: StartupTimeData) { ... }
func fatalHangReceived(info: HangInfo) { ... }
func nonFatalHangReceived(info: HangInfo) { ... }
func viewControllerLeakReceived(viewController: UIViewController) { ... }
func watchdogTerminationReceived(_ data: WatchdogTerminationData) { ... }
func appRenderingMetricsReceived(metrics: RenderingMetrics) { ... }
对于屏幕级指标,您应该返回 true
或 false
,以确定是否应该监控此特定的视图控制器对象
func shouldTrack(viewController: UIViewController) -> Bool { ... }
func ttiMetricsReceived(metrics: TTIMetrics, viewController: UIViewController) { ... }
func renderingMetricsReceived(metrics: RenderingMetrics, viewController: UIViewController) { ... }
SwiftUI 支持
PerformanceSuite 屏幕跟踪高度依赖 UIKit UIViewController 的生命周期。
对于纯SwiftUI应用程序,iOS仍然在底层创建UINavigationController
来执行导航,并且这些情况得到了PerformanceSuite的支持。
然而,那些在底层不创建任何UIHostingController
的自定义SwiftUI过渡目前还没有自动化。目前你可以使用片段TTI跟踪来处理这种情况下。如果对此有需求,我们可能会 later引入一些语法糖。
但是,对于大多数应用程序来说,当前的设置已经足够自动跟踪带有SwiftUI视图的UIHostingController
中的屏幕打开。详见使用方法部分。
安装
Swift Package Manager
- 在Xcode中,选择文件 > 添加包。
- 在“搜索或输入包URL”对话框中输入https://github.com/bookingcom/perfsuite-ios。
- 在下一页中选择“向上至下一个主版本”并指定最新版本。
- 在最后一页上,选择
PerformanceSuite
库并将其添加到您的目标中。 - 您的包依赖项将被添加到您的.xcodeproj文件中。
CocoaPods
要使用CocoaPods将PerformanceSuite
集成到您的Xcode项目中,请在Podfile中指定它
pod 'PerformanceSuite'
目前CocoaPods仓库遇到了索引新添加的Pod的问题,因此如果它不起作用,您可以指定源URL和标记
pod 'PerformanceSuite', :git => 'https://github.com/bookingcom/perfsuite-ios.git', :tag => '0.0.4' # use the last released version here
使用
要接收性能事件,您必须有实现以下协议之一的类
TTIMetricsReceiver
RenderingMetricsReceiver
AppRenderingMetricsReceiver
WatchDogTerminationsReceiver
HangsReceiver
ViewControllerLeaksReceiver
StartupTimeReceiver
ViewControllerLoggingReceiver
FragmentTTIMetricsReceiver
或者,您可以使用PerformanceSuiteMetricsReceiver
来接收所有事件。
应在应用程序的尽可能早的阶段开始性能监控。例如,您可以在application(application:didFinishLaunchingWithOptions:)
方法的开始处开始。
let metricsConsumer = MetricsConsumer()
try PerformanceMonitoring.enable(config: .all(receiver: metricsConsumer))
// or with more flexibility
let metricsConsumer = MetricsConsumer()
let config: Config = [
.screenLevelTTI(metricsConsumer),
.screenLevelRendering(metricsConsumer),
.appLevelRendering(metricsConsumer),
.hangs(metricsConsumer),
]
try PerformanceMonitoring.enable(
config: config,
// you may pass your own key-value storage
storage: KeyValueStorage.default,
// you may pass a flag if app did crash from Crashlytics
didCrashPreviously: didCrashPreviously
)
屏幕标识符
所有屏幕级别的指标都通过UIViewController
对象从PerformanceSuite发送到您的代码。要将视图控制器对象转换为字符串标识符,您可以采用以下方法
- 定义
PerformanceScreen
枚举,其中包含所有屏幕的屏幕标识符 - 定义协议
PerformanceTrackableScreen
,其中每个屏幕都应该返回此枚举 - 如果需要,添加对
UIHostingController
的SwiftUI支持
// We define enum with all our possible screens
// If you have too many screens, there can be several enums,
// or just a string identifier.
enum PerformanceScreen: String {
case search
case details
case checkout
}
// We define a protocol for screens to conform
protocol PerformanceTrackableScreen {
var performanceScreen: PerformanceScreen? { get }
}
// For view controllers it is easy, we just return which screen is this
extension SearchViewController: PerformanceTrackableScreen {
var performanceScreen: PerformanceScreen? { .search }
}
// If you have SwiftUI screens without corresponding custom `UIHostingController`,
// you will need to add introspection logic to find root views
// in any `UIHostingController` in the app.
//
// We should conform to this protocol in the topmost view of the screen.
//
// NB: if possible, better to use your own subclass for `UIHostingController`
// and implement `PerformanceTrackableScreen` only in your subclass.
// Otherwise it may be additional performance overhead to introspect
// all hosting controllers in the app
extension CheckoutScreenSwiftUIView: PerformanceTrackableScreen {
var performanceScreen: PerformanceScreen? { .checkout }
}
// We also need to implement the protocol in UIHostingController,
// So we can determine which is the SwiftUI view inside this controller.
extension UIHostingController: PerformanceTrackableScreen {
var performanceScreen: PerformanceScreen? {
return (introspectRootView() as? PerformanceTrackableScreen)?.performanceScreen
}
}
// In our metrics consumer we will receive UIViewController
// and should determine which screen is this.
class MetricsConsumer: TTIMetricsReceiver {
func shouldTrack(viewController: UIViewController) -> Bool {
(viewController as? PerformanceTrackableScreen)?.performanceScreen != nil
}
func ttiMetricsReceived(metrics: TTIMetrics, viewController: UIViewController) {
// find identifier for UIViewController
guard let performanceScreen = (viewController as? PerformanceTrackableScreen)?.performanceScreen else {
return
}
// send the event to your backend with this identifier
send(metric: "tti", value: metrics.tti.seconds, screen: performanceScreen.rawValue)
}
}
认可
该软件最初在Booking.com开发。经Booking.com批准,该软件以开源形式发布,作者们对此表示感谢。