← Back to Mobile application starters · project planning pack
See how it helps
Notifications and deep links
Routes notification and link entry safely across app startup, authentication and unavailable resources.
mobile-notifications-deeplinks
Agents using this skill
When is it useful?
Use when tapping a notification opens the wrong screen or loses its destination.
What does it help you do?
- Manages push registration and token rotation or removal.
- Handles foreground, background and cold-start routing without duplicate navigation.
- Validates links and restores destinations after login with meaningful back history.
Try asking this
Open an order notification while logged out, then sign in and handle an order that was deleted. Deliver the notification twice during cold start. Navigate once after authentication, then show a useful missing-order state instead of an empty or forbidden screen.
Detailed documentation
Read the skill’s original instructions, examples and checks in their authored language.
Show less
Push Notifications & Deep Links
Deliver users from push notifications, Universal Links, Android App Links and custom URL schemes to the right screen safely across cold starts, background resumes and foreground sessions.
1. Push notification registration and token lifecycle
- Contextual permission prompt: explain the value of notifications before calling
requestPermissionsAsync()/UNUserNotificationCenter.requestAuthorization/ Android 13+POST_NOTIFICATIONS. If denied, keep the app fully functional and offer an unobtrusive Settings link in notification preferences. - Token lifecycle & multi-account isolation:
- Register the device token (Expo Push Token, FCM registration token or APNs token) with the backend after authentication, associating it with the current user ID, device ID and app locale.
- Subscribe to token rotation events (
addPushTokenListener/FirebaseMessaging.onTokenRefresh) and update the backend immediately. - Unregister / disassociate the push token on sign-out (and clear delivered notifications from the OS tray + reset the app icon badge count) so a shared device never displays private notifications after logout.
- Android 8+ Notification Channels: create explicit channels (
setNotificationChannelAsync/NotificationChannel) with clear names and importance (MAXfor urgent alerts,DEFAULTfor messages,LOWfor silent updates) before requesting a token or displaying a notification.
2. Handling all three app states without race conditions
| Delivery State | Required Behavior |
|---|---|
| 1. Foreground (App Open) | Configure foreground presentation (setNotificationHandler). Never hijack the screen with an automatic router.push while the user is typing; show an in-app toast/banner and invalidate/update the relevant query cache or unread badge. |
| 2. Background / Inactive Tap | Listen for notification response events (addNotificationResponseReceivedListener / onMessageOpenedApp) and navigate once the router is mounted. |
| 3. Cold Start (App Terminated) | Read the initial notification or launch URL (useLastNotificationResponse / getInitialMessage / getInitialURL), wait for auth state hydration and router readiness, and deduplicate by notification/message ID so hot reloads or re-renders do not navigate twice. |
3. Universal Links, Android App Links and input validation
- Prefer verified HTTPS links over custom schemes:
- iOS Universal Links: configure Associated Domains (
applinks:example.com) and.well-known/apple-app-site-association. - Android App Links: configure
<intent-filter android:autoVerify="true">withhttpsscheme and.well-known/assetlinks.json. - Use custom schemes (
myapp://) only as a fallback or for local development, as any app can claim an unverified custom scheme.
- iOS Universal Links: configure Associated Domains (
- Treat incoming URLs and notification
datapayloads as untrusted input:- In Expo Router, use
+native-intent.tsx(redirectSystemPath) wrapped intry/catchto normalize or reject malformed external URLs without crashing. - Whitelist allowed routes and validate parameter formats (UUID/slug); never pass raw deep-link params into SQL queries, file paths, WebView URLs or automatic state-mutating calls.
- Use OAuth PKCE with
ASWebAuthenticationSession/ Custom Tabs and Universal Links instead of query-string tokens on custom schemes.
- In Expo Router, use
4. Auth gate, deleted resources and back-stack synthesis
- Deferred post-login redirect: if a deep link or notification targets a protected route while signed out, stash the validated target path, route to sign-in, and redirect after login succeeds.
- Graceful
403/404screen state: if the linked item was deleted or belongs to another account, render a clear "Unavailable or access denied" state with a Home action. - Synthesize a back path: when a cold-start deep link opens a detail screen directly (
/orders/123), ensure Back navigates to the parent list or Home instead of exiting unexpectedly.
Before you finish
- Push tokens register on login, update on rotation, and unregister + clear tray/badge on logout.
- Android channels exist; foreground, background-tap and cold-start flows are deduplicated.
- Deep link URLs and notification payloads are validated as untrusted input with
try/catch. - Unauthenticated links defer until login; missing/
403items and back-stack navigation work.
Included files 2
LICENSE.txtSKILL.md
