Expo SDK
Push notifications for Expo applications with managed workflow support
PushBase Expo SDK
The PushBase Expo SDK will provide seamless push notification integration for Expo applications, supporting both managed and bare workflows with optimized configuration.
Overview
The PushBase Expo SDK provides a complete wrapper on top of expo-notifications to simplify permissions, token management, message handling, and local notifications for Expo apps. It supports:
- Expo push tokens (default) or native device tokens (APNs/FCM) via useNativeTokens
- Automatic initialization (configurable) and listeners setup
- Android notification channels
- Local notifications, badge count, and initial notification retrieval
- Typed configuration and event handlers
Expected Installation
npx expo install @pushbase/expoQuick Start
import { PushBaseExpo } from "@pushbase/expo";
import * as Notifications from "expo-notifications";
const pushBase = PushBaseExpo.getInstance({
projectId: "your-expo-project-id", // required for Expo push tokens
debug: __DEV__,
// autoInitialize: true (default)
});
// Optional: explicit init if you set autoInitialize: false
await pushBase.initialize();
// Request permissions and get token
const permissions = await pushBase.requestPermissions();
if (permissions.granted) {
const token = await pushBase.getToken();
console.log("Push token:", token); // { type: 'expo' | 'native', data, platform? }
}Listeners
// Foreground notifications
const unSubMessage = pushBase.onMessage((message) => {
console.log("Foreground message:", message);
});
// Background notifications
const unSubBg = pushBase.onBackgroundMessage((message) => {
console.log("Background message:", message);
});
// Notification taps/responses
const unSubResp = pushBase.onNotificationResponse((response) => {
console.log("Notification response:", response);
});
// Token refresh
const unSubToken = pushBase.onTokenRefresh((token) => {
console.log("Token refreshed:", token);
});
// Error handling
const unSubErr = pushBase.onError((error) => {
console.error("PushBaseExpo error:", error);
});Local Notifications and Badge
// Schedule local notification
const id = await pushBase.scheduleNotification({
content: { title: "Hello", body: "Welcome!" },
trigger: { type: "timeInterval", seconds: 2 },
});
// Cancel notifications
await pushBase.cancelNotification(id);
await pushBase.cancelAllNotifications();
// Badge count
await pushBase.setBadgeCount(3);
const current = await pushBase.getBadgeCount();Android Channel (optional)
await pushBase.createNotificationChannel({
id: "promos",
name: "Promotions",
importance: "HIGH",
});Native Tokens (optional)
const pb = PushBaseExpo.getInstance({
projectId: "your-expo-project-id",
useNativeTokens: true, // returns { type: 'native', data, platform }
});
const token = await pb.getToken();State and Utilities
const state = pushBase.getState();
const hasPerm = await pushBase.hasPermissions();
const initial = await pushBase.getInitialNotification();
// Cleanup
pushBase.destroy();Types and Utilities
import {
PushBaseExpoConfig,
ExpoPushMessage,
ExpoPermissionStatus,
ExpoSDKState,
ExpoScheduleOptions,
PushToken,
ExpoUtils, // sendPushNotifications, getPushReceipts, sendSingleNotification
} from "@pushbase/expo";- ExpoUtils provides helper functions for server-side operations:
sendPushNotifications(): Send notifications to multiple recipientsgetPushReceipts(): Retrieve delivery receipts for sent notificationssendSingleNotification(): Send a single notification to a specific device
Expected Configuration
app.json / app.config.js
{
"expo": {
"name": "Your App",
"plugins": [
[
"@pushbase/expo",
{
"mode": "development" // or "production"
}
]
],
"notification": {
"icon": "./assets/notification-icon.png",
"color": "#ffffff",
"androidMode": "default",
"androidCollapsedTitle": "#{unread_notifications} new interactions"
}
}
}Expected Usage
Basic Setup
import { PushBase } from "@pushbase/expo";
import * as Notifications from "expo-notifications";
// Configure notification behavior
Notifications.setNotificationHandler({
handleNotification: async () => ({
shouldShowAlert: true,
shouldPlaySound: false,
shouldSetBadge: false,
}),
});
// Initialize PushBase
const pushBase = PushBase.getInstance();
// Initialize with configuration
await pushBase.initialize({
// For managed workflow (uses Expo Push Notifications)
projectId: "your-expo-project-id",
// For bare workflow (uses FCM)
firebaseConfig: {
// Firebase config (optional, for bare workflow)
},
serverUrl: "https://your-server.com/api", // Optional
debug: __DEV__, // Enable debug in development
});Request Permissions
// Request notification permissions
const permissions = await pushBase.requestPermissions();
if (permissions.granted) {
console.log("Notifications enabled!");
// Get the push token
const token = await pushBase.getToken();
console.log("Push token:", token);
} else {
console.log("Notifications denied");
}Handle Notifications
// Listen for foreground notifications
pushBase.onMessage((message) => {
console.log("Foreground notification:", message);
// Show local notification if needed
Notifications.scheduleNotificationAsync({
content: {
title: message.notification?.title || "New Message",
body: message.notification?.body || "You have a new message",
data: message.data,
},
trigger: null, // Show immediately
});
});
// Listen for background notifications
pushBase.onBackgroundMessage((message) => {
console.log("Background notification:", message);
});
// Listen for notification taps
pushBase.onNotificationTap((notification) => {
console.log("Notification tapped:", notification);
// Navigate to specific screen based on notification data
});Topic Subscriptions
// Subscribe to topics
await pushBase.subscribeToTopic("announcements");
await pushBase.subscribeToTopic("user-updates");
// Unsubscribe from topics
await pushBase.unsubscribeFromTopic("announcements");Error Handling
// Listen for errors
pushBase.onError((error) => {
console.error("PushBase error:", error);
});
// Listen for token refresh
pushBase.onTokenRefresh((newToken) => {
console.log("Token refreshed:", newToken);
});Expo-Specific Features
Managed vs Bare Workflow
The SDK will automatically detect your workflow and use the appropriate push service:
// Managed Workflow
// Uses Expo Push Notifications automatically
const pushBase = PushBase.getInstance();
await pushBase.initialize({
projectId: "your-expo-project-id",
});
// Bare Workflow
// Uses Firebase Cloud Messaging
const pushBase = PushBase.getInstance();
await pushBase.initialize({
firebaseConfig: {
// Your Firebase config
},
});Development vs Production
// Automatic environment detection
const pushBase = PushBase.getInstance();
await pushBase.initialize({
projectId: "your-expo-project-id",
environment: __DEV__ ? "development" : "production", // Auto-detected
});EAS Build Integration
For EAS Build, the SDK will work seamlessly:
// eas.json
{
"build": {
"development": {
"developmentClient": true,
"distribution": "internal",
"env": {
"PUSHBASE_ENV": "development"
}
},
"production": {
"env": {
"PUSHBASE_ENV": "production"
}
}
}
}Expected Types
interface ExpoPushBaseConfig {
// For managed workflow
projectId?: string;
// For bare workflow
firebaseConfig?: {
apiKey: string;
authDomain: string;
projectId: string;
storageBucket: string;
messagingSenderId: string;
appId: string;
};
serverUrl?: string;
environment?: "development" | "production";
debug?: boolean;
}
interface ExpoPermissionStatus {
granted: boolean;
status: "granted" | "denied" | "undetermined";
canAskAgain: boolean;
settings: {
allowsAlert: boolean;
allowsBadge: boolean;
allowsSound: boolean;
allowsDisplayInNotificationCenter: boolean;
allowsDisplayInCarPlay: boolean;
allowsDisplayOnLockScreen: boolean;
};
}
interface ExpoPushMessage {
messageId: string;
data?: Record<string, any>;
notification?: {
title?: string;
body?: string;
sound?: boolean | string;
badge?: number;
categoryId?: string;
subtitle?: string;
};
from?: string;
sentTime?: number;
ttl?: number;
}Development Status
- 🚧 In Development: Core Expo integration
- 📋 Planned: Managed workflow implementation
- 📋 Planned: Bare workflow support
- 📋 Planned: EAS Build optimization
- 📋 Planned: TypeScript definitions
- 📋 Planned: Testing and documentation
Expo Compatibility
The SDK will support:
- Expo SDK 50+: Full feature support
- Managed Workflow: Expo Push Notifications
- Bare Workflow: Firebase Cloud Messaging
- EAS Build: Optimized build configuration
- Expo Development Client: Development testing
Get Notified
Want to be notified when the Expo SDK is ready?
- ⭐ Star our GitHub repository
- 📧 Join our mailing list
- 💬 Follow updates on Discord
Migration from Expo Notifications
When the Expo SDK is released, migrating from direct Expo Notifications will be simple:
Before (Direct Expo Notifications)
import * as Notifications from "expo-notifications";
import { registerForPushNotificationsAsync } from "./registerForPushNotifications";
// Manual setup
const token = await registerForPushNotificationsAsync();
// Manual listeners
Notifications.addNotificationReceivedListener((notification) => {
console.log("Notification received:", notification);
});
Notifications.addNotificationResponseReceivedListener((response) => {
console.log("Notification tapped:", response);
});After (PushBase Expo SDK)
import { PushBase } from "@pushbase/expo";
const pushBase = PushBase.getInstance();
await pushBase.initialize({ projectId: "your-project-id" });
// Automatic setup
const permissions = await pushBase.requestPermissions();
const token = await pushBase.getToken();
// Simplified listeners
pushBase.onMessage((message) => {
console.log("Message received:", message);
});
pushBase.onNotificationTap((notification) => {
console.log("Notification tapped:", notification);
});Related Documentation
- React Native SDK - Currently available
- Web SDK - Coming soon
- API Reference - Complete API documentation