pushfire_sdk 0.1.3
pushfire_sdk: ^0.1.3 copied to clipboard
A lightweight push notification tracking SDK for Firebase.
PushFire Flutter SDK #
A Flutter SDK for integrating with the PushFire push notification service. This SDK provides easy-to-use APIs for device registration, subscriber management, and tag operations.
Features #
- π Automatic Device Registration: Seamlessly registers devices with FCM tokens
- π€ Subscriber Management: Login, update, and logout subscribers
- π·οΈ Tag Management: Add, update, and remove subscriber tags
- π± Cross-Platform: Works on both iOS and Android
- π§ Configurable: Customizable API endpoints and settings
- π Logging: Built-in logging for debugging
- π Event Streams: Real-time updates via streams
- π‘οΈ Error Handling: Comprehensive exception handling
Installation #
Add this to your package's pubspec.yaml
file:
dependencies:
pushfire_sdk: ^1.0.0
Then run:
flutter pub get
Setup #
1. Firebase Setup #
This SDK uses Firebase Cloud Messaging (FCM) for push notifications. You need to:
- Create a Firebase project at Firebase Console
- Add your Android/iOS app to the project
- Install FlutterFire CLI and configure Firebase:
dart pub global activate flutterfire_cli flutterfire configure
- This will generate
firebase_options.dart
file with your Firebase configuration - Download and add the configuration files:
google-services.json
for Android (place inandroid/app/
)GoogleService-Info.plist
for iOS (place inios/Runner/
)
- Follow the FlutterFire setup guide for platform-specific configuration
2. Platform Configuration #
Android
Add the following to your android/app/build.gradle
:
dependencies {
implementation 'com.google.firebase:firebase-messaging:23.0.0'
}
iOS
Enable push notifications in your iOS project:
- Open
ios/Runner.xcworkspace
in Xcode - Select your project target
- Go to "Signing & Capabilities"
- Add "Push Notifications" capability
- Add "Background Modes" capability and enable "Background processing" and "Remote notifications"
Usage #
1. Initialize the SDK #
Initialize the SDK in your app's main()
function:
import 'package:pushfire_sdk/pushfire_sdk.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// Initialize PushFire SDK
await PushFireSDK.initialize(
PushFireConfig(
apiKey: 'your-api-key-here',
baseUrl: 'https://api.pushfire.com', // Optional: defaults to production
enableLogging: true, // Optional: enable for debugging
timeoutSeconds: 30, // Optional: request timeout
authProvider: AuthProvider.firebase, // Optional: authentication provider
),
);
runApp(MyApp());
}
2. Authentication Provider Integration #
The PushFire SDK supports automatic subscriber management through authentication providers. When configured, the SDK automatically handles subscriber login/logout based on the user's authentication state.
Supported Authentication Providers
- Firebase Authentication (
AuthProvider.firebase
) - Supabase Authentication (
AuthProvider.supabase
) - None (
AuthProvider.none
) - Default, manual subscriber management
Firebase Authentication Integration
await PushFireSDK.initialize(
PushFireConfig(
apiKey: 'your-api-key-here',
authProvider: AuthProvider.firebase,
),
);
When Firebase Authentication is configured:
- The SDK automatically listens for
authStateChanges()
fromFirebaseAuth.instance
- When a user signs in, the SDK automatically calls
loginSubscriber()
with:externalId
: User's UIDemail
: User's email (if available)name
: User's display name or 'Guest' if not availablephone
: User's phone number (if available)
- When a user signs out, the SDK automatically calls
logoutSubscriber()
Supabase Authentication Integration
await PushFireSDK.initialize(
PushFireConfig(
apiKey: 'your-api-key-here',
authProvider: AuthProvider.supabase,
),
);
When Supabase Authentication is configured:
- The SDK automatically listens for
onAuthStateChange
events fromSupabase.instance.client.auth
- When a user signs in (
AuthChangeEvent.signedIn
), the SDK automatically callsloginSubscriber()
with:externalId
: User's IDemail
: User's email (if available)name
: User's full_name from metadata or 'Guest' if not availablephone
: User's phone number (if available)
- When a user signs out (
AuthChangeEvent.signedOut
), the SDK automatically callslogoutSubscriber()
Manual Subscriber Management
await PushFireSDK.initialize(
PushFireConfig(
apiKey: 'your-api-key-here',
authProvider: AuthProvider.none, // Default
),
);
When no authentication provider is configured, you must manually manage subscribers using the SDK methods.
3. Subscriber Management #
Login/Register a Subscriber
try {
final subscriber = await PushFireSDK.instance.loginSubscriber(
externalId: 'user123', // Your user ID
name: 'John Doe',
email: 'john@example.com',
phone: '+1234567890',
);
print('Subscriber logged in: ${subscriber.id}');
} catch (e) {
print('Login failed: $e');
}
Update Subscriber
try {
final updatedSubscriber = await PushFireSDK.instance.updateSubscriber(
name: 'John Smith',
email: 'johnsmith@example.com',
);
print('Subscriber updated: ${updatedSubscriber.name}');
} catch (e) {
print('Update failed: $e');
}
Logout Subscriber
try {
await PushFireSDK.instance.logoutSubscriber();
print('Subscriber logged out');
} catch (e) {
print('Logout failed: $e');
}
Check Subscriber Status
// Check if subscriber is logged in
final isLoggedIn = await PushFireSDK.instance.isSubscriberLoggedIn();
// Get current subscriber
final subscriber = await PushFireSDK.instance.getCurrentSubscriber();
if (subscriber != null) {
print('Current subscriber: ${subscriber.name}');
}
3. Tag Management #
Add Tags
// Add single tag
try {
final tag = await PushFireSDK.instance.addTag('user_type', 'premium');
print('Tag added: ${tag.tagId} = ${tag.value}');
} catch (e) {
print('Failed to add tag: $e');
}
// Add multiple tags
try {
final tags = await PushFireSDK.instance.addTags({
'user_type': 'premium',
'subscription_plan': 'yearly',
'region': 'us-west',
});
print('Added ${tags.length} tags');
} catch (e) {
print('Failed to add tags: $e');
}
Update Tags
// Update single tag
try {
final tag = await PushFireSDK.instance.updateTag('user_type', 'enterprise');
print('Tag updated: ${tag.tagId} = ${tag.value}');
} catch (e) {
print('Failed to update tag: $e');
}
// Update multiple tags
try {
final tags = await PushFireSDK.instance.updateTags({
'user_type': 'enterprise',
'subscription_plan': 'monthly',
});
print('Updated ${tags.length} tags');
} catch (e) {
print('Failed to update tags: $e');
}
Remove Tags
// Remove single tag
try {
await PushFireSDK.instance.removeTag('user_type');
print('Tag removed');
} catch (e) {
print('Failed to remove tag: $e');
}
// Remove multiple tags
try {
await PushFireSDK.instance.removeTags(['user_type', 'region']);
print('Tags removed');
} catch (e) {
print('Failed to remove tags: $e');
}
4. Workflow Execution #
Execute automated workflows for targeted push notifications:
Create Immediate Workflow
// Execute workflow immediately for specific subscribers
try {
await PushFireSDK.instance.createImmediateWorkflowForSubscribers(
workflowId: 'welcome-series',
subscriberIds: ['sub1', 'sub2', 'sub3'],
);
print('Workflow executed for subscribers');
} catch (e) {
print('Workflow execution failed: $e');
}
// Execute workflow immediately for segments
try {
await PushFireSDK.instance.createImmediateWorkflowForSegments(
workflowId: 'promotion-campaign',
segmentIds: ['premium-users', 'active-users'],
);
print('Workflow executed for segments');
} catch (e) {
print('Workflow execution failed: $e');
}
Create Scheduled Workflow
// Schedule workflow for future execution
final scheduledFor = DateTime.now().add(Duration(hours: 2));
try {
await PushFireSDK.instance.createScheduledWorkflowForSubscribers(
workflowId: 'reminder-series',
subscriberIds: ['sub1', 'sub2'],
scheduledFor: scheduledFor,
);
print('Workflow scheduled for subscribers');
} catch (e) {
print('Workflow scheduling failed: $e');
}
try {
await PushFireSDK.instance.createScheduledWorkflowForSegments(
workflowId: 'weekly-digest',
segmentIds: ['newsletter-subscribers'],
scheduledFor: scheduledFor,
);
print('Workflow scheduled for segments');
} catch (e) {
print('Workflow scheduling failed: $e');
}
Advanced Workflow Execution
// Create custom workflow execution request
final request = WorkflowExecutionRequest(
workflowId: 'custom-workflow',
type: WorkflowExecutionType.scheduled,
scheduledFor: DateTime.now().add(Duration(days: 1)),
target: WorkflowTarget(
type: WorkflowTargetType.subscribers,
values: ['sub1', 'sub2'],
),
);
try {
await PushFireSDK.instance.createWorkflowExecution(request);
print('Custom workflow execution created');
} catch (e) {
print('Custom workflow execution failed: $e');
}
5. Device Information #
// Get current device
final device = PushFireSDK.instance.currentDevice;
if (device != null) {
print('Device ID: ${device.id}');
print('FCM Token: ${device.fcmToken}');
print('OS: ${device.os} ${device.osVersion}');
}
// Get device ID
final deviceId = await PushFireSDK.instance.getDeviceId();
print('Device ID: $deviceId');
// Get subscriber ID
final subscriberId = await PushFireSDK.instance.getSubscriberId();
print('Subscriber ID: $subscriberId');
6. Event Streams #
Listen to real-time events:
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
late StreamSubscription _deviceSubscription;
late StreamSubscription _subscriberSubscription;
late StreamSubscription _fcmSubscription;
@override
void initState() {
super.initState();
_setupEventListeners();
}
void _setupEventListeners() {
// Listen to device registration events
_deviceSubscription = PushFireSDK.instance.onDeviceRegistered.listen(
(device) {
print('Device registered: ${device.id}');
},
);
// Listen to subscriber login events
_subscriberSubscription = PushFireSDK.instance.onSubscriberLoggedIn.listen(
(subscriber) {
print('Subscriber logged in: ${subscriber.name}');
},
);
// Listen to FCM token refresh events
_fcmSubscription = PushFireSDK.instance.onFcmTokenRefresh.listen(
(token) {
print('FCM token refreshed: $token');
},
);
}
@override
void dispose() {
_deviceSubscription.cancel();
_subscriberSubscription.cancel();
_fcmSubscription.cancel();
super.dispose();
}
// ... rest of your widget
}
7. Error Handling #
The SDK provides specific exception types for different error scenarios:
try {
await PushFireSDK.instance.loginSubscriber(externalId: 'user123');
} on PushFireNotInitializedException {
print('SDK not initialized');
} on PushFireSubscriberException catch (e) {
print('Subscriber error: ${e.message}');
} on PushFireApiException catch (e) {
print('API error: ${e.message} (${e.statusCode})');
} on PushFireNetworkException catch (e) {
print('Network error: ${e.message}');
} catch (e) {
print('Unknown error: $e');
}
8. Advanced Usage #
Reset SDK
// Reset SDK and clear all data
await PushFireSDK.instance.reset();
Dispose SDK
// Dispose SDK resources (call when app is shutting down)
PushFireSDK.dispose();
Check Initialization Status
if (PushFireSDK.isInitialized) {
print('SDK is ready to use');
} else {
print('SDK needs to be initialized');
}
Configuration Options #
PushFireConfig #
Parameter | Type | Required | Default | Description |
---|---|---|---|---|
apiKey |
String | Yes | - | Your PushFire API key |
baseUrl |
String | No | https://jojnoebcqoqjlshwzmjm.supabase.co/functions/v1/ |
API base URL |
enableLogging |
bool | No | false |
Enable debug logging |
timeoutSeconds |
int | No | 30 |
Request timeout in seconds |
authProvider |
AuthProvider | No | AuthProvider.none |
Authentication provider for automatic subscriber management |
requestNotificationPermission |
bool | No | true |
Automatically request notification permissions during SDK initialization |
Notification Permissions #
The PushFire SDK provides flexible notification permission handling to accommodate different app requirements and user experience strategies.
Automatic Permission Request #
By default, the SDK automatically requests notification permissions during initialization:
await PushFireSDK.initialize(
config: PushFireConfig(
apiKey: 'your-api-key',
requestNotificationPermission: true, // Default behavior
),
);
Manual Permission Request #
For apps that prefer to request permissions at a more appropriate time in the user journey:
// Initialize without automatic permission request
await PushFireSDK.initialize(
config: PushFireConfig(
apiKey: 'your-api-key',
requestNotificationPermission: false,
),
);
// Later, when appropriate for your UX
bool permissionGranted = await PushFireSDK.requestNotificationPermission();
if (permissionGranted) {
print('Notification permission granted');
} else {
print('Notification permission denied');
}
Platform-Specific Behavior #
The SDK handles platform-specific permission requirements:
- iOS: Uses Firebase Messaging's permission system with appropriate settings for alerts, badges, and sounds
- Android: Handles runtime permissions for Android 13+ (API level 33+) and gracefully handles older versions
- Web: Requests browser notification permissions through Firebase Messaging
Best Practices for Permissions #
- Context Matters: Request permissions when users understand the value of notifications
- Graceful Degradation: Your app should work even if permissions are denied
- Re-request Strategy: Use
requestNotificationPermission()
to re-request if initially denied - User Education: Explain the benefits before requesting permissions
Permission Status Handling #
The SDK automatically:
- Logs permission request outcomes for debugging
- Continues device registration even if permissions are denied
- Supports manual permission grants through device settings
- Re-registers the device when permissions are granted via manual request
Error Types #
PushFireException
- Base exception classPushFireApiException
- API-related errorsPushFireNotInitializedException
- SDK not initializedPushFireConfigurationException
- Configuration errorsPushFireDeviceException
- Device registration errorsPushFireSubscriberException
- Subscriber operation errorsPushFireTagException
- Tag operation errorsPushFireNetworkException
- Network connectivity errors
Best Practices #
- Initialize Early: Call
PushFireSDK.initialize()
as early as possible in your app lifecycle - Handle Errors: Always wrap SDK calls in try-catch blocks
- Check Status: Use
isSubscriberLoggedIn()
before performing subscriber operations - Listen to Events: Use event streams to react to SDK state changes
- Dispose Resources: Call
PushFireSDK.dispose()
when your app shuts down - Enable Logging: Use
enableLogging: true
during development for debugging
Troubleshooting #
Common Issues #
-
SDK Not Initialized
- Ensure you call
PushFireSDK.initialize()
before using any other methods - Check that initialization completes successfully
- Ensure you call
-
Device Registration Fails
- Verify Firebase setup is correct
- Check that FCM is properly configured
- Ensure device has internet connectivity
-
API Errors
- Verify your API key is correct
- Check that the base URL is accessible
- Ensure your PushFire account is active
-
Subscriber Operations Fail
- Make sure a subscriber is logged in before performing operations
- Verify the external ID is valid
Debug Logging #
Enable logging to see detailed information about SDK operations:
await PushFireSDK.initialize(
PushFireConfig(
apiKey: 'your-api-key',
enableLogging: true, // Enable this for debugging
),
);
Support #
For issues and questions:
- Check the troubleshooting section
- Review the API documentation
- Contact support at support@pushfire.com
License #
This project is licensed under the MIT License - see the LICENSE file for details.