BSPluginLoader
Language: Objective-C, Author: Karsten
License: Public domain
BSPluginLoader is a loadable bundle that allows applications to easily load plugins. The plugins can be installed in any applications support folder or in the application's bundle itself.
BSPluginLoader source preview
//
// BSPluginLoader.m
// BSPluginLoader
//
// Created by Karsten Kusche on 30.03.07.
//
/*
todos:
- move stuff to instance side
- make loader more customizable (execute method with object)
*/
#import "BSPluginLoader.h"
@implementation BSPluginLoader
- (NSArray*)domainPathes
{
// domain pathes are used as a basis for searching for plugins.
// appending subfolders like 'plugins' to them should list all folders that are used to store plugins.
static NSMutableArray* domains;
if (domains)
{
return domains;
}
domains = [[NSMutableArray alloc] init];
//get the processes name, it's used as subfolder in the app-support folders
NSString* appName = [[NSProcessInfo processInfo] processName];
NSEnumerator* basicDomains = [[NSArray arrayWithObjects:
@"~/Library/Application Support/",
@"/Library/Application Support/",
@"/System/Library/Application Support/",
nil] objectEnumerator];
NSString* domain;
while (domain = [basicDomains nextObject])
{
[domains addObject:[[domain stringByExpandingTildeInPath] stringByAppendingPathComponent:appName]];
}
// finally add the bundle's contents folder
[domains addObject:[[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:@"Contents"]];
return domains;
}
- (void)initBundle:(NSBundle*)bundle
{
Class class = [bundle principalClass];
// NSLog(@"principal class for bundle:%@ is: %@",[[bundle bundlePath] lastPathComponent],[class description]);
if (class)
{
if (selector)
{
if (sender)
{
[sender performSelector:selector withObject: class];
}
}
}
}
- (int)loadPluginsInDomain:(NSString*)domain atPath:(NSString*)aPath withExtensions: (NSArray*)extensions
{
int bundleCount = 0;
NSString* pluginFolder = [[domain stringByExpandingTildeInPath] stringByAppendingPathComponent:aPath];
NSArray* pluginFiles = [[NSFileManager defaultManager] directoryContentsAtPath:pluginFolder];
// if folder doesn't exist, return
if (pluginFiles == nil) return 0;
NSEnumerator* plugins = [pluginFiles objectEnumerator];
NSString* plugin;
while (plugin = [plugins nextObject])
{
// check if plugin extension is exqual to the required extension
if ([extensions containsObject:[plugin pathExtension]])
{
// load bundle
NSBundle* pluginBundle = [NSBundle bundleWithPath:[pluginFolder stringByAppendingPathComponent:plugin]];
if ([pluginBundle load])
{
//load was successful, increment the counter and init the bundle
bundleCount ++;
[self initBundle: pluginBundle];
}
}
}
return bundleCount;
}
- (int)loadPluginsAtPath:(NSString*)aPath withExtension: (NSString*)extension
{
return [self loadPluginsAtPath:aPath withExtensions:[NSArray arrayWithObject:extension]];
}
- (int)loadPluginsAtPath:(NSString*)aPath withExtensions: (NSArray*)extensions
{
int bundleCount = 0;
NSEnumerator* domains = [[self domainPathes] objectEnumerator];
NSString* domain;
while (domain = [domains nextObject])
{
bundleCount += [self loadPluginsInDomain: domain atPath: aPath withExtensions: extensions];
}
// return how many bundles loaded successfully
return bundleCount;
}
+ (int)loadPluginsAtPath:(NSString*)aPath withExtension: (NSString*)extension
{
return [self loadPluginsAtPath:aPath withExtensions:[NSArray arrayWithObject:extension]];
}
+ (int)loadPluginsAtPath:(NSString*)aPath withExtensions: (NSArray*)extensions
{
BSPluginLoader* loader = [[self alloc] init];
int bundleCount = [loader loadPluginsAtPath:aPath withExtensions:extensions];
[loader release];
return bundleCount;
}
- (id) init {
self = [super init];
if (self != nil) {
selector = nil;
sender = nil;
}
return self;
}
- (void)setSelector:(SEL)newSelector
{
selector = newSelector;
}
- (void)setSender:(id)newsender
{
[sender release];
sender = [newsender retain];
}
- (void) dealloc {
[sender release];
[super dealloc];
}
+ (id)loaderForSender:(id)sender notifyingWith:(SEL)selector
{
BSPluginLoader* loader = [[self alloc] init];
[loader setSender:sender];
[loader setSelector:selector];
return loader;
}
@end
BSPluginLoader header preview
//
// BSPluginLoader.h
// BSPluginLoader
//
// Created by Karsten Kusche on 30.03.07.
//
#import <Cocoa/Cocoa.h>
/*
BSPluginLoader will load all plugins into your application that have a given extension and are located in a given subpath.
it will search all domains (~/Library/Application Support /Library/Application Support /System/Library/Application Support)
as well as the application-bundle's contents folder.
load the bundle by hand when your application launches and benefit of a simplified plugin loading mechanism.
*/
@interface BSPluginLoader : NSObject {
SEL selector; // selector...has to accept the class that was loaded as argument
id sender; // target that receives this selector
}
// create a new loader with sender and action
+ (id)loaderForSender:(id)sender notifyingWith:(SEL)selector;
// load plugins at a relative path (@"plugins" for example) and with a given extension, or extensions
+ (int)loadPluginsAtPath:(NSString*)aPath withExtension: (NSString*)extension;
+ (int)loadPluginsAtPath:(NSString*)aPath withExtensions: (NSArray*)extensions;
// same as the class methods, but notifying the target with the selector specified in the factory method
- (int)loadPluginsAtPath:(NSString*)aPath withExtension: (NSString*)extension;
- (int)loadPluginsAtPath:(NSString*)aPath withExtensions: (NSArray*)extensions;
// set the instance variables
- (void)setSelector:(SEL)newSelector;
- (void)setSender:(id)newSender;
@end
Download Archive
Compatible with:
- Mac OS X 10.3
- Mac OS X 10.4 PPC
- Mac OS X 10.4 Intel
- Mac OS X 10.5 PPC
- Mac OS X 10.5 Intel

You should not hard-core any path. This is a bad practice. Use NSSearchPathForDirectoriesInDomains to locate the Application Support folders, and -[NSBundle builtInPlugInsPath] for the internal path.