Writing your Xcode plugin
- Tutorial
Often there are situations when the functionality of the IDE you want to expand. It is lucky if the developer is provided with the tools and documentation in order to do this. Unfortunately, in the case of c Xcode, this is not the case. Documentation of features has stopped on the version of Xcode 3.0 , so no one guarantees that in the next version the plugin you wrote will work.
Note: the ColorSense-for-Xcode plugin was taken as the basis for writing this topic .
As I said, officially, Xcode does not provide a public API for writing plugins. When the application starts, Xcode scans the plugins folder (~ / Library / Application Support / Developer / Shared / Xcode / Plug-ins) and downloads the ones found (.xcplugin).
In fact, a simple plug-in is written in a few hours, which you will see later.
The plugin is just an OS X bundle, create a new project with the type 'bundle'.

When creating a project, you need to make sure that ARC is turned off, since Xcode works under the control of the garbage collector, the same applies to the plugin.
Open the plugin’s target and set the following settings:

We go to build settings and set the following settings:
Also, you need to add a few user-definded settings:
We indicated where our plugin should be installed after assembly. Important: with debugging plugins, everything is sad, and you will have to restart Xcode after each build.
Let's create a new class and call it the name that you found in the setting of the Principal class. When Xcode loads the plugin, the + (void) pluginDidLoad: (NSBundle *) plugin method will be called , in which the plugin can be configured initially (usually the plugin is a singleton).
in the applicationDidFinishLaunching handler : we can directly execute the plugin logic. In our case, we will subscribe to notifications of changes in the cursor position in the editor, and also add a new item in the Edit menu.
For example, we will output a line by changing the cursor position:
The simplest, not doing anything useful plugin is ready!
As I said above, debugging a plugin is only possible by restarting Xcode (when I wrote the plugin, I put NSAlert everywhere and displayed the necessary information). Due to the fact that there is no documentation as such, in order to find the desired view in the hierarchy, or to find out which notifications are sent, it is necessary to perform the same trick: display the information either in the log or in the alert. If the plugin crashes, then Xcode will not start, and the plugin needs to be removed from '~ / Library / Application Support / Developer / Shared / Xcode / Plug-ins'.
A prerequisite for writing this article was a small plugin that I wrote, which displays auto-size masks for UIView:

Source on github .
Thanks for attention!
Note: the ColorSense-for-Xcode plugin was taken as the basis for writing this topic .
As I said, officially, Xcode does not provide a public API for writing plugins. When the application starts, Xcode scans the plugins folder (~ / Library / Application Support / Developer / Shared / Xcode / Plug-ins) and downloads the ones found (.xcplugin).
In fact, a simple plug-in is written in a few hours, which you will see later.
Create a new Xcode project
The plugin is just an OS X bundle, create a new project with the type 'bundle'.

When creating a project, you need to make sure that ARC is turned off, since Xcode works under the control of the garbage collector, the same applies to the plugin.
Open the plugin’s target and set the following settings:
- XC4Compatible = YES
- XCPluginHasUI = NO
- XCGCReady = YES
- Principal class = {name of the main class of the plugin}

Configure Build Settings
We go to build settings and set the following settings:
- Installation Build Products Location = $ {HOME}
- Installation Directory = / Library / Application Support / Developer / Shared / Xcode / Plug-ins
- Deployment Location = YES
- Wrapper extension = xcplugin
Also, you need to add a few user-definded settings:
- GCC_ENABLE_OBJC_GC = supported
- GCC_MODEL_TUNING = G5
We indicated where our plugin should be installed after assembly. Important: with debugging plugins, everything is sad, and you will have to restart Xcode after each build.
Writing a plugin
Let's create a new class and call it the name that you found in the setting of the Principal class. When Xcode loads the plugin, the + (void) pluginDidLoad: (NSBundle *) plugin method will be called , in which the plugin can be configured initially (usually the plugin is a singleton).
+ (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;
}
in the applicationDidFinishLaunching handler : we can directly execute the plugin logic. In our case, we will subscribe to notifications of changes in the cursor position in the editor, and also add a new item in the Edit menu.
- (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:@"Show autoresizing masks"
action:@selector(toggleMasks:)
keyEquivalent:@"m"];
[newMenuItem setTarget:self];
[newMenuItem setKeyEquivalentModifierMask:NSAlternateKeyMask];
[[editMenuItem submenu] addItem:newMenuItem];
[newMenuItem release];
}
}
For example, we will output a line by changing the cursor position:
- (void)selectionDidChange:(NSNotification*)notification {
if ([[notification object] isKindOfClass:[NSTextView class]]) {
NSTextView* textView = (NSTextView *)[notification object];
if (![[NSUserDefaults standardUserDefaults] boolForKey:kDLShowSizingsPreferencesKey]) {
return;
}
NSArray* selectedRanges = [textView selectedRanges];
if (selectedRanges.count >= 1) {
NSRange selectedRange = [[selectedRanges objectAtIndex:0] rangeValue];
NSString *text = textView.textStorage.string;
NSRange lineRange = [text lineRangeForRange:selectedRange];
NSString *line = [text substringWithRange:lineRange];
}
NSAlert *alert = [[[NSAlert alloc] init] autorelease];
[alert setMessageText:line];
[alert runModal];
}
The simplest, not doing anything useful plugin is ready!
Remarks
As I said above, debugging a plugin is only possible by restarting Xcode (when I wrote the plugin, I put NSAlert everywhere and displayed the necessary information). Due to the fact that there is no documentation as such, in order to find the desired view in the hierarchy, or to find out which notifications are sent, it is necessary to perform the same trick: display the information either in the log or in the alert. If the plugin crashes, then Xcode will not start, and the plugin needs to be removed from '~ / Library / Application Support / Developer / Shared / Xcode / Plug-ins'.
More functional example
A prerequisite for writing this article was a small plugin that I wrote, which displays auto-size masks for UIView:

Source on github .
Thanks for attention!