Introduction to cocoa plug-in
Luo chaohui (http://blog.csdn.net/kesalin)
CC license. For more information, see Source
In the previous article, I explained the framework in the framework of cocoa, and then explained the plug-in. If you are not familiar with the framework, read the article, use the framework in this example, and do not detail the creation and use process in this article.
Download the code in this article: click here
Why introduce plug-ins?
We know that related frameworks will be connected during program compilation. Generally, the frameworks we connect are the foundation and application frameworks. When the program starts to run, each connected framework is loaded into the objc runtime environment of the program. What should we do if we want to load a new framework to a running program? One of the answers is to use the plugin mechanism. The plug-in mechanism of cocoa is usually implemented by the nsbundle class, and the function objc_addclass is used to realize dynamic loading. Generally, we do not need
To deal with this function, we use nsbundle to do most of the work related to plugin.
The plugin mechanism allows us to develop highly modular, customizable, and scalable applications, and allows third parties to add new features to the application. Many people are familiar with eclipse, and eclipse's plug-in mechanism is very convenient and powerful.
Introduction to nsbundle
Bundle is a directory structure in the file system. It packs the resources used by the program. These resources can include compiled code, NIB files, configuration files, images, sounds, and localized resources. Bundle is a core feature of Mac OS X. Applications, frameworks, and plug-ins all have different extensions, for example, the application extension is. the extension of APP and framework is. framework; default extension of the plug-in is. bundle.
A plugin is a bundle. By default, xcode uses. Bundle as the extension. We usually use our own defined extension to distinguish it from the system or the plug-in compiled by others. We use nsbundle to load the bundle and register the compiled classes in the objc runtime. Then we can use these classes in the program; we can also use all resources in the bundle.
Plugin Architecture
We can implement a plugin in multiple ways:
1. Define an objc protocol so that the plugin complies with the protocol;
2. Define a base class so that plugin can inherit the base class;
3. Define a C callback function interface for plugin to implement the callback function;
4. Use cfplugin to create the plugin interface;
In today's example, the second situation is used. This situation is slightly more complex. We need to create a framework for the host Program (the program using the plug-in) and plugin, this framework is mainly responsible for providing basic class interfaces.
Directory for storing plugin
Normally, plugin is stored in the following three locations:
1. Application name. APP/contents/plug-ins this is where the developer of the program stores the plug-ins released with the product.
2 ,~ /Library/Application Support/Application name/plug-ins the place where the user stores the personal plug-in.
3. Plug-ins in the/library/Application Support/Application name/plug-ins system for all users.
In today's example, the first case is to store the plug-in the application package.
Create a Host Program
Create a cocoa application named plugindemo. This program contains a popup button that shows the installed plugin and a button that executes the selected plugin.
Create framework
1. Create a framework named pluginframework and add the plugin base class: abstractplugin to it. If you forget how to create and use the framework, refer to the previous article: a simple introduction to the cocoa framework.
The abstractplugin class only provides two interfaces:
- (NSString *)name;- (IBAction)run:(id)sender;
Name is used to identify plugin, and run is used for the host to run the plug-in.
2. connect to and use the Framework to run the plug-in plugindemo. If you forget how to connect to and use the framework, refer to the previous article: a simple introduction to the cocoa framework. In the button response function, run the selected plug-in.
- (IBAction)runPlugin:(id)sender{ AbstractPlugin *plugin = [[pluginsController selectedObjects] lastObject];if (!plugin) return; [plugin run:sender];}
Create plugin
1. Create plugin;
2. Connect to pluginframework. If you forget how to connect to and use the framework, refer to the previous article: A Brief Introduction to the cocoa framework.
3. Create a UI;
4. Create a in subclass inherited from the base class: pluginone;
The pluginone class inherits from abstractplugin. It only shows and hides a window, and its implementation is as follows:
#import "PluginOne.h"@implementation PluginOne@synthesize mainWindow;- (id)init{ self = [super init]; if (self) { // Initialization code here. [NSBundle loadNibNamed:@"PluginOneMainWindow" owner:self]; } return self;}- (void)dealloc{ mainWindow = nil; [super dealloc];}- (NSString *)name;{return @"Plugin One";}- (IBAction)run:(id)sender;{[mainWindow center];[mainWindow makeKeyAndOrderFront:sender];}- (IBAction)closeWindow:(id)sender;{[mainWindow orderOut:sender];}@end
5. plugin settings
Next we will set plugin. We can set its principal class and wrapper extension (Extension ).
Use plugin
1. Host Program settings
As mentioned above, in this example, we plan to release the plug-in along with the Host Program, so its storage location is in the Host application package. Therefore, we need to add a build phase of add copy files in the Host Program, as shown below:
2. Load plugin
In the formal application, we should find all the Plugins under the three directories mentioned above, because these three directories are the plugin directories recommended by cocoa. In this example, the program is released along with the Host application, so I only scanned the directory in the application package.
- (NSArray *)loadPlugins{NSBundle *main = [NSBundle mainBundle];NSArray *allPlugins = [main pathsForResourcesOfType:@"bundle" inDirectory:@"../PlugIns"];NSMutableArray *availablePlugins = [[[NSMutableArray alloc] init] autorelease];id plugin = nil;NSBundle *pluginBundle = nil;for (NSString *path in allPlugins) {pluginBundle = [NSBundle bundleWithPath:path];[pluginBundle load]; Class principalClass = [pluginBundle principalClass];if (![principalClass isSubclassOfClass:[AbstractPlugin class]]) {continue;} plugin = [[principalClass alloc] init]; if ([plugin respondsToSelector:@selector(run:)]) { [availablePlugins addObject:plugin]; NSLog(@" >> loading plugin %@ from %@", [plugin name], path); } [plugin release]; plugin = nil;pluginBundle = nil;}return availablePlugins;}
This function is called in init:
- (id)init{ self = [super init]; if (self) { plugins = [[self loadPlugins] retain]; } return self;}
The following provides a function to scan the three directories mentioned above. You can use this function to call loadplugins in the code above:
- (NSArray *)loadAllPlugins{ NSString *appName = @"PluginOne/Plugins"; NSString *appSupport = @"Library/Application Support"; appSupport = [appSupport stringByAppendingPathComponent:appName]; NSString *appPath = [[NSBundle mainBundle] builtInPlugInsPath]; NSString *userPath = [NSHomeDirectory() stringByAppendingPathComponent:appSupport]; NSString *sysPath = [@"/" stringByAppendingPathComponent:appSupport]; NSArray* paths = [NSArray arrayWithObjects:appPath, userPath, sysPath, nil]; NSMutableArray * availablePlugins = [[[NSMutableArray alloc] init] autorelease]; for (NSString * path in paths) { NSLog(@" >> Search in directory: %@", path); NSArray *contents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:NULL]; for (NSString *fileName in contents) { if ( [[fileName pathExtension] isEqualToString:@"plugin"] || [[fileName pathExtension] isEqualToString:@"bundle"]) { NSString *fullPath = [path stringByAppendingPathComponent:fileName]; NSBundle *pluginBundle = [NSBundle bundleWithPath:fullPath]; if (pluginBundle && [pluginBundle load]) { Class principalClass = [pluginBundle principalClass]; if (![principalClass isSubclassOfClass:[AbstractPlugin class]]) { continue; } id plugin = [[principalClass alloc] init]; if ([plugin respondsToSelector:@selector(run:)]) { [availablePlugins addObject:plugin]; NSLog(@" >> loading plugin %@ from %@", [plugin name], path); } [plugin release]; plugin = nil; } } } } return availablePlugins;}
The popupbutton content that shows the plugin list is bound to the Plugins array. After the program is started, the plugin list is displayed. The running result is as follows:
Click Run to display the main interface of the plug-in:
Reference:
Code
Loading programming topics Provides information about writing plug-ins using the objective-C language.
Bundle
Programming Guide provides an overview to bundles, including their purpose, types, structure, and the API for accessing bundle resources.