Xcode plugins 开发

Xcode plugins 开发

@(iOS)[Xcode]

背景介绍

  • 搞这个呢,主要是项目中要用的字段太多了,有时一个界面要一百多个字段(一个字段一个属性对应一个View),每次赋值粘贴都要疯了。前几天写了个python小脚本,使用起来不是很方便,所以冒出这个想法:做一个小插件试试。

原理

  • 在Xcode启动的时候,Xcode将会寻找位于~/Library/Application Support/Developer/Shared/Xcode/Plug-ins文件夹中的后缀名为.xcplugin的bundle作为插件进行加载(运行其中的可执行文件),这就可以令我们光明正大合法合理地将我们的代码注入(虽然这个词有点不好听)Xcode,并得到运行。因此,想要创建Xcode插件,我们需要创建Bundle工程并将编译的bundle放到上面所说的插件目录中去,这就是Xcode插件的原理。
  • 因为是注入方式添加插件,所以如果插件有问题闪退,那么Xcode也会闪退。

项目配置

  • Xcode plugins 开发的话,没有任何官方文档,而且在新建项目时要配置很多参数,作为小白的我可是搞了大半天也没配置正确,这里使用大神的template(Xcode plugins)来创建项目。
  • 通过Alcatraz安装模板

Alt text

  • 新建工程

Alt text

  • 其中几处关键的地方是plist中新增两个BOOL值,通过模板已经设置过
    • XCPluginHasUI = NO
    • XC4Compatible = YES
    • Alt text
  • 然后就是Bulid Setting 里设置的参数
    • Alt text

示例代码

//
//  SLQPluginDemo.m
//  SLQPluginDemo
//
//  Created by Christian on 16/7/30.
//  Copyright © 2016年 MrSong. All rights reserved.
//

#import "SLQPluginDemo.h"

static SLQPluginDemo *sharedPlugin; // 单例对象

@implementation SLQPluginDemo

#pragma mark - Initialization

+ (void)pluginDidLoad:(NSBundle *)plugin
{
    NSArray *allowedLoaders = [plugin objectForInfoDictionaryKey:@"me.delisa.XcodePluginBase.AllowedLoaders"];
    if ([allowedLoaders containsObject:[[NSBundle mainBundle] bundleIdentifier]]) {
        sharedPlugin = [[self alloc] initWithBundle:plugin];
    }
}

+ (instancetype)sharedPlugin
{
    return sharedPlugin;
}

- (id)initWithBundle:(NSBundle *)bundle
{
    if (self = [super init]) {
        // reference to plugin's bundle, for resource access
        _bundle = bundle;
        // NSApp may be nil if the plugin is loaded from the xcodebuild command line tool
        if (NSApp && !NSApp.mainMenu) {
            [[NSNotificationCenter defaultCenter] addObserver:self
                                                     selector:@selector(applicationDidFinishLaunching:)
                                                         name:NSApplicationDidFinishLaunchingNotification
                                                       object:nil];
        } else {
            [self initializeAndLog];
        }
    }
    return self;
}

- (void)applicationDidFinishLaunching:(NSNotification *)notification
{
    [[NSNotificationCenter defaultCenter] removeObserver:self name:NSApplicationDidFinishLaunchingNotification object:nil];
    [self initializeAndLog];
}

- (void)initializeAndLog
{
    NSString *name = [self.bundle objectForInfoDictionaryKey:@"CFBundleName"];
    NSString *version = [self.bundle objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
    NSString *status = [self initialize] ? @"loaded successfully" : @"failed to load";
    NSLog(@"🔌 Plugin %@ %@ %@", name, version, status);
}

#pragma mark - Implementation

- (BOOL)initialize
{
    // Create menu items, initialize UI, etc.
    // Sample Menu Item:
    NSMenuItem *menuItem = [[NSApp mainMenu] itemWithTitle:@"Edit"];
    if (menuItem) {
        [[menuItem submenu] addItem:[NSMenuItem separatorItem]];
        NSMenuItem *actionMenuItem = [[NSMenuItem alloc] initWithTitle:@"Do Action" action:@selector(doMenuAction) keyEquivalent:@""];
        //[actionMenuItem setKeyEquivalentModifierMask:NSAlphaShiftKeyMask | NSControlKeyMask];
        [actionMenuItem setTarget:self];
        [[menuItem submenu] addItem:actionMenuItem];
        return YES;
    } else {
        return NO;
    }
}

// 相应点击
- (void)doMenuAction
{
    [self loadWindowAndPutInFront];
}

// 弹出窗口
- (void)loadWindowAndPutInFront {
    if (!self.windowController.window)
        self.windowController = [[TransferViewController alloc] initWithBundle:self.bundle];
    
    [[self.windowController window] makeKeyAndOrderFront:self];
}
@end
  • 在点击doMenuAction处理自己要处理的事情就行,可以弹出一个窗口之类的。或者只是添加监听。

提交到Alcatraz

   {
        "name": "OCPropertyTransfer",
        "url": "https://github.com/slq0378/OCPropertyTransfer",
        "description": "Transfer assigned string to property",
        "screenshot": "https://github.com/slq0378/OCPropertyTransfer/blob/master/OCPropertyTransfer%E4%BD%BF%E7%94%A8.gif"
    },
  • 接着就是要测试一下自己添加的格式是否正确,使用ruby测试
    • sudo gem install rspec
    • 到工程目录,执行rspec
song$ rspec
.......

Finished in 0.07776 seconds (files took 0.33704 seconds to load)
7 examples, 0 failures

其他

参考

插件开发
提交Xcode插件到Alcatraz

posted @ 2019-05-01 12:15  struggle_time  阅读(239)  评论(0编辑  收藏  举报