Files
Kordant/docs/MOBILE_PUSH_INTEGRATION.md

390 lines
11 KiB
Markdown

# Push Notifications - Mobile App Quick Start
This guide helps you integrate push notifications into the ShieldAI React Native mobile app.
## Prerequisites
Before starting, ensure:
- ✅ Backend push notification infrastructure is deployed
- ✅ Firebase project is set up (for Android)
- ✅ Apple Developer account is active (for iOS)
- ✅ Environment variables are configured on the backend
## Step 1: Install Dependencies
```bash
npm install @react-native-firebase/app @react-native-firebase/messaging
```
## Step 2: Android Setup
### 2.1 Add Firebase to Android Project
1. Go to [Firebase Console](https://console.firebase.google.com)
2. Select your ShieldAI project
3. Add Android app with package name: `com.shieldai.mobile`
4. Download `google-services.json`
5. Place it in `android/app/google-services.json`
### 2.2 Update Build Configuration
In `android/build.gradle`:
```gradle
buildscript {
dependencies {
classpath 'com.google.gms:google-services:4.4.0'
}
}
```
In `android/app/build.gradle`:
```gradle
apply plugin: 'com.google.gms.google-services'
```
### 2.3 Request Permissions
In `AndroidManifest.xml`:
```xml
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.VIBRATE" />
```
## Step 3: iOS Setup
### 3.1 Enable Push Notifications
1. Open Xcode project
2. Select your app target
3. Go to "Signing & Capabilities"
4. Click "+ Capability"
5. Add "Push Notifications"
6. Add "Background Modes" and check "Remote notifications"
### 3.2 Configure Firebase
1. Download `GoogleService-Info.plist` from Firebase Console
2. Add it to your Xcode project (drag to project folder)
3. Ensure "Copy items if needed" is checked
### 3.3 Add Import in AppDelegate.swift
```swift
import FirebaseMessaging
import UserNotifications
@main
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
Messaging.messaging().delegate = self
return true
}
// Request permission
func requestAuthorization() {
UNUserNotificationCenter.current().delegate = self
let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
UNUserNotificationCenter.current().requestAuthorization(
options: authOptions,
completionHandler: { granted, error in
if granted {
DispatchQueue.main.async {
UIApplication.shared.registerForRemoteNotifications()
}
}
}
)
}
// Handle token refresh
func messaging(_ messaging: Messaging, didRefreshRegistrationToken fcmToken: String) {
print("FCM token refreshed: \(fcmToken)")
// Send new token to backend
registerDeviceToken(fcmToken)
}
// Handle foreground notifications
func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler:
@escaping (UNNotificationPresentationOptions) -> Void) {
let userInfo = notification.request.content.userInfo
print("Foreground notification: \(userInfo)")
completionHandler([.banner, .sound, .badge])
}
// Handle notification tap
func userNotificationCenter(_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: @escaping () -> Void) {
let userInfo = response.notification.request.content.userInfo
print("Notification tapped: \(userInfo)")
completionHandler()
}
}
extension AppDelegate: MessagingDelegate {
func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) {
print("FCM token received: \(fcmToken ?? "none")")
if let token = fcmToken {
registerDeviceToken(token)
}
}
}
// Helper function to register with backend
func registerDeviceToken(_ token: String) {
// Call your API to register the device
// POST /api/v1/devices/register
// Body: { userId, platform: "ios", token, deviceType: "mobile" }
}
```
## Step 4: React Native Integration
### 4.1 Create Notification Service
Create `src/services/NotificationService.ts`:
```typescript
import messaging from '@react-native-firebase/messaging';
import AsyncStorage from '@react-native-async-storage/async-storage';
import axios from 'axios';
const API_BASE_URL = 'https://api.shieldai.com/api/v1';
export class NotificationService {
private static instance: NotificationService;
private userId: string | null = null;
private constructor() {}
static getInstance(): NotificationService {
if (!NotificationService.instance) {
NotificationService.instance = new NotificationService();
}
return NotificationService.instance;
}
setUserId(userId: string) {
this.userId = userId;
}
async requestPermission(): Promise<boolean> {
try {
const authStatus = await messaging().requestPermission();
const enabled =
authStatus === messaging.AuthorizationStatus.AUTHORIZED ||
authStatus === messaging.AuthorizationStatus.PROVISIONAL;
if (enabled) {
console.log('Push notification permission granted');
await this.registerDevice();
return true;
}
return false;
} catch (error) {
console.error('Failed to request permission:', error);
return false;
}
}
async registerDevice(): Promise<void> {
if (!this.userId) {
console.warn('User ID not set, cannot register device');
return;
}
try {
const token = await messaging().getToken();
const platform = Platform.OS === 'ios' ? 'ios' : 'android';
const response = await axios.post(`${API_BASE_URL}/devices/register`, {
userId: this.userId,
platform,
token,
deviceType: 'mobile',
appName: 'ShieldAI Mobile',
appVersion: '1.0.0',
});
console.log('Device registered:', response.data);
} catch (error) {
console.error('Failed to register device:', error);
}
}
setupListeners() {
// Foreground messages
messaging().onMessage(async (remoteMessage) => {
console.log('Foreground message received:', remoteMessage);
// Show local notification
this.showLocalNotification(remoteMessage);
});
// Background messages
messaging().setBackgroundMessageHandler(async (remoteMessage) => {
console.log('Background message received:', remoteMessage);
});
// Notification opened
messaging().onNotificationOpenedApp((remoteMessage) => {
console.log('Notification opened app:', remoteMessage);
// Navigate to relevant screen
this.handleNotificationTap(remoteMessage);
});
// Check if app was opened from notification
messaging()
.getInitialNotification()
.then((remoteMessage) => {
if (remoteMessage) {
console.log('App opened from notification:', remoteMessage);
this.handleNotificationTap(remoteMessage);
}
});
}
private showLocalNotification(message: any) {
// Use react-native-push-notification or similar
console.log('Show notification:', message.notification?.title);
}
private handleNotificationTap(message: any) {
// Navigate to relevant screen based on notification data
const { alertId, type } = message.data || {};
if (alertId) {
// Navigate to alert detail
console.log('Navigate to alert:', alertId);
}
}
async deregisterDevice(): Promise<void> {
if (!this.userId) return;
try {
const token = await messaging().getToken();
await axios.post(`${API_BASE_URL}/devices/deregister`, {
token,
userId: this.userId,
});
} catch (error) {
console.error('Failed to deregister device:', error);
}
}
}
```
### 4.2 Initialize in App Component
```typescript
// App.tsx
import React, { useEffect } from 'react';
import { NotificationService } from './src/services/NotificationService';
const notificationService = NotificationService.getInstance();
function App() {
useEffect(() => {
// Initialize push notifications
notificationService.setupListeners();
}, []);
// When user logs in
const handleLogin = async (userId: string) => {
notificationService.setUserId(userId);
await notificationService.requestPermission();
};
// When user logs out
const handleLogout = async () => {
await notificationService.deregisterDevice();
notificationService.setUserId('');
};
return (
// Your app components
);
}
```
## Step 5: Testing
### Android Emulator
1. Start Android emulator with Google Play Services
2. Install and run app
3. Trigger a test notification from backend
4. Check notification appears
### iOS Device (Required)
iOS Simulator does not support push notifications. Use a real device.
### Backend Test
```bash
# Test notification API
curl -X POST https://api.shieldai.com/api/v1/notifications/send \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"userId": "user-uuid",
"channel": "push",
"subject": "Test Alert",
"body": "This is a test notification from ShieldAI",
"priority": "high",
"metadata": {
"alertId": "alert-uuid",
"type": "darkweb_exposure"
}
}'
```
## Troubleshooting
### Android Issues
**Problem**: Token not received
- Check `google-services.json` is in correct location
- Verify Firebase project ID matches
- Check internet connection on emulator
**Problem**: Notifications not showing
- Ensure notification permissions granted
- Check battery optimization settings
- Verify notification channel is created
### iOS Issues
**Problem**: Token not received
- Verify Push Notifications capability is enabled
- Check APNs key configuration in backend
- Ensure device is not in development mode if using production certs
**Problem**: Notifications not showing
- Check notification permissions granted
- Verify APNs configuration on backend
- Ensure proper certificate/key is used
## Next Steps
1. ✅ Set up Firebase project
2. ✅ Configure APNs on Apple Developer Portal
3. ✅ Implement notification handling in app
4. ✅ Test on Android device/emulator
5. ✅ Test on iOS device
6. ✅ Integrate with DarkWatch and SpamShield alerts
7. ✅ Add notification preferences UI
8. ✅ Implement deep linking from notifications
## Resources
- [Firebase Cloud Messaging Docs](https://firebase.google.com/docs/cloud-messaging)
- [React Native Firebase Messaging](https://rnfirebase.io/messaging/usage)
- [Apple Push Notification Service](https://developer.apple.com/documentation/usernotifications)