MagicPrefs plugins API

The API is currently very limited, it is subject to be expanded in the future.

All the details are below, MPPluginInterface.h needs to be downloaded and used as it is.

You can download the MPPExample.zip example project for a plugin that illustrates both basic functionality and pref settings.

A example MPPExample.plist shows the structure of the file that needs to reside at your app's url along with the zip archive of the plugin.

Feel free to distibute your plugin any way you like, if you want it included in the list shown under the plugin preferences in MagicPrefs i reserve the right to test it that everything is kosher.

REQUIREMENTS:
  • - the exact code listed here
    - the exact project settings listed here
    - icon.png size 128x128
    - [PluginName] is your project name, the name of the plugin and the main class
    - [NSUserDefaults standardUserDefaults] points to com.vladalexa.MagicPrefs.MagicPrefsPlugins.plist, you are only allowed to write settings under [PluginName] dictionary, never in the root of the plist
    - preferences are optional, but if you implement them they must use the following names (Preferences.h Preferences.m Preferences.xib MPPlugin[PluginName]PreferencesEvent)

 

Required code (or the more complex one with preferences code_preferences.txt)

[PluginName].h
#import "MPPluginInterface.h"
@interface [PluginName] : NSObject <MPPluginProtocol> {
}

[PluginName].m
#import "[PluginName].h"
static NSBundle* pluginBundle = nil;
@implementation [PluginName]

+ (BOOL)initializeClass:(NSBundle*)theBundle {
	if (pluginBundle) {
		return NO;
	}
	pluginBundle = [theBundle retain];
	return YES;
}

+ (void)terminateClass {
	if (pluginBundle) {
		[pluginBundle release];
		pluginBundle = nil;
	}
}

- (id)init{
    self = [super init];
    if(self != nil) {		
		NSString *bundleId = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleIdentifier"];					
		if ([bundleId isEqualToString:@"com.apple.systempreferences"]) return self;	
				
		//your initialization here						
    }
    return self;
}

Required settings

Xcode > New Project > Framework & Library > Bundle > Cocoa > Choose

(Add the main class files now and build your project to see the GCC settings section, Xcode3 bug)

Project Settings > Build > Objective-C Garbage Collection : supported
Project Settings > Build > Wrapper Extension : MPplugin
Project Settings > Build > Deployment SDK: 10.6

Project Settings > Build > Code Signing Identity: your developer certificate

(with Xcode 3 check that the Targets > [PluginName] > Build settings are the same)

Info.plist > Principal Class : [PluginName]
Info.plist > Bundle Identifier : com.yourcompany.MagicPrefs.[PluginName]
Info.plist > NSHumanReadableCopyright : [Your name/company name]
Info.plist > MPUrlString : [http:// url to a page for the plugin (is also used for update [PluginName].MPplugin.zip and [PluginName].plist must exist there)]
Info.plist > MPDescriptionString : [a description of the plugin]

NOTES

  • - if a [PluginName].prefPane exists in your bundle it will be copied to ~/Library/PreferencePanes when the plugin is loaded and deleted from there if the plugin is turned off, also the preferences will show a link to the pref pane
    - if your plugin is distributed trough a app in the Mac App Store use a link to in in the MPUrlString (make sure it starts with macappstore:// not http://)
    - plugins will be loaded from either ~/Library/Application Support/MagicPrefs/PlugIns , /Library/Application Support/MagicPrefs/PlugIns or yourmacstore.app/Contents/PlugIns
    - for plugins distributed with Mac App Store apps the validity of both the app signature and receipt will be tested, if either fails the plugin will not be loaded, the bundle id of the app that distributes must be the same as the plugin's minus ".MagicPrefs"
    - for plugins distributed dirrectly from your website [PluginName].plist will be parsed as a dictionary with the keys being version numbers and the value as string containing the release notes for that version

TIPS

  • - replace all occurrences of [NSBundle mainBundle] with pluginBundle (or [NSBundle bundleForClass:[self class]]) in order to properly access resources from your bundle not the plugin loader's bundle
    eg:
    NSImage *foo = [NSImage imageNamed:@"bar.png"];
    to
    NSImage *foo = [[[NSImage alloc] initWithContentsOfFile:[[NSBundle bundleForClass:[self class]] pathForImageResource:@"bar.png"]] autorelease];

ACTION INTEGRATION

NSDistributedNotification named MPPlugin[PluginName]Event

events : [notification name] [title]
optionally if a icon named [notification name].png exists in the plugin's bundle resources it will be loaded

 

DIALOGS

//show a dialog
[[NSNotificationCenter defaultCenter] postNotificationName:@"MPpluginsEvent" object:nil userInfo:
[NSDictionary dictionaryWithObjectsAndKeys:@"doAlert",@"what",@"A dialog title.",@"title",@"A dialog message",@"text",@"OK",@"action",nil]
];

//send a growl notification
[[NSNotificationCenter defaultCenter] postNotificationName:@"MPpluginsEvent" object:nil userInfo:
[NSDictionary dictionaryWithObjectsAndKeys:@"doGrowl",@"what",@"A growl title",@"title",@"A growl message",@"message",nil]
];

//show a main dialog
[[NSDistributedNotificationCenter defaultCenter] postNotificationName:@"MPcoreMainEvent" object:nil userInfo:
[NSDictionary dictionaryWithObjectsAndKeys:@"doAlert",@"what",@"A dialog title.",@"title",@"A dialog message",@"text",@"Button Action",@"action",nil]
];

//show a main notification
[[NSDistributedNotificationCenter defaultCenter] postNotificationName:@"MPcoreMainEvent" object:nil userInfo:
[NSDictionary dictionaryWithObjectsAndKeys:@"doNotif",@"what",@"square",@"image",@"Some Text",@"text",nil]
];

//set the dock icon to a image on the disk
[[NSDistributedNotificationCenter defaultCenter] postNotificationName:@"MPpluginsEvent" object:nil userInfo:
[NSDictionary dictionaryWithObjectsAndKeys:@"showDockImage",@"what",@"/the/path/to/a/image/name.ext",@"path",nil]
];