Overview
Injected bundle is an Integration layer between Service Manager and the player in RDK Browser and WPE.
- Adds an ability to send messages from JavaScript to UI side and vice versa.
- Supports ACL for the JavaScript objects.
Code Block |
---|
title | JavaScript Bridge implementation |
---|
|
The JS Bridge consists of 2 parts:
- execution backend (written in C++)
- client interface to execution backend (this one)
Each part consists of 2 layers:
- object interface (methods calls)
- general messaging (serialized messages)
Each method call JS => C++ is serialized into JSON, trasfered via IPC,
received on another side, mapped into the corresponding method call.
So, the route is:
C++ JS
------------------- -------------------
object interface < < object interface
------------------ | |-------------------
general messaging | | general messaging
------------------ | |-------------------
IPC <===< IPC
Responses and events are transferred in opposite direction (C++ => JS) |
Implementation Details
How to Expose C/C++ API using injectedbundle
- Define an Injectedbundle CB that's invoked when a page is loaded
Define an object of WKBundlePageLoaderClientV1 with your own function callback for didCommitLoadForFrame. This callback gets invoked when a page's DOM contens finishes loading. This will also provide the mainFrame instance in which the JS object is to be loaded.
Code Block |
---|
|
WKBundlePageLoaderClientV1 client {
{1, clientInfo},
// Version 0.
nullptr, // didStartProvisionalLoadForFrame;
nullptr, // didReceiveServerRedirectForProvisionalLoadForFrame;
nullptr, // didFailProvisionalLoadWithErrorForFrame;
didCommitLoad, // didCommitLoadForFrame;
nullptr, // didFinishDocumentLoadForFrame;
nullptr, // didFinishLoadForFrame;
nullptr, // didFailLoadWithErrorForFrame;
nullptr, // didSameDocumentNavigationForFrame;
nullptr, // didReceiveTitleForFrame;
nullptr, // didFirstLayoutForFrame;
nullptr, // didFirstVisuallyNonEmptyLayoutForFrame;
nullptr, // didRemoveFrameFromHierarchy;
nullptr, // didDisplayInsecureContentForFrame;
nullptr, // didRunInsecureContentForFrame;
nullptr, // didClearWindowObjectForFrame;
nullptr, // didCancelClientRedirectForFrame;
nullptr, // willPerformClientRedirectForFrame;
nullptr, // didHandleOnloadEventsForFrame;
// Version 1.
nullptr, // didLayoutForFrame
nullptr, // didNewFirstVisuallyNonEmptyLayout_unavailable
nullptr, // didNewFirstVisuallyNonEmptyLayout_unavailable
nullptr,
nullptr, // globalObjectIsAvailableForFrame
nullptr, // globalObjectIsAvailableForFrame
nullptr, // didReconnectDOMWindowExtensionToGlobalObject
nullptr // willDestroyGlobalObjectForDOMWindowExtension
}; |
- void didCommitLoad(WKBundlePageRef page, WKBundleFrameRef frame) // WKBundleFrameRef frame provides the JS context in which to load JS/C++ bindings
Code Block |
---|
|
void didCommitLoad(WKBundlePageRef page, WKBundleFrameRef frame)
{
JSGlobalContextRef context = WKBundleFrameGetJavaScriptContext(frame);
LoadJS(context);
} |
- Using the context obtained from frame you can load custom JS objects, but first you need to define a JS class definition which provides a standard set of callbacks and properties for the JS object
Code Block |
---|
title | Reference - usr/include/JavaScriptCore/JSObjectRef.h |
---|
|
typedef struct {
int version; /* current (and only) version is 0 */
JSClassAttributes attributes;
const char* className;
JSClassRef parentClass;
const JSStaticValue* staticValues;
const JSStaticFunction* staticFunctions;
JSObjectInitializeCallback initialize;
JSObjectFinalizeCallback finalize;
JSObjectHasPropertyCallback hasProperty;
JSObjectGetPropertyCallback getProperty;
JSObjectSetPropertyCallback setProperty;
JSObjectDeletePropertyCallback deleteProperty;
JSObjectGetPropertyNamesCallback getPropertyNames;
JSObjectCallAsFunctionCallback callAsFunction;
JSObjectCallAsConstructorCallback callAsConstructor;
JSObjectHasInstanceCallback hasInstance;
JSObjectConvertToTypeCallback convertToType;
} JSClassDefinition; |
The important parameters for any JS object are staticValues, staticFunctions which helps to implement JSObject.property (get/set) and JSObject.function()
You may find more about the structure of JSStaticValue and JSStaticFunction in JSObjectRef.h
- Once the class and corresponding callbacks are defined, you may load this object onto the context that is retrieved from the frame object in injectedbundle
Code Block |
---|
static const JSClassDefinition JS_class_def;
void LoadJS(JSGlobalContextRef context)
{
//Create a custom object that holds the context and any other variables that are required, for eg- seesion keeping var.
struct CustomObject* obj = new CustomObject();
JSClassRef classDef = JSClassCreate(&JS_class_def);
JSObjectRef classObj = JSObjectMake(context, classDef, obj);
JSObjectRef globalObj = JSContextGetGlobalObject(context);
JSStringRef str = JSStringCreateWithUTF8CString("JSObject"); //If you would like to name your object as JSObject and access like JSObject.property
JSObjectSetProperty(context, globalObj, str, classObj, kJSPropertyAttributeReadOnly, NULL); //this loads the JSObject to page
JSClassRelease(classDef);
JSStringRelease(str);
} |
- Once the page is loaded, you may add an event listenet for onDOMContentLoaded and verify if the JSObject is defined ( if(typeof global.JSObject !== "undefined" {console.log ("JSObject available")})
How to Invoke a JS API from C/C++
- Pass the JS API function pointer to Native code and store it as a JSObjectRef
Code Block |
---|
JSObject.addEventListener(eventType, eventListener) //with eventListener having a definition like "function eventListener(event: any) {....}"
static JSValueRef addEventListener(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception)
{
JSObjectRef callbackObj = JSValueToObject(context, arguments[1], NULL);
if (callbackObj != NULL && JSObjectIsFunction(context, callbackObj))
{
//Store the callbackObj in a variable
eventListener = callbackObj;
JSValueProtect(context, callbackObj);
}
else
{
return JSValueMakeUndefined(context);
}
return JSValueMakeNull(context);
} |
To invoke the JS API from C/C++, call JSObjectCallAsFunction with the callbackObj and arguments
Code Block |
---|
JSObjectCallAsFunction(context, callbackObj, NULL, 1, args, NULL); //args is the list of arguments if required |