如何创建Apple邮件插件

iPh*_*eDv 27 macos plugins cocoa objective-c

我将为OS X Mail.app应用程序创建一个邮件插件,以获得一些额外的功能.

我不知道从哪里开始,因为没有插件的官方文档.

任何人都可以帮助我,我该如何开始这个项目.是否有任何初始链接或教程,请建议?

Ale*_*hek 50

如上所述,编写Apple Mail插件并不简单,因为它只有一个私有插件API,完全没有文档,可以随任何新版本的Mail.app进行更改.最好的代码示例是GPGMail,它是开源的并且仍处于活动状态(已经在Yosemite支持下工作).这是我成功开始的事情(一旦完成就将它放在github上):

如何构建一个最小的Apple Mail插件(从Mavericks和Xcode 6.0.1开始)

  1. 你需要在XCode中创建一个OSX"Bundle"项目
  2. 包装器扩展名是mailbundle(在项目构建设置中的包装下)
  3. 需要存储一个bundle ~/Library/Mail/Bundles(作为Build Phase添加一个Copy Files操作,将其作为绝对路径目标,并从build /文件夹中添加*.mailbundle作为要复制的项)
  4. 对于开发,我已经/Applications/Mail.app在我的运行方案中设置为可执行文件,以便在XCode中运行将构建它,复制包并启动邮件; 请注意,此时您将收到来自Mail的错误,指出您的插件无法启动并被禁用
  5. 你需要SupportedPluginCompatibilityUUIDs在Info.plist中提供一个列表,我从GPGMail中窃取它,这些更改与新的Mail/OSX版本
  6. 使用class-dump从Mail.app的私有API生成头文件
  7. 起点是MVMailBundle,你必须继承,并有一个registerBundle方法来勾住你
    • 我从一个小的MVMailBundle.h头文件中的巨大生成的头文件中提取了它,以包含所需的位置(由GPGMail完成)
  8. 创建一个MyMailBundle继承自的新类NSObject
    • 它需要一种initialize方法
    • 并在Info.plist中将其设置为"Principle class",以便在Mail.app加载包时运行它
#import <Cocoa/Cocoa.h>

@interface MyMailBundle : NSObject

+ (void)initialize;
@end
Run Code Online (Sandbox Code Playgroud)
  1. initialize实现:以前,你可以使用简单的方式直接继承在信箱做,但是,因为Objective-C的64位运行时,你必须使用动态的方式由GPGMail完成:
    • 使用NSClassFromString动态获取MVMailBundle
    • class_setSuperclass<objc/runtime.h>有自己的类继承它
    • 然后打电话registerBundle给它MVMailBundle(需要包括MVMailBundle.h)
#import <objc/runtime.h>
#import "MVMailBundle.h"
#import "MyMailBundle.h"

@implementation MyMailBundle

+ (void)initialize
{
    NSLog(@"Loading MyMail plugin...");

    // since 64-bit objective-c runtimes, you apparently can't load
    // symbols directly (i.e. through class inheritance) and have to
    // resort to NSClassFromString
    Class mvMailBundleClass = NSClassFromString(@"MVMailBundle");

    // If this class is not available that means Mail.app
    // doesn't allow plugins anymore or has changed the API
    if (!mvMailBundleClass)
        return;

    // dynamically change super class hierarchy
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated"
    class_setSuperclass([self class], mvMailBundleClass);
#pragma GCC diagnostic pop

    // register our plugin bundle in mail
    [[((MyMailBundle *)self) class] registerBundle];

    NSLog(@"Done registering MyMail plugin.");
}
@end
Run Code Online (Sandbox Code Playgroud)
  1. 添加一些NSLog日志记录调用来验证正确的事情,当在XCode中运行/调试Mail.app时,或者在Console.app的系统日志中,它们将在XCode的控制台中可见.
  2. 这应该成功运行Mail中的插件没有错误!
  3. 接下来的步骤涉及疯狂的事情,如MethodSwizzlingClassPosing来修改Mail的行为,其中GPGMail可以是一个有用的示例.(我自己还没有去过那里)

作为参考,以下是一些帮助我的资源:

  • 您可以使用以下命令获取当前正在运行的系统的UUID:`cat /Applications/Mail.app/Contents/Info.plist | grep UUID -A 1` (3认同)
  • OSX 10.10.1上Mail.app的插件UUID是`7C051997-F45A-4523-B053-2D262F94C775` (2认同)