Writing an NPAPI plugin for Mac OS X

Recently I have been doing some work to make life easier for NPAPI plugin developers. As part of that effort I started to revive our NPAPI SDK and rewrite some of our sample code. Today I’m going to explain how to write an NPAPI plugin for Mac OS X, based on the basic sample plugin in our SDK. It is actually pretty easy now. You can have one built and running in the browser in minutes.

The sample code I’m going to be referencing today can be found here:

http://mxr.mozilla.org/mozilla-central/source/modules/plugin/sdk/samples/basic/mac/

We decided to commit that sample under a BSD-style license which means you can use it for anything, even if you don’t plan to release source code. This is unfortunately common for NPAPI plugins.

If you check out the Mozilla source code in Mac OS X, you can simply open “BasicPlugin.xcodeproj” and hit build and you’re done. A “build” directory will be created next to “BasicPlugin.xcodeproj”, and if you built in release mode that will contain a “Release” directory with the plugin inside it. Copy that plugin into one of the following two locations and it’ll work:

/Library/Internet\ Plugins/
~/Library/Internet\ Plugins/

Just modify the basic sample plugin to do whatever you want.

Now I’ll explain some things that might not be obvious if you were trying to get such a plugin building on your own.

The plugin communicates its MIME and extension information using the “Info.plist” file which is packaged in the plugin bundle. Just read the file to see how that is done. The plugin also communicates its bundle type in that file, under the key “CFBundlePackageType” – the type is “BRPL”. If the type is not an NPAPI plugin type, the bundle won’t load as an NPAPI plugin. You can just always use “BRPL”.

I made a GCC preprocessor definition in the project file, “XP_MACOSX=1”. This is used by the NPAPI headers, if you don’t define it they won’t be interpreted correctly on Mac OS X. This is easy to miss in the sample project file build settings.

Symbol visibility is a common problem area for people trying to get NPAPI plugins working. Some symbols must be visible as standard C symbols so the browser can find them, which (always?) means simply prefixed with an underscore (Foo() = _Foo). There are three symbols that need to be visible as standard C symbols on Mac OS X – “NP_Initialize”, “NP_GetEntryPoints”, and “NP_Shutdown”. Our sample plugin is written entirely in standard C and uses a standard Xcode build configuration so by default all of its symbols are C-style and visible. If you wanted to implement your plugin in C++ (.cpp) or Obj-C++ (.mm), you would have to do this:

#pragma GCC visibility push(default)
extern "C"
{
NPError NP_Initialize(NPNetscapeFuncs *browserFuncs);
NPError NP_GetEntryPoints(NPPluginFuncs *pluginFuncs);
void NP_Shutdown(void);
}
#pragma GCC visibility pop

You can check to see if your symbols are visible and in standard C naming format using the “nm” utility on Mac OS X, targeted at the plugin binary. The results should look like this:

[josh@denmark MacOS] nm BasicPlugin
...
00000810 T _NP_GetEntryPoints
000007fa T _NP_Initialize
000008a0 T _NP_Shutdown
...

This basic knowledge should get new NPAPI plugin developers pretty far on Mac OS X. Soon I’ll write up the same thing for getting an NPAPI plugin working on Linux/UNIX systems.