Writing a plugin for Mac OS X

This article is adapted from Josh Aas's blog post Writing an NPAPI plugin for Mac OS X.

Before you go on reading this article, you may wish to grab the sample code located here, as it will be referenced during this tutorial. The sample is posted under a BSD-style license that means you can use it for anything, even if you don't plan to release your source code.

Getting started

If you check out the Mozilla source code in Mac OS X, you can simply open BasicPlugin.xcodeproj in Xcode, click Build, and you're done. Xcode will create a "build" directory next to the project file, and if you built it in release mode, that folder in turn contains a "Release" directory with the plugin inside it.

To install the plugin, just copy it into one of these two locations:

  • /Library/Internet Plugins/
  • ~/Library/Internet Plugins/

From this point, you can simply modify the sample plugin to do whatever you want.

Notes and tips

This section provides some additional information that may be helpful if you're trying to get a plugin building on your own.

Info.plist

The plugin communicates its MIME and filename extension information using the Info.plist file, which is packaged in the plugin bundle. The plugin also communicates its bundle type in that file, under the key CFBundlePackageType; the type is 'BRPL'. If the type isn't an NPAPI plugin type, the bundle won't load as an NPAPI plugin. You can always just use 'BRPL'.

XP_MACOSX

It's important to define the GCC preprocessor definition XP_MACOSX to 1; this is used by the NPAPI headers to build properly on Mac OS X. If you don't define it, they won't be interpreted correctly. This is easy to miss in the sample project's build settings.

Symbol visibility

Symbol visibility is a common problem for people trying to get NPAPI plugins working. Some symbols must be visible as standard C symbols so the browser can find them, which means they need to be prefixed by an underscore, and must not have the C++ obfuscation that is generated by the C++ compiler.

The three symbols that must always be visible are:

  • NP_Initialize()
  • NP_GetEntryPoints()
  • NP_Shutdown()

The sample plugin is written entirely in C, using a standard Xcode build configuration, so by default all of its symbols are C-style and visible.

If you want to implement your plugin in C++ or Objective-C++, you need to tell the compiler to export them in C format by using extern "C" in the header, like 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 be sure your symbols are visible and in standard C format by using the nm utility provided among the Mac OS X developer tools:

[user@foo MyMac] nm BasicPlugin

...
00000810 T _NP_GetEntryPoints
000007fa T _NP_Initialize
000008a0 T _NP_Shutdown

See also

Original Document Information

  • Author(s): Josh Aas
  • Last Updated Date: October 24, 2008