Pugpig HTML Bridge Overview
This article provides a comprehensive overview of the Pugpig HTML Bridge, giving readers insights into its functionalities and capabilities to enhance their understanding of this technology.
Table of Contents
Pugpig Bolt is a hybrid app - it uses native code where appropriate but also renders certain parts of the app using native HTML Webviews. The purpose of the HTML bridge is to allow the webviews to pass information back and forth with the native code. You can think of it in a similar way to a bridge provided by the Apache Cordova project, but more powerful for specific kinds of apps.
The main screens which need access to the bridge are:
- The Timeline and Storefront pages
- The Article View pages
- The search pages
- And HTML settings pages
The bridge has various components, which are discussed below. We also have a reference doc providing details of all the available bridge calls.
Access to native device functionality
The purpose of the Pugpig HTML bridge is to allow a link in the HTML content of a page to trigger a function of the app native code, optionally passing in parameters. A common implementation is to interact with device hardware like the camera and to interact with system level resources such as calendars, contacts and stored media.
Our Pugpig HTML bridge includes functions for:
- Full Screen Image Gallery
- Internal and External Links
- Cross edition links / upsells
- Create calendar entries
- In Page Analytic Events
- Invoking the camera (Publish only)
- Audio Authorisation status
- User metadata
- Logging
- Localisation
- Edition management
This bridge is internally referenced as 'pugpigBridgeService' for Bolt and 'KGJavascriptBridge' for Publish and we also have documentation on extending the bridge yourself if you use our toolkit products.
Access to information about the content
This gives the HTML pages access to the content structure of the entire app. It is particularly useful for a storefront which needs to show all of the available editions that can be purchased.
Access to information about the current user
This allows the HTML pages to display information about the user, or decide to show different content based on their logged in state. It also allows integrations with third parties in the HTML content as we have access to the user details. A good example of this is integration with third party HTML/Javascript based commenting systems.
Collection Sets
The bridge currently does not pass in the information about the chosen collection set. This is needed to filter search results, for example.
Technical Javascript Concepts
The Pugpig Bridge Service is a global object maintained by native applications and is injected into content views. This object includes various functions facilitating the retrieval of app data from within content views.
Accessing the Pugpig Bridge Service
To access the bridge: use parent.pugpigBridgeService
- we just need to call upon a global object, however, we should also handle the case of it not existing by defaulting it to an empty object. An example JavaScript code snippet demonstrating the retrieval of the bridge object is provided below:
parent.pugpigBridgeService = parent.pugpigBridgeService || {};
Example invocation
The code below shows an example of retrieving data from the bridge (as mentioned above we can trigger various actions) in this example we'll are retrieving all the authorisation data associated with the current user as a JSON object.
async function fetchUserData() {
const payload = await parent.pugpigBridgeService?.authorisationStatus()
const payloadJson = JSON.parse(payload)
console.log(payloadJson)
}
(Note: The methods on the bridge service return promises on iOS and is a standards callback on Android so it's recommended to use async/await to handle both platform differences. Furthermore, all data returned from the bridge is in string format, as such it requires json parsing).
Handling updates
Occasionally the app may need to post updates to indicate new data availability in the bridge. To manage this the content should create a window.pugpigUpdate
function. This update function should handle various updates and receive the bridge name as the first parameter (the name of the method to be called/bridge being updated is passed as the first argument) Here's an example:
window.pugpigUpdate = async (method, _args) => {
if (method === 'authorisationStatus') return console.log('Authorisation status bridge updated!');
}
It's important to note that the typical flow involves creating the pupigUpdate
function, triggering it, and then calling the corresponding method via parent.pugpigBridgeService
as shown below in which we handle both logging the userId on page load and whenever the app posts an update.
parent.pugpigBridgeService = parent.pugpigBridgeService || {};
window.pugpigUpdate = async (method, _args) => {
if (method !== 'authorisationStatus' || !parent.pugpigBridgeService.authorisationStatus) return
const userIdScheme = 'http://schema.pugpig.com/attribute/user_id'
const payload = await parent.pugpigBridgeService?.authorisationStatus()
const { userInfo } = JSON.parse(payload)
const userId = userInfo?.[userIdScheme] || 'unknown'
console.log(userId)
}
window.addEventListener('DOMContentLoaded', () => {
window.pugpigUpdate('authorisationStatus')
})
Putting it all together
In the following example we bring together all the concepts discussed. We retrieve the user ID from the authorisationStatus
bridge and then pass it to a theoretical sendAnalytics
function. In this particular case the function simply logs the user ID, but it could be extended to forward it using a third-party service if necessary. Additionally we ensure seamless handling of updates from the application and address the scenario where the bridge might not exist.
/**
* Cache any existing functions to ensure no logic is
*/
parent.oldPugpigUpdate = window.pugpigUpdate || undefined;
parent.pugpigBridgeService = parent.pugpigBridgeService || {}
/**
* Asynchronously fetches the user ID from the Pugpig Bridge Service.
* @returns {Promise<string>} A Promise that resolves to the user ID.
*/
async function fetchUserId() {
if (!parent.pugpigBridgeService?.authorisationStatus) return
const userIdScheme = 'http://schema.pugpig.com/attribute/user_id'
const payload = await parent.pugpigBridgeService?.authorisationStatus()
const { userInfo } = JSON.parse(payload)
const userId = userInfo?.[userIdScheme] || 'unknown'
return userId
}
/**
* Asynchronously sends an analytics event and logs the user ID.
* @param {string} userId - The user ID to be included in the analytics event.
*/
function sendAnalyticsEvent(userId) {
console.log(userId) // placeholder.
}
/**
* Triggers when containing application updates the data in the bridge i.e. auth changes.
* @param {string} method - The Pugpig update method.
* @param {any} args - Arguments for the Pugpig update method.
* @returns {Promise<void>} A Promise that resolves after the update is complete.
*/
window.pugpigUpdate = async (method, args) => {
// Call the original Pugpig update function if available.
if (parent.oldPugpigUpdate) parent.oldPugpigUpdate(method, args)
if (method !== 'authorisationStatus') return
const userId = await fetchUserId()
sendAnalyticsEvent(userId)
}
/**
* Run pugpigUpdate authorisationStatus on page load.
*/
window.addEventListener('DOMContentLoaded', () => {
window.pugpigUpdate('authorisationStatus')
})