Injected Bundle
Created on June 21, 2022
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.
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.
Example
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
Example
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
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
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
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
JSObjectCallAsFunction(context, callbackObj, NULL, 1, args, NULL); //args is the list of arguments if required
Go To Top