Boom Swagger Boom











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.



I’ve been thinking that it would be really nice to have a “test plugin” that exercised every aspect of the API, for when one is messing with the browser side of the interface. For instance, there’s a bug somewhere to the effect that if you make drastic-enough style changes from script to a page with a plugin on it, the plugin gets reloaded; it would be nice to fix that, but testing currently would be a matter of “well, it appears to work with Flash and Java and a media player…” A test plugin could let me say “it works with code that pushes the API to its limits but no farther, so any plugin it breaks is buggy.”



Josh Aas says:

We plan to create a testing system for NPAPI.



I’ve migrated this post into MDC here:

https://developer.mozilla.org/En/Writing_a_plugin_for_Mac_OS_X

Feel free to poke at it if you see anything I botched up during the copy and paste and edit session. :)



Petoi says:

I built it and compiled the plugin which results in a BasicPlugin.bundle file which I copy to ~/Library/Internet Plug-ins. I then load the test.html page in the parent folder of the project using Firefox and it does not find the plugin. It asks if I want to download the plugin. Any ideas?



Francis says:

I have the same problem as Petoi. Using Xcode 3.1, latest mozilla source from mozilla-central (as of 17 Feb 2009), and Firefox 3.0.6. The plugin builds fine and creates the BasicPlugin.bundle. Putting this in the plug-in paths as described doesn’t seem to do anything. about:plugins doesn’t show it as being installed. Any help would be really appreciated.



fugelen says:

Anyone know a similar tutorial for Linux?



elan says:

I have the same problem as Petoi and Francis above… Interesting observation is that Safari actually finds the basic plugin, but it won’t show in Firefox



Having problems building the BasicPlugin sample for 10.4 using XCode 2.3. I’ve changed the SDKROOT to /Developer/SDKs/MacOSX10.4u.sdk, and renamed npfunctions.h to npupp.h in BasicPlugin.h (as per the latest gecko sdk where it hasn’t been renamed to npfunctions.h yet), but whenever I build using either Xcode.app or xcodebuild, it doesn’t actually build the plugin. In the build/Release/BasicPlugin.bundle/Contents dir I only see Info.plist and Resources, but no MacOS and no plugin. There are no errors. For some reason when it builds it is only copying over the resources – it never even tries to build the plugin. Does the sample project not work with 10.4? I have a Safari plugin that builds fine using xcode.



Petoi, Francis and Elan:

Safari and the Minefield FireFox builds use the Info.plist file for the plugin information. But the official FireFox and Opera use the Resource Fork (BasicPlugin/Contents/Resources/BasicPlugin.rsrc) of the plugin for info. In Xcode create a file called BasicPlugin.r with the following contents (i hope formatting will be allright):

#include
resource ‘STR#’ (126, “Description”) { { “Shows the user agent using CoreGraphics”, “Basic Plugin” } };
resource ‘STR#’ (127, “MIME type description”) { { “The basic plugin mime type” } };
resource ‘STR#’ (128, “MIME type”) { { “application/basic-plugin”, “” } };

And add a ‘Build ResourceManager Resources’ build phase to the project. That should get you started.



That include line should be:

#include <Carbon/Carbon.r>



Francis says:

Thanks Selwyn, works a treat now. For others, be careful copying and pasting though. The single and double quotes came out wrong for me when I pasted in xcode. (Maybe this will paste better, I dunno)

#include
resource ‘STR#’ (126, “Description”) { { “Shows the user agent using CoreGraphics”, “Basic Plugin” } };
resource ‘STR#’ (127, “MIME type description”) { { “The basic plugin mime type” } };
resource ‘STR#’ (128, “MIME type”) { { “application/basic-plugin”, “” } };

Francis



Francis says:

No, looks like its done the same again.



JJGL says:

Hello,

I have built your project with XCode and placed the bundle with the .rsrc file in the Internet Plug-Ins path. The plugin works fine on Safari and on Mozilla Firefox 3.x. However on my Mozilla Firefox 2.0.0.13 it isn’t loaded although it appears in about:plugins. I have checked that NP_Initialize function is not called. Any idea about compatibility with Firefox 2.x?

Thanks in advance,

Juanjo



Leave a Reply

et cetera