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
安装模板
- 新建工程
- 其中几处关键的地方是plist中新增两个BOOL值,通过模板已经设置过
XCPluginHasUI = NO
XC4Compatible = YES
- 然后就是Bulid Setting 里设置的参数
示例代码
//
// 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
- 主要过程就是下载这个仓库 https://github.com/supermarin/alcatraz-packages
- 然后添加自己的项目到
plugins
数组中,格式如下
{
"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
-
每一问题,就可以push 到github了
-
其他
- 其中安装
rspec
出了问题,解决方法如下 - 通过brew重新安装ruby
参考
本文来自博客园,作者:struggle_time,转载请注明原文链接:https://www.cnblogs.com/songliquan/p/12784428.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?