Plugins (was Re: CoreFoundation question)
Plugins (was Re: CoreFoundation question)
- Subject: Plugins (was Re: CoreFoundation question)
- From: Greg Titus <email@hidden>
- Date: Tue, 28 Aug 2001 13:57:13 -0700
On Tuesday, August 28, 2001, at 11:01 AM, email@hidden wrote:
I know it's OT, but I wonder if anyone here can help...
[...]
I think that most folks who use a plug-in architecture (well, me,
anyway) want to define one or more types, then be able to dynamically
figure out what plugins provide factories for the type(s), without
having to have prior knowledge of how the plugins will be named. Am I
smoking crack here? So, does anyone know of a way to have the plugin
host dynamically locate candidate plugins?
An approach comes to my mind, but before I go down that path, has
anyone got some good suggestions?
The app could define a location (or some locations), say,
/Library/PlugIns and ~/Library/PlugIns, and enumerate all .plugin
packages found in those locations, instantiate the plugins, and then
look for factories for the types.
My conceptual problem with the approach is that every plugin-host app
must either provide its own subfolder in .../PlugIns (or somewhere
else), or else it will be instantiating CFPlugIns for plugins that
belong to unrelated apps, and no limiting (until memory is exhausted)
how many that might be.
I could find no information from Apple how they recommend partitioning
the plugin store.
The other concern that comes to my mind is that it seems not unlikely
that tools like web browsers and media players might share some plugin
types... so that it becomes preferable in that case to have all plugins
centrally located again, without special subdirectories for each one.
Has someone got a pointer to better Apple documentation? I've studied
http://developer.apple.com/techpubs/macosx/CoreFoundation/PluginServices/
* pretty thoroughly.
I don't think Apple has anything more specific on this topic. I can tell
you what the structure we use looks like, and that may give you some
ideas...
As you describe above, OmniWeb looks in /Library/PlugIns,
~/Library/PlugIns, and /Network/Library/PlugIns for .plugin packages.
But instead of instantiating all of them, we load the Info.plist inside
as a dictionary and look for a couple custom keys.
The first is "OFRequiredSoftwareVersions" which is a dictionary of keys
(framework or application names) with the value being a version string.
If the .plugin is missing the "OFRequiredSoftwareVersions" key it
obviously isn't meant for us, so we discard it and never attempt to load
it. Otherwise we match each element in the dictionary with our app name
or the names of frameworks which the app loads. If the plugin is meant
for a different application, it will contain a key that doesn't match
our app or framework list and again, it is discarded and never loaded.
Similarly, if the version string doesn't match, the plugin is out of
date and discarded.
Notice that we check not only against the app name but against the
loaded frameworks. Most of our plugins specify only framework names in
the OFRequiredSoftwareVersions section, which means they can be loaded
by more than one application as long as each one uses the required
framework(s). For instance, our imaging framework has a plugin
architecture for parsing and displaying images in different formats (we
can't just use the AppKit directly because we want incremental display
and animations). The gif.plugin, jpeg.plugin, png.plugin, et cetera can
not only be loaded into OmniWeb, but also any other app (say a simple
image viewer) that included the framework with the architecture that the
plugins are based on.
The second key is "OFRegistrations" which is a series of dictionaries
describing what the plugin is actually for. The plugin examination code
basically forwards appropriate chunks of the registration dictionary to
the classes that might load plugins and they can either decide to load
that particular plugin immediately, or store the registration dictionary
and plugin location for later. To use the image plugins as an example
again, their registration dictionaries specify that they can transform
MIME types like "image/gif" or "image/jpeg" or whatever into an image
object. This registration information is stored and the plugin isn't
actually loaded until the first time the application comes upon some
"image/gif" content that needs to be dealt with. It's only at that point
that the plugin is loaded and instantiated.
This is all public code, though like all our other code, not well
documented. OFBundleRegistry and OFBundledClass in the OmniFoundation
framework. It's completely generic and should be useful for any kind of
plugin-based Cocoa application.
Also, as another place to look, you may want to check out Apple's
documentation on IOKit. It has a somewhat similar approach to describing
dependencies and connections in an info dictionary and only loading
driver bundles as needed. It's a little more complex because it handles
full dependency graphs instead of the simpler two level dependencies
(plugin on framework or app) that we manage.
Hope this helps,
--Greg