Wrapply logoWrapply Tutorials
🧩 Native bridge

Wrapply Bridge API: connect your website to native app features

Practical guide to Wrapply native bridge APIs for notifications, deep links, inbound links, in-app purchases and location in generated Flutter apps.

Native bridge reference

The generated Flutter app exposes window.Wrapply inside the WebView. Your website can call this object to use native features only when the related module is enabled during configuration. Always wait for wrapplyNativeBridgeReady and always handle { ok:false, error } as a normal fallback case.

APIWhen to use itInputResponse
window.Wrapply.isNativeApp()Detect the native wrappernonetrue inside app
notifications.requestPermission(payload)Ask notification permission{ provider }{ ok, permission, granted }
notifications.getToken(payload)Read or refresh the device token{ provider, refresh? }{ ok, token, provider }
notifications.refreshToken(payload)Regenerate the token. Alias: updateToken{ provider }{ ok, token, refreshed:true }
notifications.show(payload)Show an immediate local notification{ title, body?, data? }{ ok, shown:true }
notifications.getStatus(payload)Read provider and permission status{ provider }{ ok, granted, configured? }
iap.getProducts(payload)Read configured store products{ packageName, productIds }{ ok, available, products }
iap.purchase(payload)Start an in-app purchase{ packageName, productId, consumable? }{ ok, purchaseStarted }
iap.restorePurchases(payload)Restore non-consumable purchases{ packageName }{ ok, latestPurchases }
deepLinks.open(payload)Open internal URL, external URL, phone, email or WhatsApp{ type, url/value }{ ok, type, url }
wrapply://open/pathOpen the installed app from email, SMS or external siteexternal linkloads https://DOMAIN/path
When bridge features are enabled, Wrapply also provides a PDF guide with enabled modules, exact calls, provider configuration and store-review notes.

Notification providers

The website can choose the notification provider on each call. Wrapply includes only the provider selected in the generated app.

ProviderUseRequired configurationImportant note
localSafe default, local token stored in shared preferencesNo external fileUseful for tests/session ID; not a real remote push token
firebaseFirebase Cloud Messaging providerandroid/app/google-services.json and optional ios/Runner/GoogleService-Info.plistIf files are missing, bridge returns ok:false/configured:false
onesignalOneSignal providerOneSignal App ID in configuration/buildRequires OneSignal setup before sending remote pushes

Device permissions

Camera, microphone and geolocation use standard browser APIs. The wrapper adds the native Android/iOS permissions when the feature is enabled.

FeatureWeb APINative permissionsBehaviour
Cameranavigator.mediaDevices.getUserMedia({ video:true })Android CAMERA, iOS NSCameraUsageDescriptionUse standard web API; app handles native prompt
Microphonenavigator.mediaDevices.getUserMedia({ audio:true })Android RECORD_AUDIO, iOS NSMicrophoneUsageDescriptionUse standard web API; no direct Wrapply call
Geolocationnavigator.geolocation.getCurrentPosition(...)Android COARSE/FINE, iOS location usage stringFine location is optional and should be enabled only when needed

Examples by code type

These examples are intentionally small: they show the exact integration pattern, while your generated PDF lists the modules enabled for the specific app.

Ready helper

function onWrapplyReady(callback) {
if (window.Wrapply && window.Wrapply.__nativeBridgeReady) {
callback(window.Wrapply);
return;
}
window.addEventListener("wrapplyNativeBridgeReady", () => {
callback(window.Wrapply);
}, { once: true });
}

JavaScript

document.querySelector("#notify").addEventListener("click", async () => {
if (!window.Wrapply?.notifications) return alert("Available inside the app");
const permission = await window.Wrapply.notifications.requestPermission({ provider: "firebase" });
if (!permission.ok || !permission.granted) return;
const token = await window.Wrapply.notifications.getToken({ provider: "firebase" });
await fetch("/api/device-token", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ token: token.token, platform: "wrapply" })
});
});

TypeScript

type WrapplyResponse = Promise<Record<string, unknown>>;
declare global {
interface Window {
Wrapply?: {
__nativeBridgeReady?: boolean;
isNativeApp: () => Promise<boolean>;
notifications?: {
requestPermission: (p: Record<string, unknown>) => WrapplyResponse;
getToken: (p: Record<string, unknown>) => WrapplyResponse;
refreshToken: (p: Record<string, unknown>) => WrapplyResponse;
updateToken: (p: Record<string, unknown>) => WrapplyResponse;
show: (p: Record<string, unknown>) => WrapplyResponse;
getStatus: (p: Record<string, unknown>) => WrapplyResponse;
};
iap?: { purchase: (p: Record<string, unknown>) => WrapplyResponse };
deepLinks?: { open: (p: Record<string, unknown>) => WrapplyResponse };
};
}
}
export {};

React

import { useEffect, useState } from "react";
export function useWrapplyBridge() {
const [ready, setReady] = useState(false);
useEffect(() => {
if (window.Wrapply?.__nativeBridgeReady) return setReady(true);
const onReady = () => setReady(true);
window.addEventListener("wrapplyNativeBridgeReady", onReady);
return () => window.removeEventListener("wrapplyNativeBridgeReady", onReady);
}, []);
return { ready, Wrapply: ready ? window.Wrapply : null };
}

Vue 3

import { ref, onMounted, onBeforeUnmount } from "vue";
export function useWrapplyBridge() {
const ready = ref(false);
const markReady = () => { ready.value = true; };
onMounted(() => {
if (window.Wrapply?.__nativeBridgeReady) markReady();
else window.addEventListener("wrapplyNativeBridgeReady", markReady);
});
onBeforeUnmount(() => window.removeEventListener("wrapplyNativeBridgeReady", markReady));
return { ready };
}

Angular

@Injectable({ providedIn: "root" })
export class WrapplyBridgeService {
async requestToken(provider = "firebase") {
if (!window.Wrapply?.notifications) {
return { ok: false, error: "Bridge unavailable" };
}
return window.Wrapply.notifications.getToken({ provider });
}
}

jQuery

$("#wrapply-token").on("click", async function () {
if (!window.Wrapply?.notifications) return;
const result = await window.Wrapply.notifications.getToken({ provider: "local" });
$("#wrapply-output").text(JSON.stringify(result, null, 2));
});

PHP / Laravel Blade

<button onclick="buyNativeProduct()">Buy premium</button>
<script>
async function buyNativeProduct() {
if (!window.Wrapply?.iap) return;
const result = await window.Wrapply.iap.purchase({
packageName: "{{ config('app.mobile_package') }}",
productId: "premium_monthly",
consumable: false
});
console.log(result);
}
</script>

WordPress

add_action('wp_footer', function () { ?>
<script>
window.wrapplyNotify = async function () {
if (!window.Wrapply?.notifications) return;
return window.Wrapply.notifications.show({
title: "WordPress",
body: "Notification called from theme/plugin"
});
};
</script>
<?php });

Deep links

// External links from email, SMS, CRM or website
wrapply://open/profile
wrapply://open/checkout?plan=premium
wrapply://open/orders/123

// Native action inside the app
await window.Wrapply.deepLinks.open({ type: "internal_url", url: "https://example.com/account" });
await window.Wrapply.deepLinks.open({ type: "mailto", value: "support@example.com" });
await window.Wrapply.deepLinks.open({ type: "tel", value: "+390000000000" });
await window.Wrapply.deepLinks.open({ type: "whatsapp", value: "+390000000000" });

What the Wrapply bridge does

The bridge exposes a JavaScript API inside the WebView. Your website can call window.Wrapply and the generated Flutter app handles the native action only when the related feature was enabled during configuration.

When bridge features are selected, Wrapply also provides a PDF implementation guide with the exact calls, enabled modules and configuration notes for your generated project.

Enable only the modules you need

Notifications
Local/Firebase/OneSignal provider, permission request, token read/refresh and local notification display.
Actions and deeplinks
Open internal WebView URLs, external browser URLs, phone, email and WhatsApp from your website.
Inbound links
Open the installed app from a configured scheme or app link, then route the user to the right page.
In-app purchases
Query store products, start purchase, restore purchases and send results to your backend for validation.
Location
Add the native permission base for maps, nearby results or geolocation flows.

Setup flow

1. Configure features

Enable only the modules you need in the Wrapply configurator.

2. Add required files

Upload Firebase files or provider identifiers when the selected provider requires them.

3. Generate source code

Wrapply writes conditional dependencies, AndroidManifest entries, Info.plist keys and bridge modules.

4. Add JavaScript calls

Call window.Wrapply from your website only after checking the bridge exists.

5. Test before publishing

Test native permissions, tokens, purchases and links on real Android/iOS devices.

Real JavaScript examples

Use these calls from your website only after verifying that window.Wrapply exists.

Notifications

async function enablePush() {
if (!window.Wrapply?.notifications) return;
await window.Wrapply.notifications.requestPermission({ provider: 'firebase' });
const token = await window.Wrapply.notifications.getToken({ provider: 'firebase' });
await fetch('/api/device-token', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ token: token.token, platform: 'app' })
});
}
window.Wrapply?.notifications?.show({ title: 'Order updated', body: 'Your request is ready' });

Actions and deeplinks

window.Wrapply?.deepLinks?.open({ type: 'internal_url', url: 'https://example.com/account' });
window.Wrapply?.deepLinks?.open({ type: 'mailto', value: 'support@example.com' });
window.Wrapply?.deepLinks?.open({ type: 'tel', value: '+390000000000' });
window.Wrapply?.deepLinks?.open({ type: 'whatsapp', value: '+390000000000' });
window.Wrapply?.deepLinks?.open({ type: 'url', url: 'https://example.com/help' });

In-app purchases

async function buyPremium() {
if (!window.Wrapply?.iap) return;
await window.Wrapply.iap.getProducts({ productIds: ['premium_monthly'] });
const result = await window.Wrapply.iap.purchase({
productId: 'premium_monthly',
consumable: false,
applicationUserName: currentUser.id
});
await fetch('/api/iap/verify', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(result)
});
}

Location

if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition((position) => {
console.log(position.coords.latitude, position.coords.longitude);
});
}

What you receive with bridge features

Conditional source code
Only selected dependencies, permissions and bridge files are included.
Configuration files
Firebase files, OneSignal App ID and iOS optional files are inserted only when requested.
PDF implementation guide
When bridge features are selected, Wrapply also provides a PDF implementation guide with the exact calls, enabled modules and configuration notes for your generated project.
Store review support
Payment, notification and permission modules should be tested before publishing.

Bridge FAQ

Does the bridge work on the public website?

No. It works inside the generated app WebView. Always check window.Wrapply before calling native APIs.

Do I need a backend?

For Firebase push and in-app purchase validation, yes. The app exposes tokens and purchase events, but the backend should send messages and validate receipts.

Can Wrapply implement it?

Yes. Managed publishing can include configuration, testing and documentation for the enabled bridge modules.

Ready to connect native features?

Practical guide to Wrapply native bridge APIs for notifications, deep links, inbound links, in-app purchases and location in generated Flutter apps.