This guide explains how to implement smart push notification prompts in MobiLoud apps using the available APIs and best practices. For the purpose of this guide, we will create a button that is only displayed under the correct conditions, and that when clicked, triggers the push notification prompt.
Here's the basic flow for implementing a push notification button:
iOS_Enable_Push_Notifications: false
)To have full control over when push prompts appear, you should configure your MobiLoud app to disable the default push prompt that shows immediately when the app opens. Add these parameters to your app configuration:
{
"App_Permissions": {
"iOS_Enable_Push_Notifications": false,
"Android_Enable_Location": false
}
}
Setting iOS_Enable_Push_Notifications
to false
disables the automatic push prompt that MobiLoud normally shows on app launch. This gives you complete control over when and how to present the push notification request to your users.
Check if user is in MobiLoud app:
function isInApp() {
return navigator.userAgent.toLowerCase().includes('canvas');
}
MobiLoud apps inject "canvas" into the user agent string. This is how we determine if the user is accessing your website from within the app or from a regular browser. Push prompts should only appear when users are in the app context, since regular browsers don't have access to the native push notification functionality.
Get current status:
function isPushEnabled() {
try {
return !!(window.mobiloudAppInfo && window.mobiloudAppInfo.pushSubscribed);
} catch (e) {
return false; // Assume disabled if can't read
}
}
MobiLoud injects an object called mobiloudAppInfo
into the DOM that allows you to pull certain details about the user, including their current push notification subscription status. The pushSubscribed
property is a boolean that tells you whether the user has already enabled push notifications for your app. This is super useful because you don't want to keep asking users who have already subscribed!
Object: window.mobiloudAppInfo.pushSubscribed
Listen for status changes:
// Override the global callback
window.mlPushStatusChanged = function(isSubscribed) {
console.log('Push status changed:', isSubscribed);
// Update your UI here
updatePromptVisibility(isSubscribed);
};
Here's the thing - we can't update that mobiloudAppInfo
object in real-time when the user's subscription status changes. This is due to limitations in the WebView. So instead, MobiLoud triggers a global function called mlPushStatusChanged
whenever the subscription status changes. This makes it super easy for you to update your UI elements immediately when the user enables or disables notifications, giving them a much smoother user experience. No need to constantly check the status or refresh the page!
Function: window.mlPushStatusChanged(isSubscribed)
isSubscribed
(boolean)Show native permission dialog:
function triggerPushPrompt() {
// Only trigger if in app context
if (isInApp()) {
nativeFunctions.triggerPushPrompt();
}
}
This function triggers the native OS-level permission dialog that asks the user to enable push notifications. It's the actual system prompt that appears on iOS and Android devices.
Function: nativeFunctions.triggerPushPrompt()
The nativeFunctions
object and mobiloudAppInfo
are not available immediately when the page loads. The app needs time to initialize and inject these APIs into your webpage. Here's how to handle this:
Option 1: Polling Method
function waitForNativeFunctions(callback, maxAttempts = 50) {
let attempts = 0;
function check() {
attempts++;
// Check if APIs are ready
if (typeof nativeFunctions !== 'undefined' && window.mobiloudAppInfo) {
callback(); // APIs ready, proceed
} else if (attempts < maxAttempts) {
setTimeout(check, 100); // Try again in 100ms
}
// Stop after 5 seconds (50 × 100ms)
}
check();
}
Option 2: Event-based approach
// Wait for page to load, then start checking
document.addEventListener('DOMContentLoaded', function() {
waitForNativeFunctions(() => {
setupPushPrompt();
});
});
This ensures your code doesn't try to access APIs before they're available, which would cause errors.
Both iOS and Android have built-in restrictions on how many times an app can show the push notification permission prompt:
The good news is that nativeFunctions.triggerPushPrompt()
handles these limits automatically! When the platform limits are reached, instead of showing the native system dialog, it will automatically display a different prompt that directs users to manually enable notifications through their device settings.
You don't need to detect or handle this yourself - just call triggerPushPrompt()
and the function will either show the native dialog or the settings redirect as appropriate.
class PushNotificationButton {
constructor() {
this.button = null;
this.init();
}
init() {
// Wait for page to load
document.addEventListener('DOMContentLoaded', () => {
this.setup();
});
}
setup() {
// Wait for MobiLoud APIs to be available
this.waitForNativeFunctions(() => {
// Set up the button if conditions are met
this.updateButton();
// Listen for real-time status changes
this.setupStatusListener();
});
}
updateButton() {
const shouldShow = this.isInApp();
const isSubscribed = this.isPushEnabled();
if (shouldShow) {
if (!this.button) {
// Create button if it doesn't exist
this.createButton();
}
// Update button text based on subscription status
if (isSubscribed) {
this.button.textContent = '✅ Notifications Enabled';
this.button.disabled = true;
} else {
this.button.textContent = '🔔 Enable Notifications';
this.button.disabled = false;
}
} else {
// Hide button if not in app
this.hideButton();
}
}
createButton() {
// Create the button element
this.button = document.createElement('button');
this.button.style.cssText = `
padding: 12px 24px;
background-color: #007AFF;
color: white;
border: none;
border-radius: 8px;
font-size: 16px;
cursor: pointer;
margin: 10px;
`;
// Handle button clicks
this.button.onclick = () => this.handleClick();
// Add button to page (you can change this to any container)
document.body.appendChild(this.button);
}
handleClick() {
// Only trigger if user is in app and not subscribed
if (this.isInApp() && !this.isPushEnabled()) {
// This will show native prompt or settings redirect automatically
nativeFunctions.triggerPushPrompt();
}
}
isInApp() {
// Check if user is in MobiLoud app
return navigator.userAgent.toLowerCase().includes('canvas');
}
isPushEnabled() {
// Check current subscription status
try {
return !!(window.mobiloudAppInfo &&
window.mobiloudAppInfo.pushSubscribed);
} catch (e) {
return false;
}
}
setupStatusListener() {
// Store any existing callback
const original = window.mlPushStatusChanged;
// Override with our handler
window.mlPushStatusChanged = (isSubscribed) => {
// Call original callback if it existed
if (typeof original === 'function') original(isSubscribed);
// Update button based on new status
this.updateButton();
};
}
hideButton() {
// Remove button if it exists
if (this.button) {
this.button.remove();
this.button = null;
}
}
waitForNativeFunctions(callback, maxAttempts = 50) {
let attempts = 0;
function check() {
attempts++;
// Check if both APIs are available
if (typeof nativeFunctions !== 'undefined' && window.mobiloudAppInfo) {
callback(); // Ready to go!
} else if (attempts < maxAttempts) {
setTimeout(check, 100); // Try again in 100ms
}
// Stop after 5 seconds total
}
check();
}
}
// Initialize the notification button
new PushNotificationButton();
The button will automatically: