
{"id":9919,"date":"2022-06-21T09:10:32","date_gmt":"2022-06-21T09:10:32","guid":{"rendered":"https:\/\/developer.rdkcentral.com\/documentation\/documentation\/documentation\/rdk_video_documentation\/components\/open-sourced_components\/injected_bundle\/"},"modified":"2025-03-25T05:18:36","modified_gmt":"2025-03-25T05:18:36","slug":"injected_bundle","status":"publish","type":"page","link":"https:\/\/developer.rdkcentral.com\/documentation\/documentation\/rdk_video_documentation\/components\/injected_bundle\/","title":{"rendered":"Injected Bundle"},"content":{"rendered":"<p><!DOCTYPE html PUBLIC \"-\/\/W3C\/\/DTD HTML 4.0 Transitional\/\/EN\" \"http:\/\/www.w3.org\/TR\/REC-html40\/loose.dtd\"><br \/>\n <html><body><\/p>\n<p class=\"RepoDescription\">\n<div class=\"toc-macro client-side-toc-macro  conf-macro output-block\" data-headerelements=\"H1,H2,H3,H4,H5,H6,H7\" data-hasbody=\"false\" data-macro-name=\"toc\"> <\/div>\n\n\n<h2 class=\"wp-block-heading wp-main-header\">Overview<\/h2>\n\n\n<p class=\"RepoDescription\">Injected bundle is an Integration layer between Service Manager and the player in RDK Browser and WPE.&nbsp;<\/p>\n<ul>\n<li class=\"RepoDescription\">Adds an ability to send messages from JavaScript to UI side and vice versa.<\/li>\n<li class=\"RepoDescription\">Supports ACL for the JavaScript objects.\n<\/li>\n<\/ul>\n<div class=\"code panel pdl conf-macro output-block\" data-hasbody=\"true\" data-macro-name=\"code\">\n<div class=\"codeHeader panelHeader pdl\"><b>JavaScript Bridge implementation<\/b><\/div>\n<div class=\"codeContent panelContent pdl\">\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">The JS Bridge consists of 2 parts:\n    - execution backend (written in C++)\n    - client interface to execution backend (this one)\n\n  Each part consists of 2 layers:\n   - object interface (methods calls)\n   - general messaging (serialized messages)\n\n  Each method call JS =&gt; C++ is serialized into JSON, trasfered via IPC,\n  received on another side, mapped into the corresponding method call.\n  So, the route is:\n\n  C++                        JS\n  -------------------       -------------------\n  object interface  &lt;      &lt; object interface\n  ------------------ |     |-------------------\n  general messaging  |     | general messaging\n  ------------------ |     |-------------------\n  IPC                 &lt;===&lt;  IPC\n\n  Responses and events are transferred in opposite direction (C++ =&gt; JS)<\/pre>\n<\/div>\n<\/div>\n\n\n<h2 class=\"wp-block-heading wp-main-header\">Implementation Details<\/h2>\n\n\n<h3 class=\"wp-sub-header\"><span>How to Expose C\/C++ API using injectedbundle<\/span><\/h3>\n<ul>\n<li><span>Define an Injectedbundle CB that&#8217;s invoked when a page is loaded<\/span><\/li>\n<\/ul>\n<p><span>Define an object of WKBundlePageLoaderClientV1 with your own function callback for didCommitLoadForFrame. This callback gets invoked when a page&#8217;s DOM contens finishes&nbsp;<\/span><span>loading. This will also provide the mainFrame instance in which the JS object is to be loaded.<\/span><\/p>\n<div class=\"code panel pdl conf-macro output-block\" data-hasbody=\"true\" data-macro-name=\"code\">\n<div class=\"codeHeader panelHeader pdl\"><b>Example<\/b><\/div>\n<div class=\"codeContent panelContent pdl\">\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">WKBundlePageLoaderClientV1 client {\n        {1, clientInfo},\n        \/\/ Version 0.\n        nullptr, \/\/ didStartProvisionalLoadForFrame;\n        nullptr, \/\/ didReceiveServerRedirectForProvisionalLoadForFrame;\n        nullptr, \/\/ didFailProvisionalLoadWithErrorForFrame;\n        didCommitLoad, \/\/ didCommitLoadForFrame;\n        nullptr, \/\/ didFinishDocumentLoadForFrame;\n        nullptr, \/\/ didFinishLoadForFrame;\n        nullptr, \/\/ didFailLoadWithErrorForFrame;\n        nullptr, \/\/ didSameDocumentNavigationForFrame;\n        nullptr, \/\/ didReceiveTitleForFrame;\n        nullptr, \/\/ didFirstLayoutForFrame;\n        nullptr, \/\/ didFirstVisuallyNonEmptyLayoutForFrame;\n        nullptr, \/\/ didRemoveFrameFromHierarchy;\n        nullptr, \/\/ didDisplayInsecureContentForFrame;\n        nullptr, \/\/ didRunInsecureContentForFrame;\n        nullptr, \/\/ didClearWindowObjectForFrame;\n        nullptr, \/\/ didCancelClientRedirectForFrame;\n        nullptr, \/\/ willPerformClientRedirectForFrame;\n        nullptr, \/\/ didHandleOnloadEventsForFrame;\n \n        \/\/ Version 1.\n        nullptr, \/\/ didLayoutForFrame\n        nullptr, \/\/ didNewFirstVisuallyNonEmptyLayout_unavailable\n        nullptr, \/\/ didNewFirstVisuallyNonEmptyLayout_unavailable\n        nullptr,\n        nullptr, \/\/ globalObjectIsAvailableForFrame\n        nullptr, \/\/ globalObjectIsAvailableForFrame\n        nullptr, \/\/ didReconnectDOMWindowExtensionToGlobalObject\n        nullptr \/\/ willDestroyGlobalObjectForDOMWindowExtension\n    };<\/pre>\n<\/div>\n<\/div>\n<p><span><br \/><\/span><\/p>\n<ul>\n<li><span>&nbsp;void didCommitLoad(WKBundlePageRef page, WKBundleFrameRef frame) \/\/ WKBundleFrameRef frame provides the JS context in which to load JS\/C++ bindings<\/span><\/li>\n<\/ul>\n<div class=\"code panel pdl conf-macro output-block\" data-hasbody=\"true\" data-macro-name=\"code\">\n<div class=\"codeHeader panelHeader pdl\"><b>Example<\/b><\/div>\n<div class=\"codeContent panelContent pdl\">\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">void didCommitLoad(WKBundlePageRef page, WKBundleFrameRef frame)\n{\n    JSGlobalContextRef context = WKBundleFrameGetJavaScriptContext(frame);\n    LoadJS(context);\n}<\/pre>\n<\/div>\n<\/div>\n<p><span>&nbsp;<\/span><\/p>\n<ul>\n<li><span>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&nbsp;<\/span>for the JS object<\/li>\n<\/ul>\n<div class=\"code panel pdl conf-macro output-block\" data-hasbody=\"true\" data-macro-name=\"code\">\n<div class=\"codeHeader panelHeader pdl\"><b>Reference &#8211; usr\/include\/JavaScriptCore\/JSObjectRef.h<\/b><\/div>\n<div class=\"codeContent panelContent pdl\">\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">typedef struct {\n    int                                 version; \/* current (and only) version is 0 *\/\n    JSClassAttributes                   attributes;\n \n    const char*                         className;\n    JSClassRef                          parentClass;\n \n    const JSStaticValue*                staticValues;\n    const JSStaticFunction*             staticFunctions;\n \n    JSObjectInitializeCallback          initialize;\n    JSObjectFinalizeCallback            finalize;\n    JSObjectHasPropertyCallback         hasProperty;\n    JSObjectGetPropertyCallback         getProperty;\n    JSObjectSetPropertyCallback         setProperty;\n    JSObjectDeletePropertyCallback      deleteProperty;\n    JSObjectGetPropertyNamesCallback    getPropertyNames;\n    JSObjectCallAsFunctionCallback      callAsFunction;\n    JSObjectCallAsConstructorCallback   callAsConstructor;\n    JSObjectHasInstanceCallback         hasInstance;\n    JSObjectConvertToTypeCallback       convertToType;\n} JSClassDefinition;<\/pre>\n<\/div>\n<\/div>\n<p><\/p>\n<p><span>The important parameters for any JS object are staticValues, staticFunctions which helps to implement JSObject.property (get\/set) and JSObject.function()<\/span><\/p>\n<p><span>You may find more about the structure of JSStaticValue and JSStaticFunction in JSObjectRef.h<\/span><\/p>\n<ul>\n<li><span>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<\/span><\/li>\n<\/ul>\n<div class=\"code panel pdl conf-macro output-block\" data-hasbody=\"true\" data-macro-name=\"code\">\n<div class=\"codeContent panelContent pdl\">\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">static const JSClassDefinition JS_class_def;\n \nvoid LoadJS(JSGlobalContextRef context)\n{\n        \/\/Create a custom object that holds the context and any other variables that are required, for eg- seesion keeping var.\n        struct CustomObject* obj = new CustomObject();\n        JSClassRef classDef = JSClassCreate(&amp;JS_class_def);\n        JSObjectRef classObj = JSObjectMake(context, classDef, obj);\n        JSObjectRef globalObj = JSContextGetGlobalObject(context);\n        JSStringRef str = JSStringCreateWithUTF8CString(\"JSObject\"); \/\/If you would like to name your object as JSObject and access like JSObject.property\n        JSObjectSetProperty(context, globalObj, str, classObj, kJSPropertyAttributeReadOnly, NULL); \/\/this loads the JSObject to  page\n        JSClassRelease(classDef);\n        JSStringRelease(str);\n}<\/pre>\n<\/div>\n<\/div>\n<p><span>&nbsp;<\/span><\/p>\n<ul>\n<li><span>Once the page is loaded, you may add an event listenet for onDOMContentLoaded and verify if the JSObject is defined ( if(typeof global.JSObject !== &#8220;undefined&#8221; {console.log (&#8220;JSObject available&#8221;)})<\/span><\/li>\n<\/ul>\n<h3 class=\"wp-sub-header\"><span>&nbsp;<\/span><span>How to Invoke a JS API from C\/C++<\/span><\/h3>\n<ul>\n<li>Pass the JS API function pointer to Native code and store it as a JSObjectRef<\/li>\n<\/ul>\n<div class=\"code panel pdl conf-macro output-block\" data-hasbody=\"true\" data-macro-name=\"code\">\n<div class=\"codeContent panelContent pdl\">\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">JSObject.addEventListener(eventType, eventListener) \/\/with eventListener having a definition like \"function eventListener(event: any) {....}\"\n \nstatic JSValueRef addEventListener(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception)\n{\n        JSObjectRef callbackObj = JSValueToObject(context, arguments[1], NULL);\n \n        if (callbackObj != NULL &amp;&amp; JSObjectIsFunction(context, callbackObj))\n        {\n              \/\/Store the callbackObj in a variable\n              eventListener = callbackObj;\n              JSValueProtect(context, callbackObj);\n        }\n        else\n        {\n              return JSValueMakeUndefined(context);\n        }\n \n        return JSValueMakeNull(context);\n}<\/pre>\n<\/div>\n<\/div>\n<ul>\n<li>\n<p><span>To invoke the JS API from C\/C++, call JSObjectCallAsFunction with the callbackObj and arguments<\/span><\/p>\n<div class=\"code panel pdl conf-macro output-block\" data-hasbody=\"true\" data-macro-name=\"code\">\n<div class=\"codeContent panelContent pdl\">\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">JSObjectCallAsFunction(context, callbackObj, NULL, 1, args, NULL);&nbsp; \/\/args is the list of arguments if required<\/pre>\n<\/div>\n<\/div>\n<\/li>\n<\/ul>\n<p><\/body><\/html><\/p>","protected":false},"excerpt":{"rendered":"<p>Overview Injected bundle is an Integration layer between Service Manager and the player in RDK [&hellip;]<\/p>\n","protected":false},"author":28,"featured_media":0,"parent":9844,"menu_order":10,"comment_status":"open","ping_status":"closed","template":"","meta":{"_bbp_topic_count":0,"_bbp_reply_count":0,"_bbp_total_topic_count":0,"_bbp_total_reply_count":0,"_bbp_voice_count":0,"_bbp_anonymous_reply_count":0,"_bbp_topic_count_hidden":0,"_bbp_reply_count_hidden":0,"_bbp_forum_subforum_count":0,"footnotes":""},"class_list":["post-9919","page","type-page","status-publish","hentry"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v24.9 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Injected Bundle - RDK Documentation Portal | Documentation<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/developer.rdkcentral.com\/documentation\/documentation\/rdk_video_documentation\/components\/injected_bundle\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Injected Bundle - RDK Documentation Portal | Documentation\" \/>\n<meta property=\"og:description\" content=\"Overview Injected bundle is an Integration layer between Service Manager and the player in RDK [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/developer.rdkcentral.com\/documentation\/documentation\/rdk_video_documentation\/components\/injected_bundle\/\" \/>\n<meta property=\"og:site_name\" content=\"RDK Documentation Portal | Documentation\" \/>\n<meta property=\"article:modified_time\" content=\"2025-03-25T05:18:36+00:00\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data1\" content=\"2 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/developer.rdkcentral.com\/documentation\/documentation\/rdk_video_documentation\/components\/injected_bundle\/\",\"url\":\"https:\/\/developer.rdkcentral.com\/documentation\/documentation\/rdk_video_documentation\/components\/injected_bundle\/\",\"name\":\"Injected Bundle - RDK Documentation Portal | Documentation\",\"isPartOf\":{\"@id\":\"https:\/\/developer.rdkcentral.com\/documentation\/#website\"},\"datePublished\":\"2022-06-21T09:10:32+00:00\",\"dateModified\":\"2025-03-25T05:18:36+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/developer.rdkcentral.com\/documentation\/documentation\/rdk_video_documentation\/components\/injected_bundle\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/developer.rdkcentral.com\/documentation\/documentation\/rdk_video_documentation\/components\/injected_bundle\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/developer.rdkcentral.com\/documentation\/documentation\/rdk_video_documentation\/components\/injected_bundle\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/developer.rdkcentral.com\/documentation\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Documentation\",\"item\":\"https:\/\/developer.rdkcentral.com\/documentation\/\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"RDK Video\",\"item\":\"https:\/\/developer.rdkcentral.com\/documentation\/documentation\/rdk_video_documentation\/\"},{\"@type\":\"ListItem\",\"position\":4,\"name\":\"Components\",\"item\":\"https:\/\/developer.rdkcentral.com\/documentation\/documentation\/rdk_video_documentation\/components\/\"},{\"@type\":\"ListItem\",\"position\":5,\"name\":\"Injected Bundle\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/developer.rdkcentral.com\/documentation\/#website\",\"url\":\"https:\/\/developer.rdkcentral.com\/documentation\/\",\"name\":\"RDK Documentation Portal | Documentation\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/developer.rdkcentral.com\/documentation\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Injected Bundle - RDK Documentation Portal | Documentation","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/developer.rdkcentral.com\/documentation\/documentation\/rdk_video_documentation\/components\/injected_bundle\/","og_locale":"en_US","og_type":"article","og_title":"Injected Bundle - RDK Documentation Portal | Documentation","og_description":"Overview Injected bundle is an Integration layer between Service Manager and the player in RDK [&hellip;]","og_url":"https:\/\/developer.rdkcentral.com\/documentation\/documentation\/rdk_video_documentation\/components\/injected_bundle\/","og_site_name":"RDK Documentation Portal | Documentation","article_modified_time":"2025-03-25T05:18:36+00:00","twitter_card":"summary_large_image","twitter_misc":{"Est. reading time":"2 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/developer.rdkcentral.com\/documentation\/documentation\/rdk_video_documentation\/components\/injected_bundle\/","url":"https:\/\/developer.rdkcentral.com\/documentation\/documentation\/rdk_video_documentation\/components\/injected_bundle\/","name":"Injected Bundle - RDK Documentation Portal | Documentation","isPartOf":{"@id":"https:\/\/developer.rdkcentral.com\/documentation\/#website"},"datePublished":"2022-06-21T09:10:32+00:00","dateModified":"2025-03-25T05:18:36+00:00","breadcrumb":{"@id":"https:\/\/developer.rdkcentral.com\/documentation\/documentation\/rdk_video_documentation\/components\/injected_bundle\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/developer.rdkcentral.com\/documentation\/documentation\/rdk_video_documentation\/components\/injected_bundle\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/developer.rdkcentral.com\/documentation\/documentation\/rdk_video_documentation\/components\/injected_bundle\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/developer.rdkcentral.com\/documentation\/"},{"@type":"ListItem","position":2,"name":"Documentation","item":"https:\/\/developer.rdkcentral.com\/documentation\/"},{"@type":"ListItem","position":3,"name":"RDK Video","item":"https:\/\/developer.rdkcentral.com\/documentation\/documentation\/rdk_video_documentation\/"},{"@type":"ListItem","position":4,"name":"Components","item":"https:\/\/developer.rdkcentral.com\/documentation\/documentation\/rdk_video_documentation\/components\/"},{"@type":"ListItem","position":5,"name":"Injected Bundle"}]},{"@type":"WebSite","@id":"https:\/\/developer.rdkcentral.com\/documentation\/#website","url":"https:\/\/developer.rdkcentral.com\/documentation\/","name":"RDK Documentation Portal | Documentation","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/developer.rdkcentral.com\/documentation\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"}]}},"_links":{"self":[{"href":"https:\/\/developer.rdkcentral.com\/documentation\/wp-json\/wp\/v2\/pages\/9919","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/developer.rdkcentral.com\/documentation\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/developer.rdkcentral.com\/documentation\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/developer.rdkcentral.com\/documentation\/wp-json\/wp\/v2\/users\/28"}],"replies":[{"embeddable":true,"href":"https:\/\/developer.rdkcentral.com\/documentation\/wp-json\/wp\/v2\/comments?post=9919"}],"version-history":[{"count":2,"href":"https:\/\/developer.rdkcentral.com\/documentation\/wp-json\/wp\/v2\/pages\/9919\/revisions"}],"predecessor-version":[{"id":10999,"href":"https:\/\/developer.rdkcentral.com\/documentation\/wp-json\/wp\/v2\/pages\/9919\/revisions\/10999"}],"up":[{"embeddable":true,"href":"https:\/\/developer.rdkcentral.com\/documentation\/wp-json\/wp\/v2\/pages\/9844"}],"wp:attachment":[{"href":"https:\/\/developer.rdkcentral.com\/documentation\/wp-json\/wp\/v2\/media?parent=9919"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}