以往Xcode插件开发在没有官方支持的情况下,基本处于处于刀耕火种的状态。虽然后来有了Xcode-Plugin-Template和各种dump好的头文件,我们仍然需要在没有文档的情况下做各种猜测和hook。关于插件的开发,可以看看这篇文章。幸运的是苹果终于注意到了这一需求,并在WWDC2016上发布这一新特性–Xcode Source Editor Extension
。
简介
Xcode Source Editor Extension
,从字面意思理解就是Xcode源代码编辑器的一个扩展,事实上它的命名的确很好地反映了它的功能和定位。那么基于这项技术我们究竟能做什么呢?WWDC session 414给我们的答案是:
Add commands to the source editor
Edit text
Change selections
给Xcode的代码编辑器扩展一些命令(在Editor
菜单下增加额外的菜单),通过这些命令对源代码进行编辑(包括整个文件和选中的部分,这里的selection我起初不理解,后面做Demo就会理解了)。
相比于以往的插件开发,Xcode Source Editor Extension
具有以下特点:
- 稳定。extension运行在其独立的进程中,插件的崩溃不会再引起Xcode的崩溃了。
- 安全。extension拥有自己的sandBox,而且不会直接去操作Xcode工程,而是由Xcode将text以invocation的方式传递。
- 快速。每个extension在Xcode启动后会即会被异步地以XPC的方式加载。
- 简单。苹果提供了官方支持。
此外,作为App Extension
的一种,可在App Store发布,优秀的插件也可以为开发者增加收入。下面我们就跟着demo来探究如何实现一个Xcode Source Editor Extension
。
工程创建
我将创建一个为全部选中行添加注释的demo。根据官方指导,创建一个插件工程非常容易。首先我们创建一个Cocoa Application
命名为”XTExtension”,接着在Application Extension
中选中Xcode Source Editor Extension
,命名为XTComment
。
此时工程的XTComment
目录下有两个文件SourceEditorExtension.swift
和SourceEditorCommand.swfit
,SourceEditorExtension
用来管理extension的生命周期相关,SourceEditorCommand
则用来处理具体的命令。Extension的加载和处理流程如下:
Xcode的启动时候会记载所有的extension,并保证它们的生命周期。当用户点击选择命令按钮后,Xcode会以invocation的形式通知到extension,extension做出相应的处理并把处理结果回调给Xcode。SourceEditorExtension.swift
的方法extensionDidFinishLaunching
在extension被加载时调用,可以在这里做一些初始化的工作。
1 | func extensionDidFinishLaunching() { |
添加菜单
打开Info.plist
,展开NSExtension
至XCSourceEditorCommandDefinitions
,命令菜单的定义如下:
1 | <key>NSExtensionAttributes</key> |
其中:
XCSourceEditorCommandClassName
指向命令的处理类,该类实现XCSourceEditorCommand
。XCSourceEditorCommandIdentifier
是命令的唯一标识,通常我们会对一组命令设置同一个XCSourceEditorCommand
,在invocation中获取此标识做区分处理。XCSourceEditorCommandName
是命令在菜单栏展示的菜单名称。
此外,菜单项是动态加载的,可以实现SourceEditorExtension
的commandDefinitions:
实现,但是这会覆盖掉Info.plist
中的定义。
1 | var commandDefinitions: [[XCSourceEditorCommandDefinitionKey: AnyObject]] { |
Extension的菜单会默认加载在Show Code Coverage
下。编译运行,选取Xcode-Beta作为Lanuching App,点击Editor
,然而Show Code Coverage
下空空如也,什么也没有。作为新主题,可查的资料实在太少,一度以为因为Xcode是Beta版的问题并打算放弃了。很偶然的一个机会在Xcode 8.0 beta Release Notes看到了这个问题的答案,WTF!
To use Xcode Extensions on macOS 10.11 El Capitan, you must first launch Xcode and let it install additional system components. Then, in Terminal, run sudo /usr/libexec/xpccachectl.
Once the operation completes, restart your Mac. (26106213)
业务实现
打开SourceEditorCommand.swift
,实现perform(with:completionHandler:)
。
1 | func perform(with invocation: XCSourceEditorCommandInvocation, completionHandler: (NSError?) -> Void ) -> Void { |
invocation
的buffer
提供了比较丰富的信息,包括文件的lines
, selections
, indentationWidth
等等,具体作用可以查看WWDC视频或者苹果的文档查看,在此就不一一介绍了。
此外,需要注意的一点是,苹果希望文本的编辑是快速流畅的,如果你的处理的文本时间过长苹果就会为用户提供一个取消的入口,这会触发invocation的cancellationHandler
,所以在这里终止你的耗时的工作,否则你的extension可能不能正常地工作。最后,附上苹果的extension开发建议。
Start up quickly
Use GCD and follow standard asynchronous patterns
Don’t replace the whole buffer if you don’t have to
Handle cancellation quickly
小结
Xcode Source Editor Extension
提供了一种官方Xcode插件开发方法,从上文可以看出,其所涉及的类和函数都很少,非常容易上手。同时,从目前来看,她的能力还相对较弱,一些复杂的如FuzzyAutocompletePlugin还无法实现。但我相信很快会有优秀的插件来丰富Xcode功能和提升开发效率的。
参考