This repository contains a minimal, lightweight, and secure boilerplate template demonstrating the integration lifecycle of an Oracle Field Service Cloud (OFSC) Plugin.
It is designed to serve as a clean reference architecture for developers who need to build custom plugins, forms, or applications that run inside an iframe within Oracle Field Service and communicate with the core application.
This template comes pre-configured with essential capabilities required for enterprise OFS plugins:
- 🎨 Oracle Redwood Styling: Responsive interface matching Oracle's Redwood design palette (Terracotta, Slate Blue, Canvas Cream, and custom focus outlines) for a native extension appearance.
- ⚙️ Auto-Discovery & App Configuration: Dynamically parses and discovers core application configurations and endpoint URLs (
resourceUrl) from the hostinitpayload. - 🔑 Multi-App OAuth Token Caching: Automatically discovers all configured host integrations (OFS, OIC, Oracle CX, SCM, ERP) and requests/caches their respective OAuth tokens in parallel on startup using
callProcedure➡️getAccessToken. - 📶 Online/Offline Connection State Management: Native listeners track connection drops/restorations, displaying toast warnings and toggling network status badges.
- 💾 Local Form State Persistence: Automatically saves form values locally in the background (offline support) and restores inputs if the page resets or the session expires.
- 📸 Native Code Scanner Integration: Demonstrates device hardware integration by triggering the native device camera scanner via
callProcedure➡️scanBarcode. - 📍 Device Geolocation Integration: Demonstrates location services by retrieving precise device coordinates (Latitude, Longitude, and Accuracy) using the native HTML5 Geolocation API.
Oracle Field Service plugins run in isolated contexts (iframes) and communicate with the host OFSC Core Application using the HTML5 cross-origin window.postMessage() API.
- Auto-Discovery (
ready): The plugin loads and immediately posts areadymessage to the parent frame. - Metadata Setup (
init&initEnd): IfsendInitDatawas set totrue, OFSC Core replies with theinitmessage (containing configuration properties, translation elements, and application endpoints). The plugin saves this and acknowledges withinitEnd. - Active State (
open): When the user opens the plugin page, OFSC Core sends theopenmessage containing contextual parameters (e.g.aidfor Activity ID,resourceIdfor the technician's record). The plugin dynamically retrieves and caches OAuth access tokens in parallel for all configured applications (OFS, OIC, CX, SCM, ERP, etc.) viagetAccessTokenand renders the UI. - Synchronization (
closeorupdate): When the user completes their actions, the plugin sends aclosemessage containing anactionsarray specifying what properties to update on the activity or inventory. The host applies the updates and closes the plugin iframe.
sequenceDiagram
participant P as Plugin (Iframe)
participant H as OFS Core Application
Note over P,H: Hidden Initialization Phase
P->>H: postMessage({ method: "ready", sendInitData: true })
H->>P: postMessage({ method: "init", applications: { App_OFS: {...}, App_OIC: {...} } })
P->>P: Store Metadata Configurations
P->>H: postMessage({ method: "initEnd" })
Note over H: Core destroys initialization iframe
Note over P,H: Visible Active Phase (User Opens Plugin)
H->>P: postMessage({ method: "open", openParams: {...} })
P->>H: postMessage({ method: "callProcedure", procedure: "getAccessToken", params: { applicationKey: "App_OFS" } })
H->>P: postMessage({ method: "callProcedureResult", token: "..." })
P->>H: postMessage({ method: "callProcedure", procedure: "getAccessToken", params: { applicationKey: "App_OIC" } })
H->>P: postMessage({ method: "callProcedureResult", token: "..." })
P->>P: Render UI & Fetch external REST APIs using App tokens
Note over P,H: Submission / Exit Phase
P->>H: postMessage({ method: "close", actions: [...], backScreen: "default" })
Note over H: Core updates record properties and closes iframe
index.html: Entry point for the plugin UI. Includes basic layout, action buttons, and loading spinner placeholder.style.css: Styling sheets including clean UI classes and a loader spinner aligned to the Oracle Redwood color themes.plugin.js: Core plugin controller. Manages:- Secure bidirectional message sending/receiving.
- Verification of message origins.
- Tracking synchronous procedure responses (
callProcedure). - Form validation, auto-saving of offline state, and posting updates.
localStorage.js: An abstraction layer for local storage to cache credentials, logs, and form states.
To deploy and test this plugin within your Oracle Field Service (OFS) environment:
- Package the Plugin:
Create a standard
.ziparchive containing the plugin files. Ensure thatindex.htmlis in the root directory of the archive (not nested inside a subfolder). - Upload to OFS Console:
- Log into Oracle Field Service as an administrator.
- Go to Configuration ➡️ Forms & Plugins.
- Click Add Plugin ➡️ select Plugin Archive ➡️ upload your ZIP file.
- Set the following configuration parameters:
- Label:
TEST_HELLO_OFSC(this must match the bootstrap name inplugin.js). - Applications: Associate the external applications (OIC, CX, SCM, ERP) that this plugin is authorized to request access tokens for.
- Allowed Procedures: Enable
scanBarcode(and any other native device operations your plugin calls).
- Label:
- Map the Plugin to a Button:
- Go to Configuration ➡️ User Types ➡️ Screen Configuration.
- Edit the target screen layout (e.g., Activity Details or Edit Activity).
- Add a button, set the Action to launch your registered plugin (
TEST_HELLO_OFSC), and configure the visibility settings.
- Bootstrap Label: Update the registration label at the bottom of
plugin.jsto match your registered OFS plugin label:plugin.init("YOUR_OFS_PLUGIN_LABEL");
- OFS Property Mapping: The template automatically loops through HTML inputs and maps their
ids to uppercase OFS properties (e.g. input#cust_phoneautomatically maps toCUST_PHONE). Ensure your HTMLids match your target OFS custom properties. - Cross-Origin Storage: Since plugins run in iframes, browser security rules (like Safari ITP) may block
localStorage. If needed, implement an in-memory or cookie fallback inlocalStorage.js.
Note
Complementary / Optional Features: Barcode scanning and Geolocation are included as template demonstrations. These are complementary features that can be implemented or enabled if a client or business user specifically requests them. If your requirements do not call for them, the associated UI buttons, handlers, and helper methods in plugin.js can be safely removed to keep the plugin codebase even lighter.
- In [plugin.js], the
scanBarcodemethod uses OFSC'scallProcedureto invoke the native mobile app's barcode reader:const scanResult = await this.scanBarcode();
- Make sure to add
scanBarcodeto your plugin's Allowed Procedures in the OFS Administration screen.
- To obtain the resource's current coordinates, the plugin uses standard HTML5 Geolocation (
navigator.geolocation.getCurrentPosition) instead of custom RPC calls:const coords = await this.getLocation();
- Ensure location services are enabled on the target device and that the web browser or OFS Mobile app has permission to access device location.
Because OFSC plugins rely on the parent frame's postMessage protocol, they cannot run autonomously in a standalone tab.
To test locally:
- Start a local server (e.g., using
npx serveor Live Server in VS Code). - Create a mock wrapper page that frames the
index.htmlplugin in an iframe and simulates the OFSC Core messages. - Verify that the console displays the outgoing lifecycle messages (
ready,initEnd,close).