MTHawkeye 0.12.8

MTHawkeye 0.12.8

MTHawkeyeEuan ChanHaowen Wu维护。



MTHawkeye 0.12.8

  • 美图Hawkeye团队

MTHawkeye

Platform License PRs Welcome Version CI

Readme中文版

MTHawkeye是美图用于iOS的性能分析和调试工具,它旨在帮助iOS开发者提高开发效率和优化App性能。

在App产品开发周期中,我们引入MTHawkeye以帮助我们发现、找到、分析、定位和解决问题,更快地解决问题。

  • 开发阶段,重点关注开发和调试辅助,及时发现问题,并提示开发人员处理。
  • 测试阶段,重点关注尽可能多地从测试案例中收集性能数据,生成自动化的测试分析报告。
  • 在线阶段,重点关注我们自己的业务所需但第三方APM组件中缺少的性能数据。

MTHawkeye内置了一些常用的性能检测插件。它还作为调试辅助插件引入并改进了FLEX。当您使用MTHawkeye时,您可以自定义和添加您需要的插件。

以下是一些内置插件的演示图,如查看主线程耗时方法查看App内存分配详情查看网络事务记录。有关更多插件说明,请参阅帖子。

0x00特性

MTHawkeye可以分为上层、中层和下层。除了底层的Base层,中层是UI骨架桌面适配器,最上层的插件根据不同的场景内部分割。您可以根据自己的场景选择性地添加这些插件。整体结构如下

MTHawkeye overall structure

基本功能

基层主要负责插件管理功能、存储API和实用类。

UI骨架为开发和测试阶段提供界面交互框架。它包括一个浮动窗口、主面板框架和设置面板,这些都可以进行修改,插件还可以集成界面交互。

可选插件

内置插件根据关注点分为内存耗时能耗网络图形存储实用

内存

# LivingObjectSniffer

LivingObjectSniffer主要用于跟踪和观察ViewController直接或间接持有的对象以及自定义View对象。检测这些对象是否意外存活,可能由于泄露、没有及时释放或不必要的内存缓冲区引起。

在开发和测试阶段,检测到的意外存活对象可以通过浮动窗口闪告或Toast的形式提醒开发者。

在自动化测试中,记录的意外存活对象也可以提取出来,以进行更深入的内存使用分析。

# Allocations

Allocations类似于Instrument的Allocations模块,它跟踪应用程序实际分配的内存细节。当应用程序内存使用异常(异常升高、OOM退出)时,记录的内存分配细节可以用来分析具体的内存使用问题。

耗时

ptom# UITimeProfiler

UITimeProfiler用于协助优化主线程耗时的任务。

数据收集部分主要包括两个组件,VC Life TraceObjC CallTrace。其中,VC Life Trace跟踪打开ViewController时每个关键节点的耗时时间,当开启ObjC CallTrace时,可以跟踪主线程上执行且耗时超过指定阈值的Objective-C方法。

界面层部分将这两部分数据结合,方便开发者查找关注操作中的耗时详情。示例图如前文所述,详细信息请参阅UITimeProfiler插件文档。

在自动化测试或线上阶段启用插件后,无需其他代码,即可持续自动化跟踪启动、页面打开等关键过程耗时。

ptom# ANRTrace

ANRTrace用于捕获卡顿事件,卡顿发生时将采样主线程堆栈帧。

ptom# FPSTrace

FPSTrace用于跟踪界面FPS和OpenGL刷新FPS,并在浮动窗口中显示当前值。

能量

# CPUTrace

CPUTrace用于追踪CPU的持续高负载使用情况,并记录在高负载CPU使用期间调用的主要方法。

# BackgroundTask Trace

BackgoundTask trace插件将追踪UIBackgroundTaskIdentifier的 begin/end,在尝试找出崩溃0xbada5e47的原因时非常有用。(请查看代码了解使用方法。)

网络

# NetworkMonitor

NetworkMonitor在App中观察和记录带有指标信息的HTTP(S)网络事务。为开发者提供内置记录查看界面,以便调试网络问题。

  1. 继承FLEX的网络记录逻辑,并优化初始化逻辑,通过在启动时挂钩,大大减少影响。
  2. 对于iOS 9之后的NSURLSession,添加URLSessionTaskMetrics记录,以查看事务每个阶段的用时。
  3. 基于事务指标添加类似于Chrome网络调试的水印视图,以查看网络事务的队列和并发性,并进行进一步优化。
  4. 添加检测重复的不必要网络事务的能力。
  5. 增强搜索栏以支持多条件搜索(主机过滤,状态过滤)
  6. 记录网络事务的请求头、请求体、响应体。
# NetworkInspect

NetworkInspect基于NetworkMonitor。根据网络事务的实际情况,根据检查规则检查网络请求是否可以改进,您也可以自行添加自己的检查规则。

图形

# OpenGLTrace

OpenGLTrace 用于跟踪 OpenGL 资源的内存使用情况,并帮助找到 OpenGL API 错误调用和异常参数传递。

存储

# DirectoryWatcher

DirectoryWatcher 用于跟踪指定沙箱文件夹的大小,它还集成了 FLEX 的沙箱文件浏览器。

实用工具

# FLEX

FLEX 常用于日常开发中,MTHawkeye 作为插件添加,并扩展了 AirDrop 用于沙箱文件的使用。

桌面扩展

如果您需要将插件扩展到桌面,例如查看和处理由插件在桌面上收集的数据,您可以基于每个插件提供的接口获取数据,然后将其桥接到第三方桌面客户端提供的协议。例如

0x01 使用

开发中使用

首先,将一个MTHawkeye引用添加到项目的podfile中

  #< Only used during Debug
  #< Since the podfile dependency doesn't support environment configuration, 
  #< the dependent pods also need to be explicitly configured as Debug.
  
  def hawkeye
    pod 'MTHawkeye', :configurations => 'Debug'

    pod 'FLEX', :configurations => ['Debug']
    pod 'FBRetainCycleDetector', :configurations => ['Debug']
    pod 'fishhook', :configurations => ['Debug']
    pod 'CocoaLumberjack',
    '3.6.0', :configurations => ['Debug'] # CocoaLumberjack is optional, change to `MTHawkeye/DefaultPluginsWithoutLog` if don't need.
    # pod 'MTGLDebug', :configurations => ['Debug'] # MTGLDebug is exclude by default, change `MTHawkeye` to `MTHawkeye/DefaultPlugins` to include.

    pod 'MTAppenderFile', :configurations => ['Debug']
  end

  target "YourProject" do
    hawkeye

    # ...
  end

注意:CocoaLumberjack必须 <~3.6.0

然后,在App启动时开启MTHawkeye服务,您可以使用所有默认插件,或者选择您需要启动的插件。

A: 快速集成所有默认插件并启动

#ifdef DEBUG
  #import <MTHawkeye/MTRunHawkeyeInOneLine.h>
#endif

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
#ifdef DEBUG
  [MTRunHawkeyeInOneLine start];
#endif
  // ...
}
B: 选择所需的插件,外部插入新插件
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  [self startCustomHawkeye];
  // ...
}

- (void)startCustomHawkeye {
#ifdef DEBUG
  [[MTHawkeyeClient shared]
    setPluginsSetupHandler:^(NSMutableArray<id<MTHawkeyePlugin>> *_Nonnull plugins) {
      [MTHawkeyeDefaultPlugins addDefaultClientPluginsInto:plugins];

      // add your additional plugins here.
    }
    pluginsCleanHandler:^(NSMutableArray<id<MTHawkeyePlugin>> *_Nonnull plugins) {
      // if you don't want to free plugins memory, remove this line.
      [MTHawkeyeDefaultPlugins cleanDefaultClientPluginsFrom:plugins];

      // clean your additional plugins if need.
    }];

  [[MTHawkeyeClient shared] startServer];

  [[MTHawkeyeUIClient shared]
    setPluginsSetupHandler:^(NSMutableArray<id<MTHawkeyeMainPanelPlugin>> *_Nonnull mainPanelPlugins, NSMutableArray<id<MTHawkeyeFloatingWidgetPlugin>> *_Nonnull floatingWidgetPlugins, NSMutableArray<id<MTHawkeyeSettingUIPlugin>> *_Nonnull defaultSettingUIPluginsInto) {
      [MTHawkeyeDefaultPlugins addDefaultUIClientMainPanelPluginsInto:mainPanelPlugins
                                    defaultFloatingWidgetsPluginsInto:floatingWidgetPlugins
                                          defaultSettingUIPluginsInto:defaultSettingUIPluginsInto];


        // add your additional plugins here.
    }
    pluginsCleanHandler:^(NSMutableArray<id<MTHawkeyeMainPanelPlugin>> *_Nonnull mainPanelPlugins, NSMutableArray<id<MTHawkeyeFloatingWidgetPlugin>> *_Nonnull floatingWidgetPlugins,NSMutableArray<id<MTHawkeyeSettingUIPlugin>> *_Nonnull defaultSettingUIPluginsInto) {
      // if you don't want to free plugins memory, remove this line.
      [MTHawkeyeDefaultPlugins cleanDefaultUIClientMainPanelPluginsFrom:mainPanelPlugins
                                      defaultFloatingWidgetsPluginsFrom:floatingWidgetPlugins
                                            defaultSettingUIPluginsFrom:defaultSettingUIPluginsInto];

      // clean your additional plugins if need.
    }];

  dispatch_async(dispatch_get_main_queue(), ^(void) {
    [[MTHawkeyeUIClient shared] startServer];
  });
#endif
}

用于测试,在线

测试阶段可能会有特殊要求,或者可能不需要在发布App时保留接口代码。在这种情况下,您可以根据需要创建一个新的podspec,将需要的子规范引入到podspec中,然后将其添加到podfile中。

  pod 'YourOnlineHawkeye', :podspec => 'xxx/yourOwnHawkeyeOnline.podspec', :configurations => 'Release'

然后在初始化时,根据需要加载插件,配置插件是否应该启动。例如

#ifdef Release
  [MTHawkeyeUserDefaults shared].allocationsTraceOn = YES; // trun on allocations this time.

  [[MTHawkeyeClient shared]
    setPluginsSetupHandler:^(NSMutableArray<id<MTHawkeyePlugin>> *_Nonnull plugins) {
      [plugins addObject:[MTHAllocationsHawkeyeAdaptor new]];

      // add your additional plugins here.
    }
    pluginsCleanHandler:^(NSMutableArray<id<MTHawkeyePlugin>> *_Nonnull plugins) {

    }];

  [[MTHawkeyeClient shared] startServer];
#endif

0x02 交互

  • 浮动窗口
    • 显示和隐藏浮动窗口:连续按压两秒钟的三指长按手势或三指左滑手势。
    • 显示和隐藏浮动窗口小部件:进入设置视图,然后选择浮动窗口,切换小部件以显示或隐藏。
  • 主面板:轻击浮动窗口查看您上次查看的插件面板。
  • 设置视图:进入主面板,轻击标题展开切换模块视图,右上角点击设置

每个插件的界面交互文档:见上文链接

0x03 开发您自己的插件

如果您在开发过程中有需要避免很多陷阱的模块,或者开发期间有大量的调试/优化相关日志代码,考虑编写一个调试助手,然后根据MTHawkeye API将此组件导入MTHawkeye。在框架中用于统一交互和接口。

如果您关心的性能指标在自动化测试过程中没有持续跟踪,考虑编写一个分析插件来收集性能数据。

详情请见:MTHawkeye 插件开发指南

0x04 贡献给MTHawkeye

有关贡献问题或拉取请求的更多信息,请参阅MTHawkeye 贡献指南

0x05 感谢

0x06 许可证

MTHawkeye 使用MIT许可证,详情请见LICENSE文件。