SDK integration
HoneyNotify's Swift, Kotlin, Flutter, React Native, and web clients handle device registration, token refresh, user association, notification payload parsing, and engagement events. Give every client a restricted ps_public_ key-never a server send key.
Get the SDK source from GitHub:
Want to try HoneyNotify before building your own native shell? The ready-to-build demo apps provide configurable full-screen WebView projects for iOS and Android with registration, token refresh, notification-open handling, and lifecycle tracking already connected. Follow the demo apps guide for the complete setup path.
Common lifecycle#
Whichever platform you use, the durable integration pattern is:
- Ask for notification permission in context, after explaining the value.
- Obtain the provider token or browser Push subscription.
- Register it with HoneyNotify and retain the returned device ID.
- Identify after login, using a backend-issued identity token when verification is enabled.
- Refresh registration when provider tokens or audience attributes change.
- Parse notification data and track received, confirmed-delivered, opened, and clicked lifecycle events.
- Disable the device and clear local identity at logout or unsubscribe.
iOS 15+#
Add the Swift package from GitHub, initialise it once, and use your public client key.
Configure APNs server credentials#
HoneyNotify uses an APNs token-signing key to send notifications. In Apple Developer, open Certificates, Identifiers & Profiles → Keys, create a key with Apple Push Notifications service (APNs) enabled, and download its .p8 file. Apple allows the file to be downloaded only once, so store your original securely.
On the app's Apple iOS (APNs) setup screen in HoneyNotify, upload the .p8 file and enter:
- the 10-character Key ID shown beside the key in Apple Developer;
- the 10-character Team ID shown in Apple Developer membership details;
- the app's Bundle ID from Xcode under the target's Signing & Capabilities; and
- the Production environment for TestFlight or App Store builds, or Sandbox for development builds run directly from Xcode.
HoneyNotify validates and encrypts the credential. The .p8 key is a server credential: never add it to the iOS application, source control, or a public client.
import HoneyNotify
let honeyNotify = HoneyNotify(
baseURL: URL(string: "https://api.honeynotify.com")!,
clientKey: "ps_public_replace_me"
)
let granted = try await honeyNotify.requestPermissionAndRegister()
Only after Apple approves the host app's Critical Alerts entitlement, request the additional permission with requestPermissionAndRegister(includeCriticalAlerts: true). Use criticalAlertPermissionStatus() to inspect the user's current choice. HoneyNotify cannot grant this entitlement from the server or SDK.
Forward the APNs token from your application delegate:
func application(
_ application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data
) {
Task {
_ = try await honeyNotify.register(
deviceToken: deviceToken,
tags: ["plan": "free"]
)
}
}
Use refresh(deviceToken:) for later APNs token changes. It preserves the external user ID and tags stored by the SDK.
After login:
_ = try await honeyNotify.identify(
externalUserId: account.id,
tags: ["plan": account.plan],
identityToken: tokenFromYourBackend
)
In notification callbacks, use notification(from:), trackReceived(userInfo:), and trackOpened(userInfo:actionId:). Use track(event: "confirmed_delivered", notificationId: notification.id) only where your app can genuinely confirm display or device-side delivery. For rich images, use HoneyNotifyMediaAttachment in a Notification Service Extension. Call logout() before clearing your app session if this device should stop receiving notifications for that user.
Android with Firebase#
Include the Android SDK source from GitHub in an application module configured for Firebase Messaging.
Configure Firebase server credentials#
HoneyNotify sends Android notifications through the Firebase Cloud Messaging HTTP v1 API. In the Firebase Console, open your project, then go to Project settings → Service accounts → Firebase Admin SDK and choose Generate new private key. Upload the downloaded .json file on your app's Google Android (FCM) setup screen in HoneyNotify.
The service-account JSON is a server credential. HoneyNotify validates and encrypts it when uploaded; do not add it to your Android project, source control, or a public client. Your Android application separately uses Firebase's google-services.json, which is not the file uploaded to HoneyNotify.
val honeyNotify = HoneyNotify(
applicationContext,
"https://api.honeynotify.com",
"ps_public_replace_me"
)
honeyNotify.createNotificationChannels()
honeyNotify.registerCurrentToken(tags = mapOf("plan" to "free")) { result ->
result.onFailure { error -> Log.e("Push", "Registration failed", error) }
}
Forward token refreshes from FirebaseMessagingService:
override fun onNewToken(token: String) {
Thread { runCatching { honeyNotify.onTokenRefresh(token) } }.start()
}
Use the async helpers from UI-facing code:
honeyNotify.identifyAsync(
externalUserId = account.id,
tags = mapOf("plan" to account.plan),
identityToken = tokenFromYourBackend
) { result ->
result.onFailure { error -> Log.e("Push", "Identity failed", error) }
}
notificationFrom(data) extracts the notification ID, click URL, image URL, interruption level, channel ID, and data from FCM fields. Create the channels during foreground startup, before level-specific notifications arrive. Call trackReceived(data) when the message is received, track("confirmed_delivered", notification.id) only after a genuine device-side confirmation, and trackOpened(data, actionId) from the user's interaction. Network methods such as register, identify, and logout are blocking; do not call them on the Android main thread. Android users can override every channel's importance and sound; HoneyNotify does not request full-screen intent or DND-policy access.
Flutter for iOS and Android#
Add the Flutter SDK, configure firebase_core and Firebase Messaging for both native targets, then initialise Firebase before HoneyNotify:
await Firebase.initializeApp();
final honeyNotify = HoneyNotify(
clientKey: 'ps_public_replace_me',
);
final deviceId = await honeyNotify.requestPermissionAndRegister(
options: HoneyNotifyRegistrationOptions(
externalUserId: account?.id,
identityToken: tokenFromYourBackend,
tags: {'plan': account?.plan ?? 'visitor'},
),
);
final tokenRefresh = honeyNotify.startTokenRefreshListener(
identityTokenProvider: (_) => fetchIdentityTokenFromYourBackend(),
onError: (error, stackTrace) => logPushError(error, stackTrace),
);
The package registers the APNs token on iOS and the FCM token on Android. Cancel tokenRefresh when the application-owned integration is disposed. When verified identity is required, identityTokenProvider must fetch a fresh short-lived token from your authenticated backend. Connect FirebaseMessaging.onMessage to trackReceived(message.data) and FirebaseMessaging.onMessageOpenedApp to trackOpened(message.data). Background handlers must be top-level functions and must initialise Firebase before using Firebase services.
Call identify after login and logout before clearing the local session when the device should stop receiving user notifications. The host application remains responsible for Firebase configuration, iOS capabilities, Android notification permission, visible notification rendering, deep-link routing, and avoiding duplicate event calls across foreground and background handlers.
React Native for iOS and Android#
Install the React Native SDK from GitHub with React Native Firebase Messaging and Async Storage, then run CocoaPods for iOS:
import { HoneyNotify } from '@honeynotify/react-native';
const honeyNotify = new HoneyNotify({
clientKey: 'ps_public_replace_me',
});
const deviceId = await honeyNotify.requestPermissionAndRegister({
externalUserId: account?.id,
identityToken: tokenFromYourBackend,
tags: { plan: account?.plan ?? 'visitor' },
});
const stopTokenRefresh = honeyNotify.startTokenRefreshListener({
identityTokenProvider: async () => fetchIdentityTokenFromYourBackend(),
onError: (error) => reportPushError(error),
});
The SDK uses getAPNSToken() on iOS and getToken() on Android, preserving the correct delivery-provider boundary. Keep and call stopTokenRefresh when the owning application scope is disposed. When verified identity is required, identityTokenProvider must fetch a fresh short-lived token from your authenticated backend. Connect React Native Firebase's onMessage to trackReceived(message) and onNotificationOpenedApp to trackOpened(message); register any background handler at module scope.
Call identify after login and logout before clearing the local session when appropriate. The host application remains responsible for the native Firebase files and capabilities, Android notification channels and permission, foreground display, deep-link routing, and callback deduplication.
Web Push#
HoneyNotify supports three website integration paths:
- Typical Site for an HTML, PHP, or other server-rendered website, with a dashboard generator that creates a restricted public key and a ready-to-paste hosted-SDK snippet;
- WordPress Plugin for a ready-made installable ZIP with a settings page, shortcode, opt-in button, and root service worker;
- Magento Module for a ready-made Magento 2 ZIP with storefront configuration and opt-in;
- Drupal Module for a Drupal 10/11 ZIP with configuration, a block, and optional automatic button;
- Joomla Plugin for a Joomla 4/5 ZIP with site-plugin configuration and opt-in; and
- Custom Code for direct control of registration, user identity, tags, events, and unsubscribe behaviour.
Follow the complete Web Push setup guide, use Generate code snippet for me in the Web channel, or download the web SDK from GitHub. The hosted module is available at https://app.honeynotify.com/cdn/honeynotify-v1.js. Serve honeynotify-sw.js from your own site root (or configure the matching service-worker path), then initialise the browser module:
import { HoneyNotify } from 'https://app.honeynotify.com/cdn/honeynotify-v1.js';
const honeyNotify = new HoneyNotify({
baseURL: 'https://api.honeynotify.com',
clientKey: 'ps_public_replace_me',
vapidPublicKey: 'your_url_safe_vapid_public_key',
serviceWorkerPath: '/honeynotify-sw.js',
});
const deviceId = await honeyNotify.requestPermissionAndRegister({
externalUserId: currentUser?.id,
identityToken: tokenFromYourBackend,
tags: { plan: currentUser?.plan ?? 'visitor' },
});
The method returns null if permission is not granted. Browser permission prompts require a secure context and work best after a user gesture.
Track an application event:
await honeyNotify.track('checkout.abandoned', {
metadata: { basket_id: 'basket_441' },
});
Call unsubscribe() to unsubscribe from the browser push service, disable the HoneyNotify device, and remove its local ID.
Identity token endpoint on your backend#
When identity verification is enabled, your authenticated backend should expose a small endpoint that returns a short-lived ES256 JWT for the current user. The private EC key must stay on the backend. The client requests a new token at login or identity refresh and passes it unchanged to the SDK.
Do not accept an arbitrary external user ID in that backend endpoint. Derive sub from the authenticated session, set iss to the HoneyNotify app public ID, and keep exp within one hour.
Testing checklist#
- Test first permission grant, denial, and previously denied states.
- Confirm registration returns the same logical device after token refresh.
- Test anonymous use, login, account switching, and logout.
- Confirm notification tap and action IDs reach your deep-link router.
- Test foreground, background, and terminated app states.
- On Flutter and React Native, confirm that iOS registers an APNs token and Android registers an FCM token.
- Test missing images and expired deep links.
- Confirm events appear under the intended notification and device.
- Confirm a repeated open callback remains visible in event history but counts once in the unique open rate.
- Never use production users for broad-send tests; target an isolated test device or user.
Provider migration behaviour#
No special SDK call is required after an owner imports devices from a supported provider through the dashboard. The normal register or registerCurrentToken call sends the current APNs or FCM token. HoneyNotify checks the separate migration lookup for the same token and platform. On a match it claims the row and returns its assigned HoneyNotify device_id, which the SDK stores normally. UUID source IDs are retained; non-UUID source IDs receive a stable, provider-scoped HoneyNotify UUID. Without a match, registration behaves exactly like a new HoneyNotify installation and returns a newly generated HoneyNotify UUID.
For the highest automatic match rate, upload the provider export shortly before releasing the HoneyNotify-enabled app. Devices whose provider token changes between export and first HoneyNotify registration cannot be recognised from the token alone and receive a new HoneyNotify UUID.
