使用Reveal调试和分析UI

在移动开发当中,APP的界面的编写和调试占了相当的一部分时间,那么在不借助Xcode之外的第三方工具的情况下来调试UI是一件相对来说比较耗费时间的工作,一般情况下,你除了使用Xcode的自带的UI调试器之外,只能使用输出View结构的方式来调试UI的问题。这个在节奏紧凑的开发过程当中是非常不爽的一件事。专业的事情应该交给专业的工具来做,对于调试UI的这件事情来说,应该交给Reveal这个工具。

Reveal是一个程序界面调试工具,可以调试iOS apps和tvOS apps。使用Reveal,我们可以在开发时动态地查看和修改应用程序的界面。避免每次修改UI的时候都要重新运行程序。接下来按照规矩,如下图,能用图说明清楚的就不用文字来表达了,文字的表现力不够直观。


Reveal程序运行截图

1、如“Reveal程序运行截图”所示,我使用的Reveal官方提供的项目来作为调试Demo,最左边的是Demo的在模拟器的运行效果,右边的App就是Reveal,我第一眼看到这个Reveal有种惊艳的感觉。App的左上方是我此刻调试的模拟器,左下方是我此刻查看UI细节信息的UIView,App的中间部分就是此刻正在分析的设备界面,App的最右边是不是看着和Xcode的Xib编辑器有点类似,没错这个就是可以动态查看和修改UI的地方。这个修改的方式和Xcode的Xib修改Ui细节类似,相信你对这个已经很有感觉了,只要稍加查看就可以上手的。


Reveal查看UI

2、如“Reveal查看UI图”所示,Reveal查看UI的维度也是可以选择的,可以有二维视角,也可以有三维视角。我选择了一个三维视角,如上图所示左边点击展开UIView的层级,点击对应的View查看这个View的对应约束,用这样的方式来查看UI的约束是不是太直观了。

说了这么多,最重要的还没有说出来呢,那就是这个Reveal这么叼,那我要怎么使用它来调试我自己的App界面,或者查看其他知名App的UI布局实现信息。接下来还是先说说怎么用它来调试我们自己的App界面。


使用Reveal来调试模拟器中的我们的App的界面是最简单的。只需要添加对应的断点即可。


1、在Xcode项目中,选择“View → Navigators → Show Breakpoint Navigator”。


Add Symbolic Breakpoint”

2、在左边底部面板,点击"+"号按钮,然后选择“Add Symbolic Breakpoint”。

3、在Symbol字段里面填入“UIApplicationMain”。

4、点击“Add Action”按钮,并确认一下“Action”是设置到“Debugger Command”。

5、在Action下的文本框中贴入如下表达式

expr (Class)NSClassFromString(@"IBARevealLoader") == nil ? (void *)dlopen("/Applications/Reveal.app/Contents/SharedSupport/iOS-Libraries/libReveal.dylib", 0x2) : ((void*)0)


检查选项

6、检查选项“Automatically continue after evaluating actions”是否勾选了。



Move Breakpoint To → User

7、右键点击新建的断点,然后选择“

Move Breakpoint To → User

”保存给所有的项目使用。


打开Reveal

8、编译,在模拟器上运行你的程序,然后打开Reveal,查看你的布局。



使用真机调试我们的App界面,如果你的真机是没有越狱的设备,那么使用Reveal来调试UI的步骤是最麻烦的。


打开Reveal的库位置
Reveal的库
拖库进项目

1、如“拖库进项目”图所示,把Reveal的库拖到我们项目中来。



选择添加的方法

2、如“选择添加的方法”所示,不要把库加到我们App的target里面。



添加到Bundle Resource

3、如“添加到Bundle Resource”图所示,将Reveal的库添加到Bundle Resource。



选择添加到Bundle Resource

4、如“选择添加到Bundle Resource”所示,选择对应的Reveal的库到Bundle Resource。



添加Reveal库成功

5、如“添加Reveal库成功”图所示,当Bundle Resources出现了Reveal库的时候就添加成功了。



添加对应的系统库

6、如“添加对应的系统库”所示,添加Reveal运行时所需要的系统库。



添加Reveal运行脚本

7、如“添加Reveal运行脚本”所示,接下来是添加Reveal的运行脚本,是不是感觉到麻烦了,如果你有更好调试非越狱真机的方法欢迎告知我,谢谢!



写入Reveal对应的脚本

8、如“写入Reveal对应的脚本”所示,写入Reveal运行时候需要的脚本,脚本内容如下:

set -e

if [ -n "${CODE_SIGN_IDENTITY}" ]; then

codesign -fs "${CODE_SIGN_IDENTITY}" "${BUILT_PRODUCTS_DIR}/${FULL_PRODUCT_NAME}/libReveal.dylib"

fi




加载方法


在生命周期方法里面调用加载方法

 9、如“加载方法”图所示,需要在AppDelegate里面写对应的Reveal加载方法,我使用的是Swift版本的,当然也有OC版本的。然后如“在生命周期方法里面调用加载方法”图所示,需要在生命周期方法里面调用Reveal的加载方法。各个版本加载方法现提供如下(需要注意的是不要在发布版本去加载Reveal,因为它仅适合调试):

Swift:

// MARK: - Reveal

func loadReveal() {

if NSClassFromString("IBARevealLoader") == nil {

let revealLibName = "libReveal" // or "libReveal-tvOS" for tvOS targets

let revealLibExtension = "dylib"

var error: String?

if let dylibPath = NSBundle.mainBundle().pathForResource(revealLibName, ofType: revealLibExtension) {

print("Loading dynamic library \(dylibPath)")

let revealLib = dlopen(dylibPath, RTLD_NOW)

if revealLib == nil {

error = String(UTF8String: dlerror())

}

} else {

error = "File not found."

}

if error != nil {

let alert = UIAlertController(title: "Reveal library could not be loaded",

message: "\(revealLibName).\(revealLibExtension) failed to load with error: \(error!)",

preferredStyle: .Alert)

alert.addAction(UIAlertAction(title: "OK", style: .Default, handler: nil))

UIApplication.sharedApplication().windows.first?.rootViewController?.presentViewController(alert, animated: true, completion: nil)

}

}

}

Objective-C:

#import <dlfcn.h>

#pragma mark - Reveal

- (void)loadReveal

{

if (NSClassFromString(@"IBARevealLoader") == nil)

{

NSString *revealLibName = @"libReveal"; // or @"libReveal-tvOS" for tvOS targets

NSString *revealLibExtension = @"dylib";

NSString *error;

NSString *dyLibPath = [[NSBundle mainBundle] pathForResource:revealLibName ofType:revealLibExtension];

if (dyLibPath != nil)

{

NSLog(@"Loading dynamic library: %@", dyLibPath);

void *revealLib = dlopen([dyLibPath cStringUsingEncoding:NSUTF8StringEncoding], RTLD_NOW);

if (revealLib == NULL)

{

error = [NSString stringWithUTF8String:dlerror()];

}

}

else

{

error = @"File not found.";

}

if (error != nil)

{

NSString *message = [NSString stringWithFormat:@"%@.%@ failed to load with error: %@", revealLibName, revealLibExtension, error];

UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Reveal library could not be loaded"

message:message

preferredStyle:UIAlertControllerStyleAlert];

[alert addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil]];

[[[[[UIApplication sharedApplication] windows] firstObject] rootViewController] presentViewController:alert animated:YES completion:nil];

}

}

}



成功运行结果

10、保证你的电脑和你的真机在同一个网段内,然后运行你的App,在Reveal中选择你的设备,稍等片刻,你的Reveal就会出现对应的UI界面了,如“成功运行结果”界面所示(我的运行设备是iPad)。使用Cmd+R快捷键可以刷新你的Reveal界面。


福利福利福利!!!越狱设备福利!!!

非越狱真机调试是最麻烦的,以前真机还可以使用断点来调试的,现在都不能用了。不再纠结这个了,如果你的设备是越狱设备,那么恭喜你,你要使用Reveal简直是轻松加esay。点开链接一键配置,用Reveal Loader配合Reveal调试App会有惊喜。这个是Richard Heard这位开发者开发的一个Reveal插件,你只需要安装这个插件,保证你的电脑和你的真机在同一个网段内,然后选择你想要调试的任何App(对,没错,不是你自己家的App也可以搞,只有你想不到,没有你看不到的,哈哈哈,巨大福利)。

感谢你看完了本文,因为我感觉自己写的文字加上图片内容很多了,哈哈!这篇文章是来源于我自己的工作实践经验,在接触和使用使用Reveal之前,我一直都是使用打印View结构的方式来调试UI,但是这个方法的输出很不友好,因为没有没有接触到特别好用的工具,所以也不觉得这个打印的方法有多耗费时间。但是现在我不这么想了,根据我的经验判断,但凡不能马上看出问题的UI布局,我都会马上使用Reveal,因为省时省力,而且它也挺有意思的。

看完我的博客,如果你觉得我写的文章对你有一丁点儿帮助的话,那么请你在下面点个赞,让我知道这文章有起了它应该起的作用,谢谢!!!

参考资料:

Reveal的项目:https://github.com/revealapp/Revert

Reveal Loader安装使用 :http://bbs.iosre.com/t/reveal-loader-reveal-app/187

不修改Xcode工程来使用Reveal:  http://support.revealapp.com/kb/getting-started/integrating-reveal-load-reveal-without-changing-your-xcode-project

Xcode配置Reveal:http://support.revealapp.com/kb/getting-started/integrating-reveal-add-reveal-to-your-xcode-project

推荐阅读更多精彩内容