写个自己的Xcode4插件

转自:http://joeyio.com/ios/2013/07/25/write_xcode4_plugin_of_your_own/

刚写iOS程序的时候就知道Xcode支持第三方插件,比如ColorSense等很实用的插件,但Xcode的插件开发没有官方的文档支持,一直觉得很神秘,那今天就来揭开它的面纱。

在Xcode启动的时候,它会检查插件目录(~/Library/Application Support/Developer/Shared/Xcode/Plug-ins)下所有的插件(扩展名为.xcplugin的bundle文件)并加载他们。其实到这里我们就猜到了,我们做的插件最终会是一个扩展名为.xcplugin的bundle文件,放在插件目录下供Xcode加载。

OK,我们先做一个简单的插件,需要很简单的几个步骤即可完成,我的环境是Xcode 4.6.3 (4H1503)。

1. 新创建一个Xcode Project

Xcode插件其实就是一个Mac OS X bundle,所以可以参考下图创建一个Bundle。 

给Project起个名字,并确保不要勾选Use automatic reference counting,因为Xcode是使用GC来管理内存的,所以Xcode的插件也需要是用GC来管理内存的。Framework选择Cocoa

2. 设置Target Info

像下图一样设置这些信息

  • XC4Compatible = YES
  • XCPluginHasUI = NO
  • XCGCReady = YES
  • Principal Class = Plugin (这个设置为你插件的名字,本例中命名为Plugin)

前三个可能Info里缺省没有,可以自己添加,都选Boolean类型,最后一个Principal ClassString类型。 

3. 设置Build Settings

然后打开Build Setting Tab,设置这些:

  • 设置Installation Build Products Location${HOME},Xcode会自动转换为你当前用户的Home路径
  • 设置Installation Directory 为/Library/Application Support/Developer/Shared/Xcode/Plug-ins, Xcode会把拼接Installation Build Products LocationInstallation Directory为一个绝对路径来查找你的插件
  • 设置Deployment Location 为 YES
  • 设置Set Wrapper extension 为 xcplugin

##4. 添加 User-Defined 设置

  • 设置GCC_ENABLE_OBJC_GC 为 supported
  • 设置GCC_MODEL_TUNING 为 G5

有了这些设置,每次build这个Projct的时候,Xcode就会把build后的插件copy到plugin文件夹下,然后我们需要重启Xcode来重新加载新build的插件。开发插件相对来说简单一些,调试插件就比较纠结了,唯一的办法就是build之后,重启Xcode,来加载最新build的插件。

准备工作已经结束,下面开始实现我们的插件。

5. 实现我们的插件

在第二步的时候我们设置了一个Principal Class,那么在Xcode里新建Objective-C类,名字和Principal Class设置的值保持一致。在实现文件中添加上+ (void) pluginDidLoad: (NSBundle*) plugin方法。 该方法会在Xcode加载插件的时候被调用,可以用来做一些初始化的操作。通常这个类是一个单例,并Observe了NSApplicationDidFinishLaunchingNotification,用来获得Xcode加载完毕的通知。

+ (void) pluginDidLoad: (NSBundle*) plugin {
	static id sharedPlugin = nil;
	static dispatch_once_t once;
	dispatch_once(&once, ^{
		sharedPlugin = [[self alloc] init];
	});
}

- (id)init {
	if (self = [super init]) {
		[[NSNotificationCenter defaultCenter] addObserver:self
                        selector:@selector(applicationDidFinishLaunching:)
                            name:NSApplicationDidFinishLaunchingNotification
                          object:nil];
	}
	return self;
}

一旦接收到Xcode加载完毕的通知,就可以Observe需要的其他notification或者在菜单中添加菜单项或者访问Code Editor之类的UI组件。

在我们的这个简单例子中,我们就在Edit下添加一个叫做Custom Plugin的菜单项,并设置一个? + c快捷键。它的功能是使用NSAlert显示出我们在代码编辑器中选中的文本。我们需要通过观察NSTextViewDidChangeSelectionNotification并访问接收参数中的NSTextView,来获得被选中的文本。

- (void) applicationDidFinishLaunching: (NSNotification*) notification {
    [[NSNotificationCenter defaultCenter] addObserver:self
                        selector:@selector(selectionDidChange:)
                            name:NSTextViewDidChangeSelectionNotification
                          object:nil];

    NSMenuItem* editMenuItem = [[NSApp mainMenu] itemWithTitle:@"Edit"];
    if (editMenuItem) {
        [[editMenuItem submenu] addItem:[NSMenuItem separatorItem]];

       NSMenuItem* newMenuItem = [[NSMenuItem alloc] initWithTitle:@"Custom Plugin"
                                            action:@selector(showMessageBox:)
                                     keyEquivalent:@"c"];
       [newMenuItem setTarget:self];
       [newMenuItem setKeyEquivalentModifierMask: NSAlternateKeyMask];
       [[editMenuItem submenu] addItem:newMenuItem];
       [newMenuItem release];
   }
}

- (void) selectionDidChange: (NSNotification*) notification {
    if ([[notification object] isKindOfClass:[NSTextView class]]) {
        NSTextView* textView = (NSTextView *)[notification object];

        NSArray* selectedRanges = [textView selectedRanges];
        if (selectedRanges.count==0) {
            return;
        }

        NSRange selectedRange = [[selectedRanges objectAtIndex:0] rangeValue];
        NSString* text = textView.textStorage.string;
        selectedText = [text substringWithRange:selectedRange];
   }
}

- (void) showMessageBox: (id) origin {
    NSAlert *alert = [[[NSAlert alloc] init] autorelease];
    [alert setMessageText: selectedText];
    [alert runModal];
}

你会发现在出现selectedText的地方会报错,在实现里添加上NSString *selectedText即可。

@implementation Plugin {
    NSString *selectedText;
}

最终效果:

6. 需要注意的

  • ~~Plugin不能使用ARC,需要手动管理好内存~~(谢谢@onevcat的提醒,因为是用GC,不需要手动管理内存了)
  • 不能直接Debug,不过可以在程序里通过NSLog打印出日志,并通过tail -f /var/log/system.log 命令来查看输出的日志
  • 如果Xcode突然启动不起来了,可能是插件有问题,跑去~/Library/Application Support/Developer/Shared/Xcode/Plug-ins目录下,把插件删掉,restart Xcode,查找问题在哪
  • 如果1-4步骤的各种设置你比较讨厌的话,可以直接用这个Xcode4 Plugin Template来搞定, 怎么使用在它的Readme中有详细的说明,:)

总结

这只是一个简单的Xcode插件的入门编写示例,不过“麻雀虽小,五脏俱全”,可以了解到Xcode的插件一些东西,比如Xcode插件本质上其实就是一个Mac OS X bundle等等,而且因为没有Apple官方的文档的支持,很多东西只能去Google,或者参考别人插件的一些实现。

REF

本文主要参考和编译自WRITING YOUR OWN XCODE 4 PLUGINS,感谢原作者Blacksmith Software



另: 前两天我们的小伙伴@onevcat写了一个Xcode插件VVDocumenter,作用是在方法、类等前面输入三个/就会自动生成规范的JavaDoc文档(Xcode5中将支持JavaDoc类型的文档,对于我这样从Java转过来的来说是真是雪中送炭),赶紧clone了一个,用起来很方便,很好很强大,强烈推荐! 赶紧把我们的项目代码文档化起来,迎接Xcode5的到来吧,:)

Enjoy!!!

时间: 2024-08-30 04:01:54

写个自己的Xcode4插件的相关文章

原生js写的一个弧形菜单插件

弧形菜单是一种半弧式或者全弧形菜单,是一种不同于传统横向或者竖向菜单形式的菜单.最近在网上看到好多人写出了这种效果,于是也尝试自己写了一个. 实现方式:原生态js 主要结构: 1.参数合并 1 var defaultPra = { 2 mainMenuId: "ArcMenu",//主菜单id 3 menuBoxId:"menuBox",//菜单包裹id 4 position: "",//弧形菜单 5 customPosition:"0

用jQuery写了一个模态框插件

用jQuery写了一个模态框插件 大家觉得下面的框框好看么, 水印可以去掉(这个任务交给你们了(- o -)~zZ); "info"框 $("div").confrimModal("<font color=\"green\">成功! </font>", {type:"info", themeColor: "#008B8B"}, true); "alert

如何写一个Jquery 的Plugin插件

博客分类: Javascript /Jquery / Bootstrap / Web jQuery配置管理脚本FirebugJavaScript JQuery Plugin插件,如果大家不明白什么是JQuery插件或都不清楚如何编写可以查看其官方的网站:jQuery Authoring Guidelines 好了,下面有一些我觉得想做一个好的插件必须应有的要求: 1.在JQuery命名空间下声明只声明一个单独的名称 2.接受options参数,以便控制插件的行为 3.暴露插件的默认设置 ,以便外

菜鸟写的第一个chrome插件

一.新建一个文件夹,用来放插件的代码 二.首先新建配置文件manifest.json 1 // 开发参考:http://open.chrome.360.cn/extension_dev/overview.html 2 // 字段说明参考:http://open.chrome.360.cn/extension_dev/manifest.html 3 { 4 "name": "myTB Name", // 必填 5 "version": "

自己写一个jQuery垂直滚动条插件(panel)

html中原生的滚动条比较难看,所以有些网站,会自己实现滚动条,导航网站hao123在一个侧栏中,就自定义了垂直滚动条,效果比较好看,截图如下: 这个滚动条,只有在鼠标悬停在这个区域内时才显示,半透明效果,很节省空间的说~~,说实话,这个效果我非常喜欢. 垂直滚动条的原理,简单来说: 先起个名字,外层的叫wrapper,内层的叫content,wrapper需要有非static的定位,content需要绝对定位,这样就可以通过调节top值来模拟内容滚动. 具体说一下: 1.wrapper的ove

自已动手写的轮播图插件,功能不断增加中,可以下载

前,平时总是使用别人的轮播图插件,这次决定自已写一个,功能越多越好.实际现起来,发现并不容易.先实现基本的功能,下两周要丰富起来. 图是别人的图,心是自已的心.直接上代码: 一:结构 <!-- carousel begin --><div class="carousel-wrap">    <div class="carousel-main-wrap">        <ul class="carousel-scr

写一个Sublime Text 2插件(CSS文件里px单位替换成rem单位)

三年前我就知道了sublime text 不过那时候用DW还是很爽的样子,后来有天想为难自己了,于是用了两年的vim和五笔,最近又觉得这么好编辑器也可以试试,改变一下自己,用一下的,不过由于工作的原因,没有坚持下来,有时候顺手似乎比先进更重要一些. 最近工作都是做一些移动端的页面,而微信的长按出现二维码有个bug,在ios里缩放的页面长按是不会出现"识别二维码"的.所以需要转换一下,不要让页面缩放,要自适应,这个时候就用rem单位来做的会比较好一些,而我的同事之前开发了一个px to

写一个简单的JQ插件(例子)

虽然现在 vue angular react 当道啊但是那 JQ还是有一席之地很多很多的小单位啊.其实还会用到 我也放一个例子吧虽然我也不是很肯定有没有人写的比我更好啊但是我相信 我这个还是蛮实用的 话不多说 丢代码 JQ插件标准的封装代码如下,首先需要闭包: <scripttype="text/javascript"> (function ($) {  //这里放入插件代码 })(jQuery); </script> 这是jQuery官方的插件开发规范,这样写

08.01《jQuery》——cookie插件的简单应用和自己写的简单更换颜色插件

1.Cookie是网站设计者放置在客户端的小文本文件.实现:存储用户曾经浏览过的产品列表,记住用户喜欢浏览哪类新闻等. 在用户允许的情况下,还可以存储用户的登录信息,使得用户在访问网站时不必每次都键入这些信息. 首先上代码: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> <script src="../jqu