The BrowserPlus ServiceAPI allows you to write native plugins that can be loaded by BrowserPlus. These plugins (or "services") are primarily designed to expose a scriptable interface to Javascript running in a web browser.
A service consists of a directory which contains a single required file, manifest.json, which is json text that points to the shared library (.dll or .so) that implements the service. The manifest.json also includes other information, such as localized end-user visible strings identifying at a high level what the service does, and any explicit permissions that should be requested from the user. Here is a sample manifest file for a service that displays desktop notifications:
{
"type": "standalone",
"ServiceLibrary": "notify.dll",
"strings": {
"en": {
"title": "Notify",
"summary": "A service to deliver desktop notifications."
}
},
"permissions": [
"DisplayNotifications"
]
}
The other entities in the service's directory are the dynamic library itself, and whatever else the service author wishes to include.
As this API allows for native services to be authored, the first question that may arise is how do we support multiple platforms? At the time services are published, they may be marked platform specific, or platform independent. To support multiple platforms, the only requirement is that the same service with the same version exports the same API. It is up to the service author whether and how they wish to share code between implementations.
Finally, because services may be written in high level languages (Ruby and Python are two languages supported today), it is possible to implement a service as Ruby on one platform, and native code on another.
The ServiceAPI is a header only SDK. No libraries are required.
These C header files compose the lowest level "ServiceAPI", however it is worth noting that several libraries and frameworks exist which simplify the process of writing a service. These frameworks can be found on github at http://github.com/browserplus
The design of the BrowserPlus ServiceAPI was motivated by the following goals:
There are three different types of services, this type is specified in the service manifest (manifest.json)
Exactly one symbol is the contract between services and BrowserPlusCore. This symbol is "BPPGetEntryPoints", a symbol that returns a function which takes no arguments and returns a structure. The first member of that structure is a 32bit integer which holds the service api version against which the service was written. All function pointers from service to BrowserPlus or vice versa are passed in structures, which means that no import libraries are required, and only one symbol must be exported from a service.
BPP* functions are provided by the service and are called by BPCore. The service loading procedure is thus:
Anything that the service allocates, the service must free. Anything that BrowserPlus allocates, BrowserPlus must free. All pointers passed into a function traveling either direction are valid only for the duration of the function, the caller may free immediately after the function returns.
The threading model for services is intended to minimize complexity and maximize flexibility, leaving as much up to the service author as possible. All functions invoked by BrowserPlus on the service will be invoked from the "main" or "primordeal" thread of execution. On platforms where pertinent, there will be a OS provided "runloop" running on this thread (a Cocoa runloop or a Win32 message pump).
The service may allocate and run as many threads as it likes, and may call into BrowserPlus on any of them.
After loading a service, BrowserPlus will want to know what functions the service supports and what arguments those functions accept, and the name and version of the service, etc. All of this information is conveyed through C structures documented in bpdefinition.h.
A main purpose of services is usually to get data back to the execution environment that invoked the service. Before crossing the service <-> BrowserPlus boundary, data must be mapped into an intermediate format. Our solution to this problem is very similar to that of NPAPI. bptypes.h defines a set of structures capable of holding all of the different data types we support.
Working with the structures directly is supported, but leads to complex code. As mentioned above, there are ongoing efforts to develop service frameworks to simplify the authoring of native services, especially in the area of data binding. All pertinent projects are available on github: http://github.com/browserplus
Paths in the system are passed around as operating system native paths. That is, on unix, all paths are forward slash delimited, UTF8. On windows, paths are windows style UTF16.
In bptypes.h, the pertinent type is BPNativePath where you'll see that the type is either a wchar_t * or a char * -- depending on the platform.
A "provider" service is one that can be required by a "dependent" service. This mechanism minimally affects the authors of "standalone" services while making it possible to enable services written in high level languages. Finally, while the design motivation for this mechanism was to support interpreter services, it's conceivable that it could be applied to other use cases.
A provider service will be loaded any time a dependent service that requires it is loaded. At the time BPPInitialize() is called on the provider service, the path to the dependent service will be provided, and also any content in the manifest.json of the dependent service under the 'arguments' key will be parsed and passed into the provider. This mechanism allows the dependent service to provide arguments to the provider, and leaves the decision of the structure and content of those arguments up to the implementor of the provider service.
1.6.2