Примечание: за основу для написания данного топика был взят плагин ColorSense-for-Xcode.
Как я уже говорил, официально, Xcode не предоставляет публичного API для написания плагинов. При старте приложения, Xcode просматривает папку с плагинами (~/Library/Application Support/Developer/Shared/Xcode/Plug-ins) и загружает найденные (.xcplugin).
На самом деле, простенький плагин пишется за несколько часов, что вы и увидите далее.
Создаем новый Xcode проект
Плагин — всего навсего OS X бандл, создадим новый проект с типом ‘bundle’.
При создании проекта, нужно убедиться, что ARC выключен, так как Xсode работает под управлением garbage collector, это же распространяется и на плагин.
Открываем таргет плагина и выставляем следующие настройки:
- XC4Compatible = YES
- XCPluginHasUI = NO
- XCGCReady = YES
- Principal class = {название главного класса плагина}
Конфигурируем Build Settings
Идем в build settings и выставляем следующие настройки:
- Installation Build Products Location = ${HOME}
- Installation Directory = /Library/Application Support/Developer/Shared/Xcode/Plug-ins
- Deployment Location = YES
- Wrapper extension = xcplugin
Также, нужно добавить несколько user-definded settings:
- GCC_ENABLE_OBJC_GC = supported
- GCC_MODEL_TUNING = G5
Мы указали, куда должен устанавливаться наш плагин после сборки. Важно: с отладкой плагинов все печально, и вам придется перезапускать Xcode после каждого билда.
Пишем плагин
Создадим новый класс и назовем его тем именем, что укзали в настройке Principal class. Когда Xcode загружает плагин, будет вызван метод + (void) pluginDidLoad: (NSBundle*) plugin, в котором можно произвести начальную настройку плагина (как правило, плагин — это синглтон).
+ (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; }
в обработчике applicationDidFinishLaunching: мы можем непосредственно исполнять логику плагина. В нашем случае, мы подпишемся на нотификации изменения положения курсора в редакторе, а также добавим новый пункт в меню Edit.
- (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]; } }
Для примера, будем выводить по изменению позиции курсора строку:
- (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]; }
Простейший, ничего полезного не делающий плагин готов!
Замечания
Как я уже говорил выше, отладка плагина возможно только при помощи перезапуска Xcode (когда я писал плагин, я везде расставлял NSAlert и выводил нужную информацию). Из-за того, что документации как таковой нет, чтобы найти нужный вид в иерархии, или узнать какие нотификации отсылются, необходимо выполнить тот же самый трюк: вывести информацию либо в лог, либо в алерт. Если плагин падает, то Xcode не запустится, а плагин нужно удалить из ‘~/Library/Application Support/Developer/Shared/Xcode/Plug-ins’.
Более функциональный пример
Предпосылкой для написания статьи стал написанный мной небольшой плагин, который отображает маски авторазмера для UIView:
Исходник на github.
Спасибо за внимание!
ссылка на оригинал статьи http://habrahabr.ru/post/163795/
Добавить комментарий