你好,歡迎來到IOS教程網

 Ios教程網 >> IOS訊息 >> 關於IOS >> Xcode 插件制作入門

Xcode 插件制作入門

編輯:關於IOS
code4blog總結對 於 Xcode 5,本文有些地方顯得過時了。Xcode 5 現在已經全面轉向了 ARC,因此在插件初始化設置方面其實有所改變。另外由於一大批優秀插件的帶動(可以參看文章底部鏈接),很多大神們逐漸加入了插件開發的行列,因此,一 個簡單的 Template 就顯得很必要了。在 Github 上的這個 repo 裡,包含了一個 Xcode 5 的插件的 Template 工程,省去了每次從頭開始建立插件工程的麻煩,大家可以直接下載使用。另外值得一提的是,在 Xcode 5 中, Apple 為了防止過期插件導致的在 Xcode 升級後 IDE 的崩潰,添加了一個 UUID 的檢查機制。只有包含聲明了適配 UUID,才能夠被 Xcode 正確加載。上面那個項目中也包含了這方面的更詳細的說明,可以參考。文中其他關於插件開發的思想和常用方法在新的 Xcode 中依然是奏效的。


本文將介紹創建一個Xcode4插件所需要的基本步驟以及一些常用的方法。請注意為Xcode創建插件並沒有任何的官方支持,因此本文所描述的方法 和提供的信息可能會隨Apple在Xcode上做的變化而失效。另外,由於創建插件會使用到私有API,因此Xcode插件也不可能被提交到Mac App Store上進行出售。

本文內容是基於Xcode 4.6(4H127)完成的,但是應該可以適用於任意的Xcode 4.X版本。VVPlugInDemo的工程文件我放到了github上,有需要的話您可以從這裡下載並作為參考和起始來使用。

綜述

Xcode本身作為一個IDE來說已經可以算上優秀,但是依然會有很多缺失的功能,另外在開發中針對自己的開發需求,創建一些便利的IDE插件,必 定將大為加快開發速度。由於蘋果官方並不對Xcode插件提供任何技術和文檔支持,因此對於大部分開發者來說可能難於上手。雖然沒有官方支持,但是在 Xcode中開發並使用插件是可能的,並且也是被默許的。在Xcode啟動的時候,Xcode將會尋找位於~/Library/Application Support/Developer/Shared/Xcode/Plug-ins文件夾中的後綴名為.xcplugin的bundle作為插件進行加載 (運行其中的可執行文件),這就可以令我們光明正大合法合理地將我們的代碼注入(雖然這個詞有點不好聽)Xcode,並得到運行。因此,想要創建 Xcode插件,我們需要創建Bundle工程並將編譯的bundle放到上面所說的插件目錄中去,這就是Xcode插件的原理。

需要特別說明的是,因為Xcode會在啟動時加載你的插件,這樣就相當於你的代碼有機會注入Xcode。只要你的插件加載成功,那麼它將和 Xcode共用一個進程,也就是說當你的代碼crash的時候,Xcode也會隨之crash。同樣的情況也可能在Xcode版本更新的時候,由於兼容性 問題而出現(因為插件可能使用私有API,Apple沒有義務去維護這些API的可用性)。在出現這種情況的時候,可以直接刪除插件目錄下的導致問題的 xcplugin文件即可。

你的第一個插件

我將通過制作一個簡單的demo插件來說明一般Xcode插件的編寫方法,這個插件將在Xcode的Edit菜單中加入一個叫做“What is selected”的項目,當你點擊這個菜單命令的時候,將彈出一個警告框,提示你現在在編輯器中所選中的內容。我相信這個例子能包含絕大部分在插件創建 中所必須的步驟和一些有用的方法。由於我自己也只是個半吊子開發者,水平十分有限,因此錯誤和不當之處還懇請大家輕噴多原諒,並幫助我改正。那麼開始..

創建Bundle工程

Xcode 插件制作入門 創建工程,OSX,Framework & Library,選擇Bundle,點擊Next。

Xcode 插件制作入門

在Project信息頁面中,填入插件名字,在這個例子裡,就叫做DemoPlugin,Framework使用默認的Cocoa就行。另外一定記 住將Use Automatic Reference Counting前的勾去掉,由於插件只能使用GC來進行內存管理,因此不需要使用ARC。

工程設置

插件工程有別於一般工程,需要進行一些特別的設置,以確保能正確編譯插件bundle。

Xcode 插件制作入門

首先,在編輯工程的Info.plist文件(直接編輯plist文件或者是修改TARGETS下對應target的Info都行),加入以下三個布爾值:

<code class="hljs ini"><span class="hljs-setting">XCGCReady = <span class="hljs-value"><span class="hljs-keyword">YES</span>  </span></span>
<span class="hljs-setting">XCPluginHasUI = <span class="hljs-value"><span class="hljs-keyword">NO</span>  </span></span>
<span class="hljs-setting">XC4Compatible = <span class="hljs-value"><span class="hljs-keyword">YES</span>  </span></span>
</code>

這將告訴編譯器工程已經使用了GC,沒有另外的UI並且是Xcode4適配的,否則你的插件將不會被加載。接下來,對Bundle Setting進行一些設置:

Xcode 插件制作入門

  • Installation Build Products Location 設置為 ${HOME}
    • Product的根目錄
  • Installation Directory 設置為
    • /Library/Application Support/Developer/Shared/Xcode/Plug-ins
    • 這裡指定了插件安裝的位置,這樣build之後就會將插件直接扔到Plug-ins的目錄了。當然不嫌麻煩的話也可以每次自己復制粘貼過去。注意這裡不是絕對路徑,而是基於上面的${HOME}的路徑。
  • Deployment Location 設置為 YES
    • 告訴Xcode不要用設置裡的build location,而是用Installation Directory來確定build後放哪兒
  • Wrapper extension 設置為 xcplugin
    • 把產品後綴名改為xcplugin,否則Xcode不會加載插件

如一開始說的那樣,Xcode會在每次啟動的時候搜索插件目錄並進行加載,做如上設置的目的是每次build之後你只需要重新啟動Xcode就能看到重新編譯後的插件的效果,而避免了自己再去尋找Product然後copy&paste的步驟。
另外,還需要自己在User-Defined裡添加一個鍵值對:

Xcode 插件制作入門

  • GCCENABLEOBJC_GC 設置為 supported

至此所有配置工作完成,接下來終於可以開始實現插件了~

Hello World

新建一個類,取名叫做VVPluginDemo(當然只要不重,隨便什麼名字都是可以的),繼承自NSObject(做iOS開發的童鞋請不要忘記 現在是寫Xcode插件,您需要通過OS X的Cocoa裡的Objective-C class模版,而不要用Cocoa Touch的模版..)。打開VVPluginDemo.m,加入以下代碼:

<code class="objc hljs objectivec">+(<span class="hljs-keyword">void</span>)pluginDidLoad:(<span class="hljs-built_in">NSBundle</span> *)plugin { 
    <span class="hljs-built_in">NSLog</span>(<span class="hljs-string">@"Hello World"</span>); 
}
</code>

Build(對於OS X 10.8的SDK可能會有提示GC已經廢棄的警告,不用管,Xcode本身是GC的,ARC的插件是無法load的),打開控制台(Control+空格 輸入console),重新啟動Xcode。應該能控制台中看到我們的插件的輸出:

Xcode 插件制作入門

太好了。有句話叫做,寫出一個Hello World,就說明你已經掌握了一半…那麼,剩下的一半內容,將對開發插件時可能面臨的問題和一些常用的手段進行介紹。

創建插件單例,監聽事件

繼續我們的插件,還記得我們的目的麼?在Xcode的Edit菜單中加入一個叫做“What is selected”的項目,當你點擊這個菜單命令的時候,將彈出一個警告框,提示你現在在編輯器中所選中的內容。一般來說,我們希望插件能夠在整個 Xcode的生命周期中都存在(不要忘記其實用來寫Cocoa的Xcode本身也是一個Cocoa程序)。最好的辦法就是 在+pluginDidLoad:中初始化單例,如下:

<code class="objc hljs objectivec">+ (<span class="hljs-keyword">void</span>) pluginDidLoad: (<span class="hljs-built_in">NSBundle</span>*) plugin { 
    [<span class="hljs-keyword">self</span> shared]; 
}


+(<span class="hljs-keyword">id</span>) shared {   
    <span class="hljs-keyword">static</span> <span class="hljs-built_in">dispatch_once_t</span> once;   
    <span class="hljs-keyword">static</span> <span class="hljs-keyword">id</span> instance = <span class="hljs-literal">nil</span>;   
    <span class="hljs-built_in">dispatch_once</span>(&amp;once, ^{   
        instance = [[<span class="hljs-keyword">self</span> alloc] init];   
    });   
    <span class="hljs-keyword">return</span> instance;   
} 
</code>

這樣,以後我們在別的類中,就可以簡單地通過[VVPluginDemo shared]來訪問到插件的實例了。

在init中,加入一個程序啟動完成的事件監聽,並在程序完成啟動後,在菜單欄的Edit中添加我們所需要的菜單項,這個操作最好是在Xcode完 全啟動以後再進行,以避免一些潛在的危險和沖突。另外,由於想要在按下按鈕時顯示編輯器中顯示的內容,我們可能需要監聽 NSTextViewDidChangeSelectionNotification事件(WTF,你為什麼會知道要監聽什麼。別著急,後面會再說,先做 demo先做demo)

<code class="objc hljs objectivec">- (<span class="hljs-keyword">id</span>)init { 
    <span class="hljs-keyword">if</span> (<span class="hljs-keyword">self</span> = [<span class="hljs-keyword">super</span> init]) { 
        [[<span class="hljs-built_in">NSNotificationCenter</span> defaultCenter] addObserver:<span class="hljs-keyword">self</span> 
                selector:<span class="hljs-keyword">@selector</span>(applicationDidFinishLaunching:) 
                    name:NSApplicationDidFinishLaunchingNotification 
                  object:<span class="hljs-literal">nil</span>]; 
    } 
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">self</span>; 
} 

- (<span class="hljs-keyword">void</span>) applicationDidFinishLaunching: (<span class="hljs-built_in">NSNotification</span>*) noti {   
    [[<span class="hljs-built_in">NSNotificationCenter</span> defaultCenter] addObserver:<span class="hljs-keyword">self</span>   
            selector:<span class="hljs-keyword">@selector</span>(selectionDidChange:)   
                name:NSTextViewDidChangeSelectionNotification
              object:<span class="hljs-literal">nil</span>];   
    NSMenuItem *editMenuItem = [[NSApp mainMenu] itemWithTitle:<span class="hljs-string">@"Edit"</span>];   
    <span class="hljs-keyword">if</span> (editMenuItem) {   
        [[editMenuItem submenu] addItem:[NSMenuItem separatorItem]];   
        NSMenuItem *newMenuItem = [[NSMenuItem alloc] initWithTitle:<span class="hljs-string">@"What is selected"</span> action:<span class="hljs-keyword">@selector</span>(showSelected:) keyEquivalent:<span class="hljs-string">@""</span>];
        [newMenuItem setTarget:<span class="hljs-keyword">self</span>];   
        [newMenuItem setKeyEquivalentModifierMask: NSAlternateKeyMask];   
        [[editMenuItem submenu] addItem:newMenuItem];   
        [newMenuItem release];   
    }   
} 

-(<span class="hljs-keyword">void</span>) selectionDidChange:(<span class="hljs-built_in">NSNotification</span> *)noti {   
    <span class="hljs-comment">//Nothing now. Just in case of crash.   </span>
} 

-(<span class="hljs-keyword">void</span>) showSelected:(<span class="hljs-built_in">NSNotification</span> *)noti {   
    <span class="hljs-comment">//Nothing now. Just in case of crash.   </span>
} 
</code>

現在build,重啟Xcode,如果一切順利的話,你應該能看到菜單欄上的變化了:

Xcode 插件制作入門

完成Demo插件

剩下的事情就很簡單了,在接收到TextView的ChangeSelection通知後把現在選中的文本更新一下,在點擊按鈕時顯示一個含有儲存文字的對話框就行了。Let's do it~

首先在.m文件中加上property聲明(個人習慣,喜歡用ivar也可以)。在#import和@implementation之間加上:

<code class="objc hljs objectivec"><span class="hljs-class"><span class="hljs-keyword">@interface</span> <span class="hljs-title">VVPluginDemo</span>() </span>
<span class="hljs-keyword">@property</span> (<span class="hljs-keyword">nonatomic</span>,<span class="hljs-keyword">copy</span>) <span class="hljs-built_in">NSString</span> *selectedText; 
<span class="hljs-keyword">@end</span>
</code>

得益於新的屬性自動綁定,synthesis已經不需要寫了(對此還不太了解的童鞋可以參看我的這篇博文)。然後完成- selectionDidChange:和-showSelected:如下:

<code class="objc hljs objectivec">-(<span class="hljs-keyword">void</span>) selectionDidChange:(<span class="hljs-built_in">NSNotification</span> *)noti {
    <span class="hljs-keyword">if</span> ([[noti object] isKindOfClass:[NSTextView class]]) {
        NSTextView* textView = (NSTextView *)[noti object];

        <span class="hljs-built_in">NSArray</span>* selectedRanges = [textView selectedRanges];  
        <span class="hljs-keyword">if</span> (selectedRanges<span class="hljs-variable">.count</span>==<span class="hljs-number">0</span>) {  
            <span class="hljs-keyword">return</span>;  
        }

        <span class="hljs-built_in">NSRange</span> selectedRange = [[selectedRanges objectAtIndex:<span class="hljs-number">0</span>] rangeValue];  
        <span class="hljs-built_in">NSString</span>* text = textView<span class="hljs-variable">.textStorage</span><span class="hljs-variable">.string</span>;  
        <span class="hljs-keyword">self</span><span class="hljs-variable">.selectedText</span> = [text substringWithRange:selectedRange];  
    }  
    <span class="hljs-comment">//Hello, welcom to OneV's Den  </span>
}

-(<span class="hljs-keyword">void</span>) showSelected:(<span class="hljs-built_in">NSNotification</span> *)noti {  
    NSAlert *alert = [[[NSAlert alloc] init] autorelease];  
    [alert setMessageText: <span class="hljs-keyword">self</span><span class="hljs-variable">.selectedText</span>];  
    [alert runModal];  
} 
</code>

Build,重啟Xcode,隨便選中一段文本,然後點擊Edit中的What is selected。OY~完成~

Xcode 插件制作入門

至此,您應該已經掌握了基本的Xcode插件制作方法了。接下來的就是根據您的需求實踐了~但是在此之前,還有一些重要的技巧和常用方法可能您會有興趣。

開發插件時有用的技巧

由於沒有文檔指導插件開發,調試也只能用打log的方式,因此會十分艱難。掌握一些常用的技巧和方法,將會很有幫助。

I Need All Notifications!

一種很好的方法是監聽需要的消息,並針對消息作出反應。就像demo裡的 NSTextViewDidChangeSelectionNotification。對於熟悉iOS或者Mac開發的童鞋來說,應該在日常開發裡也接觸 過很多類型的Notification了,而因為插件開發沒有文檔,因此我們需要自己去尋找想要監聽和接收的Notification。NSNotificationCenter文檔中,關於加入Observer的方法-addObserver:selector:name:object:,當給name參數賦值nil時,將可以監聽到所有的notification:

notificationName: The name of the notification for which to register the observer; that is, only notifications with this name are delivered to the observer. If you pass nil, the notification center doesn’t use a notification’s name to decide whether to deliver it to the observer.

因此可以用它來監測所有的Notification,並從中找到自己所需要的來進行處理:

<code class="objc hljs objectivec">-(<span class="hljs-keyword">id</span>)init { 
    <span class="hljs-keyword">if</span> (<span class="hljs-keyword">self</span> = [<span class="hljs-keyword">super</span> init]) { 
        [[<span class="hljs-built_in">NSNotificationCenter</span> defaultCenter] addObserver:<span class="hljs-keyword">self</span> 
            selector:<span class="hljs-keyword">@selector</span>(notificationListener:) 
                name:<span class="hljs-literal">nil</span> object:<span class="hljs-literal">nil</span>]; 
    } 
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">self</span>; 
} 

-(<span class="hljs-keyword">void</span>)notificationListener:(<span class="hljs-built_in">NSNotification</span> *)noti {   
    <span class="hljs-built_in">NSLog</span>(<span class="hljs-string">@" Notification: %@"</span>, [noti name]);   
} 
</code>

編譯重啟後在控制台得到的輸出:

Xcode 插件制作入門

當然如果只是打印名字的話可能幫助不大,也許你需要從noti的object或者userinfo中獲得更多的信息。按條件打印,配合控制台的搜索進行尋找會是一個不錯的方法。

Hack私有API

用OC的動態特性可以做很多事,比如在運行時替換掉某個Xcode的方法。記住Xcode本身也是Cocoa程序,本質上和我們用Xcode所開發 的程序沒有太大區別。因此如果可以知道Xcode在進行某些操作時候的方法的話,就可以將該方法與我們自己實現的方法進行運行時調換,從而改為執行我們自 己的方法。這便是運行時的Method Swizzling(或者叫Monkey patch,管他呢),這在smalltalk類語言中是一種很有趣和方便的做法,關於這方面更詳細的,我以前寫過一篇關於OC運行時特性的文章。當時提到的method swizzling方法並沒有對交換的函數進行檢查等工作,通用性也比較差。現在針對OC已經有比較成熟的一套方法交換機制了,其中比較有名的有rentzsch的jrswizzle以及OC社區的MethodSwizzling實現。

有了方法交換的辦法,接下來需要尋找要交換的方法。Xcode所使用的所有庫都包含在Xcode.app/Contents/的 Frameworks,SharedFrameworks和OtherFrameworks三個文件夾下。其中和Xcode關系最為直接以及最為重要的是 Frameworks中的IDEKit和IDEFoundation,以及SharedFrameworks中的DVTKit和 DVTFoundation四個。其中DVT前綴表示Developer Toolkit,IDE和IDEFoundation中的類基本是DVT中類的子類。這四個framework將是我們在開發改變Xcode默認行為的 Xcode插件時最主要要打交道的。另外如果想對IB進行注入,可能還需要用到Frameworks下的 IBAutolayoutFoundation(待確定)。關於這些framework中的私有API,可以使用class-dump很簡單地將頭文件提取出來。當然,也有人為懶人們完成了這個工作,probablycorey的xcode-class-dump中有絕大部分類的頭文件。

作為Demo,我們將簡單地完成一個方法交換:在補全代碼時,我們簡單地輸出一句log。

MethodSwizzle

為了交換方法,可以直接用現成的MethodSwizzle實現。MethodSwizzle可以在這裡找到。將.h和.m導入插件工程即可~

尋找對應API

通過搜索,補全代碼的功能定義在DVKit中的DVTTextCompletionController類,其中有一個方法為- (BOOL)acceptCurrentCompletion,猜測返回的布爾值是否接受當前的補全結果。由於這些都是私有API,因此需要在我們的工程 中自己進行聲明。在新建文件中的C and C++中選Header File,為工程加入一個Header文件,並加入一下代碼:

<code class="objc hljs objectivec"><span class="hljs-class"><span class="hljs-keyword">@interface</span> <span class="hljs-title">DVTTextCompletionController</span> : <span class="hljs-title">NSObject</span> </span>
- (<span class="hljs-built_in">BOOL</span>)acceptCurrentCompletion; 
<span class="hljs-keyword">@end</span>
</code>

然後需要將DVKit.framework添加到工程中,在/Applications/Xcode.app/Contents /SharedFrameworks中找到DVTKit.framework,拷貝到任意正常能訪問到的目錄下,然後在插件工程的Build Phases中加入framework。嗯?你說找不到DVTKit.framework?親,私有框架當然找不到,點擊Add Other...然後去剛才copy出來的地方去找吧..

Xcode 插件制作入門

最後便是加入方法交換了~新建一個DVTTextCompletionController的Category,命名為PluginDemo

Xcode 插件制作入門

import之前定義的header和MethodSwizzle.h,在DVTTextCompletionController+PluginDemo.m中加入下面實現:

<code class="objc hljs objectivec">+ (<span class="hljs-keyword">void</span>)load
{
    MethodSwizzle(<span class="hljs-keyword">self</span>,
                  <span class="hljs-keyword">@selector</span>(acceptCurrentCompletion),
                  <span class="hljs-keyword">@selector</span>(swizzledAcceptCurrentCompletion));
}

- (<span class="hljs-built_in">BOOL</span>)swizzledAcceptCurrentCompletion {  
<span class="hljs-built_in">NSLog</span>(<span class="hljs-string">@"acceptCurrentCompletion is called by %@"</span>, <span class="hljs-keyword">self</span>);  
<span class="hljs-keyword">return</span> [<span class="hljs-keyword">self</span> swizzledAcceptCurrentCompletion];  
} 
</code>

+load方法在每個NSObject類或子類被調用時都會被執行,可以用來在runtime配置當前類。這裡交換了 DVTTextCompletionController的acceptCurrentCompletion方法和我們自己實現的 swizzledAcceptCurrentCompletion方法。在swizzledAcceptCurrentCompletion中,先打印了 一句log,輸出相應該方法的實例。接下來似乎是調用了自己,但是實際上swizzledAcceptCurrentCompletion的方法已經和原 來的acceptCurrentCompletion交換,因此這裡實際調用的將是原來的方法。那麼這段代碼所做的就是將Xcode想調用原來的 acceptCurrentCompletion的行為,改變成了先打印一個log,之後再進行原來的acceptCurrentCompletion調 用。

編譯,重啟Xcode,打開一個工程隨便輸入點東西,讓補全出現。控制台中的輸出符合我們的預期:

Xcode 插件制作入門

太棒了,有了對私有API的注入,能做的事情大為擴展了。

研究Xcode的View Hierarchy

另外一種常見的插件行為是修改某些界面。再一次說明,Xcode是一個標准Cocoa程序,一切都是那麼熟悉(如果你為Cocoa或者 CocoaTouch開發的話,應該是很熟悉)。拿到整個App的Window,然後依次遞歸打印subview。stackoverflow上有一個UIView的版本,稍微改變一下就可以得到一個NSView版本。新建一個NSView的Dumping Category,加入如下實現:

<code class="objc hljs objectivec">-(<span class="hljs-keyword">void</span>)dumpWithIndent:(<span class="hljs-built_in">NSString</span> *)indent {
    <span class="hljs-built_in">NSString</span> *class = NSStringFromClass([<span class="hljs-keyword">self</span> class]);
    <span class="hljs-built_in">NSString</span> *info = <span class="hljs-string">@""</span>;
    <span class="hljs-keyword">if</span> ([<span class="hljs-keyword">self</span> respondsToSelector:<span class="hljs-keyword">@selector</span>(title)]) {
        <span class="hljs-built_in">NSString</span> *title = [<span class="hljs-keyword">self</span> performSelector:<span class="hljs-keyword">@selector</span>(title)];
        <span class="hljs-keyword">if</span> (title != <span class="hljs-literal">nil</span> &amp;&amp; [title length] &gt; <span class="hljs-number">0</span>) {
            info = [info stringByAppendingFormat:<span class="hljs-string">@" title=%@"</span>, title];
        }
    }
    <span class="hljs-keyword">if</span> ([<span class="hljs-keyword">self</span> respondsToSelector:<span class="hljs-keyword">@selector</span>(stringValue)]) {
        <span class="hljs-built_in">NSString</span> *string = [<span class="hljs-keyword">self</span> performSelector:<span class="hljs-keyword">@selector</span>(stringValue)];
        <span class="hljs-keyword">if</span> (string != <span class="hljs-literal">nil</span> &amp;&amp; [string length] &gt; <span class="hljs-number">0</span>) {
            info = [info stringByAppendingFormat:<span class="hljs-string">@" stringValue=%@"</span>, string];
        }
    }
    <span class="hljs-built_in">NSString</span> *tooltip = [<span class="hljs-keyword">self</span> toolTip];
    <span class="hljs-keyword">if</span> (tooltip != <span class="hljs-literal">nil</span> &amp;&amp; [tooltip length] &gt; <span class="hljs-number">0</span>) {
        info = [info stringByAppendingFormat:<span class="hljs-string">@" tooltip=%@"</span>, tooltip];
    }

    <span class="hljs-built_in">NSLog</span>(<span class="hljs-string">@"%@%@%@"</span>, indent, class, info);

    <span class="hljs-keyword">if</span> ([[<span class="hljs-keyword">self</span> subviews] count] &gt; <span class="hljs-number">0</span>) {  
        <span class="hljs-built_in">NSString</span> *subIndent = [<span class="hljs-built_in">NSString</span> stringWithFormat:<span class="hljs-string">@"%@%@"</span>, indent, ([indent length]/<span class="hljs-number">2</span>)%<span class="hljs-number">2</span>==<span class="hljs-number">0</span> ? <span class="hljs-string">@"| "</span> : <span class="hljs-string">@": "</span>];  
        <span class="hljs-keyword">for</span> (<span class="hljs-built_in">NSView</span> *subview <span class="hljs-keyword">in</span> [<span class="hljs-keyword">self</span> subviews]) {  
            [subview dumpWithIndent:subIndent];  
        }  
    }  
} 
</code>

在合適的時候(比如點擊某個按鈕時),調用下面一句代碼,便可以打印當前Xcode的結構,非常方便。這對了解Xcode的構成和如何搭建一個如Xcode般復雜的程序很有幫助~

<code class="hljs css"><span class="hljs-attr_selector">[[[NSApp mainWindow]</span> <span class="hljs-tag">contentView</span>] <span class="hljs-tag">dumpWithIndent</span>:<span class="hljs-at_rule">@<span class="hljs-keyword">""];</span>
</span></code>

在結果控制台中的輸出結果類似這樣:

Xcode 插件制作入門

根據自己需要去去相應的view吧~然後配合方法交換,基本可以做到盡情做想做的事情了。

最後的小bonus

/Applications/Xcode.app/Contents/Frameworks/IDEKit.framework/Versions /A/Resources中有不少Xcode界面用的圖片,pdf,png和tiff格式都有,想要自定義run,stop按鈕或者想要讓斷點標記從藍色 塊變成機器貓頭像什麼的…應該是可能的~

/Applications/Xcode.app/Contents/PlugIns目錄裡有很多Xcode自帶的“官方版”外掛插件,顯然通過 class-dump和注入的方法,你可以為Xcode的插件寫插件...嗯~比如改變debugger的行為或者讓plist編輯器更聰明,就是這樣 的。

希望Apple能提供為Xcode編寫插件的支持,所有東西都需要摸索雖然很有趣,但是也比較花時間。

另外,github等代碼托管網站上有不少大神們寫的插件,都開源放出。這些必須是學習插件編寫的最優秀的教材和參考:

  • mneorr / Alcatraz Xcode的包管理插件,管理其他插件的插件
  • onevcat / VVDocumenter-Xcode 幫助快速寫文檔注釋的插件,自動提取參數返回值等
  • omz / ColorSense-for-Xcode 在UIColor/NSColor上顯示出對應的顏色
  • omz / Dash-Plugin-for-Xcode 在Xcode中集成Dash,方便看文檔
  • omz / MiniXcode 隱藏Xcode臃腫的工具欄,獲得更大的可視空間
  • ksuther / KSImageNamed-Xcode 輸入imageNamed的時候自動補完圖片名稱
  • JugglerShu / XVim 將Xcode編輯器改造成Vim
  • davekeck / Xcode-4-Fixins 修正一些Xcode的bugs(應該已經沒有太大用了)
  • 0xced / CLITool-InfoPlist 方便修改Info.plist為CLI目標的插件
  • questbeat / Lin 為NSLocalizedString顯示補全
  • stefanceriu / SCXcodeMiniMap 在側邊顯示代碼小地圖

好了,就到這裡吧。VVPlugInDemo的工程文件我放到了github上,有需要的話您可以從這裡下載並作為參考和起始來使用。謝謝您看完這麼長的文。正如一開始所說的,我自己水平十分有限,因此錯誤和不當之處還懇請大家輕噴多原諒,並幫助我改正,再次謝謝~

本站點采用知識共享 署名-非商業性使用-相同方式共享 4.0 國際 許可協議 基於 Ghost 搭建,感謝 Digital Ocean 為本站提供穩定的 VPS 服務 © 2015 - 本站由 @onevcat 創建,采用 Vno 作為主題
  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved