【翻译】UIDebuggingInformationOverlay

UIDebuggingInformationOverlay 是 Apple 创建的一个私有的 UIWindow 的子类,想必是为了帮助开发者和设计师调试 Apple 自己的 iOS app。

July 5, 2017 -
ios 翻译

本文翻译自 Ryan Peterson 的 Blog 上的 UIDebuggingInformationOverlay 一文。

UIDebuggingInformationOverlay


最近在浏览 UIKit 的私有头部文件时,我遇到了一个以前没有发现过的类 - UIDebuggingInformationOverlay。Google 没有搜索到更多信息,所以我简短的写出我的发现。

UIDebuggingInformationOverlay 是 Apple 创建的一个私有的 UIWindow 的子类,想必是为了帮助开发者和设计师调试 Apple 自己的 iOS app。

当启用时,你的 app 的内容之上会悬浮一个窗口,如下:

UIDebuggingInformationOverlay

在这篇文章里,我将给你展示如何显示它。我也会至少以我对它的理解,来总结其功能。

如何显示 UIDebuggingInformationOverlay

显示 UIDebuggingInformationOverlay 的一切荣耀需要 2 步:

  1. 调用 [UIDebuggingInformationOverlay prepareDebuggingOverlay] - 我不确定这个方法做了什么,但是如果你不调用它,悬浮窗将会是空的。
  2. 调用 [[UIDebuggingInformationOverlay overlay] toggleVisibility] - 这会显示悬浮窗口(假设它是不可见的)。

因为这个类和其方法是私有的,你需要跳几圈来获取编译代码。一个途径是使用全局函数 ‘NSClassFromString’ 和 ‘NSSelectorFromString’。使用 Swift,这个途径看起来像这样:

let overlayClass = NSClassFromString("UIDebuggingInformationOverlay") as? UIWindow.Type
_ = overlayClass?.perform(NSSelectorFromString("prepareDebuggingOverlay"))
let overlay = overlayClass?.perform(NSSelectorFromString("overlay")).takeUnretainedValue() as? UIWindow
_ = overlay?.perform(NSSelectorFromString("toggleVisibility"))

一旦你选择这样做,请确保代码不会打包进你的 App Store 版本,否则你很可能被拒绝。

更新,2017-05-26:感谢Bryce Pauken,发现了一旦你调用 [UIDebuggingInformationOverlay prepareDebuggingOverlay],只需使用两根手指点击状态栏,就能显示控制台。不需要调用 toggleVisibility。

更新,2017-06-02:来自 Bryce 的更多信息:

因为我很好奇 prepareDebuggingOverlay 还做了什么,所以我做了一次反汇编(Hopper!)。这是部分输出。即使在解析它之前,statusBarWindow + numberOfTouchesRequired 也跳出得足够快:

r14 = [[*_UIApp statusBarWindow] retain];
r15 = [UITapGestureRecognizer alloc];
rbx = [[UIDebuggingInformationOverlay overlay] retain];
r12 = [r15 initWithTarget:rbx action:@selector(_handleActivationGesture:)];
[rbx release];
[r12 setNumberOfTouchesRequired:0x2];
[r12 setNumberOfTapsRequired:0x1];
[r14 addGestureRecognizer:r12];

Hopper 带来的另一个乐趣 - 这里确实是 UIKit 里这个方法被调用的点:(-[UIApplication _runWithMainScene:transitionContext:completion:],似乎是在 app 启动期间被调用)。更多挖掘之后,似乎是在以下条件下激活调试悬浮窗,如果 1) CPIsInternalDevice() 返回 true,并且 2) UserDefaults(suiteName: “com.apple.UIKit”) 的 “DebuggingOverlayEnabled” 有一个 true 值。这里没有任何信息能提供更好的实现,但依然为想法喂了有趣的料。

UIDebuggingInformationOverlay 能做什么

如你在上面的截图所见,悬浮窗提供了 7 个功能。我会简要陈述前面 6 个。‘System Color Audit’ 这一屏没有给我显示任何信息,如果你有更好的运气请发消息给我。

‘View Hierarchy’ 屏

这一屏展示了你可能期望的内容;所选窗口里的一个视图列表。从这里,你能检查每个视图的详情,包括其框架和实例变量。如果你有多个窗口,也可以在窗口之间切换,或者只是好奇地看看系统窗口是如何构建的。

View Hierarchy screen

View Hierarchy info screen

‘VC Hierarchy’ 屏

你大概可以猜到这一屏的作用。除了显示当前活动视图控制器的层级外,它与 ‘View Hierarchy’ 屏非常相似。从这里,你可以检查每个视图控制器的详情,包括其视图。你也可以看到视图控制器是正在呈现一个 modal 还是呈现自身。

VC Hierarchy screen

‘Ivar Explorer’ 屏

这一屏让你可以访问 UIApplication 的实例变量。更重要的是,每个对象变量都可以探索。包括 app 的代理,app 的结构依赖,可能还提供一个方便的入口进入到你的自定义对象。

Ivar Explorer screen

‘Measure’ 屏

依我看,这是悬浮窗最酷的功能之一。它让你测量屏幕上的元素的尺寸(以点为单位)。首先,选择你想要在哪个坐标轴上看到测量结果,‘Horizontal(横向)’ 还是 ‘Vertical(纵向)’。然后在屏幕上拖动你的手指,还可以使用控制台内的放大器来辅助你。这有两种模式:

默认模式会忽略视图的边界。就我所知,这个模式将屏幕当作单个光栅化图像对待,并以颜色的变化作为潜在测量的边界。例如,在下面的截屏里,我能够测量 label 的文字结尾与屏幕边缘的距离。

Measure screen

“View mode”,另一方面,会显示焦点子视图的大小。在一个视图之上拖动你的手指,查看选中坐标轴的尺寸。在这个截图里,我正在测量屏幕顶部 textfield 的高度。

Measureview screen

‘Spec Compare’ 屏

我能看到这是开发和设计之间协作的一个非常有用的工具。添加一个截图到你的设备,接着从 Spec Compare 屏选择它。选中的截图会显示在当前 app 的顶部。你可以向下拖动以降低透明度,并将规格与实际实现进行比较。

更新,2017-05-26:Patrick Balestra 提醒我漏掉了重要的一步。你需要在你的 Info.plistNSPhotoLibraryUsageDescription 键设置值。点按 ‘Add’ 按钮弹出 UIImagePickerController,如果没有设置这个值会导致你的 app 闪退。

Spec Compare Picker

Spec Compare Overlay

总结

我只有几天来玩这个东西,但我希望在下一个测试版能用到它。控制台有一些粗糙的边缘,但它看起来很有前途去替代许多开源工具。如果你有机会使用它,并注意到任何我错过的内容,请随时联系。我学到更多就更新这篇文章。