Files
worker/lib/core/services/onesignal_service.dart
Phuoc Nguyen e3632d4445 add sentry
2025-12-11 13:44:26 +07:00

169 lines
5.8 KiB
Dart

import 'package:flutter/foundation.dart';
import 'package:onesignal_flutter/onesignal_flutter.dart';
/// OneSignal service for managing push notifications and external user ID.
///
/// This service handles:
/// - Initializing OneSignal SDK
/// - Setting external user ID after login (using phone number)
/// - Restoring external user ID on app startup
/// - Clearing external user ID on logout
///
/// Usage:
/// ```dart
/// // Initialize in main.dart
/// await OneSignalService.init(appId: 'your-app-id');
///
/// // After successful login
/// await OneSignalService.login(phoneNumber);
///
/// // On logout
/// await OneSignalService.logout();
/// ```
class OneSignalService {
OneSignalService._();
/// OneSignal App ID - Replace with your actual App ID from OneSignal dashboard
static const String _defaultAppId = '778ca22d-c719-4ec8-86cb-a6b911166066';
/// Initialize OneSignal SDK
///
/// Must be called before using any other OneSignal methods.
/// Sets up push subscription observers and requests notification permission.
///
/// [appId] - Optional App ID override (uses default if not provided)
/// [requestPermission] - Whether to request notification permission (default: true)
static Future<void> init({
String? appId,
bool requestPermission = true,
}) async {
try {
// Set debug log level (verbose in debug, none in release)
OneSignal.Debug.setLogLevel(kDebugMode ? OSLogLevel.verbose : OSLogLevel.none);
// Initialize with App ID
OneSignal.initialize(appId ?? _defaultAppId);
debugPrint('🔔 OneSignal initialized');
// Add push subscription observer to track subscription state changes
OneSignal.User.pushSubscription.addObserver((state) {
debugPrint('🔔 Push subscription state changed:');
debugPrint(' Previous - optedIn: ${state.previous.optedIn}, id: ${state.previous.id}');
debugPrint(' Current - optedIn: ${state.current.optedIn}, id: ${state.current.id}');
debugPrint(' Subscription ID: ${state.current.id}');
debugPrint(' Push Token: ${state.current.token}');
if (state.current.id != null) {
debugPrint('🔔 ✅ Device successfully subscribed!');
}
});
// Add notification permission observer
OneSignal.Notifications.addPermissionObserver((isGranted) {
debugPrint('🔔 Notification permission changed: $isGranted');
});
// Request permission if enabled
if (requestPermission) {
final accepted = await OneSignal.Notifications.requestPermission(true);
debugPrint('🔔 Permission request result: $accepted');
}
// Give OneSignal SDK time to complete initialization and server registration
await Future<void>.delayed(const Duration(seconds: 2));
// Log current subscription status
_logSubscriptionStatus();
} catch (e) {
debugPrint('🔔 OneSignal error: Failed to initialize - $e');
}
}
/// Log current subscription status for debugging
static void _logSubscriptionStatus() {
final optedIn = OneSignal.User.pushSubscription.optedIn;
final id = OneSignal.User.pushSubscription.id;
final token = OneSignal.User.pushSubscription.token;
debugPrint('🔔 Current subscription status:');
debugPrint(' Opted In: $optedIn');
debugPrint(' Subscription ID: $id');
debugPrint(' Push Token: $token');
if (id == null) {
debugPrint('🔔 ⚠️ Subscription ID is null - check device connectivity and OneSignal app ID');
}
}
/// Login user to OneSignal by setting external user ID.
///
/// This associates the device with the user's phone number,
/// allowing targeted push notifications to specific users.
///
/// [phoneNumber] - The user's phone number (used as external ID)
static Future<void> login(String phoneNumber) async {
try {
// Set external user ID for targeting
await OneSignal.login(phoneNumber);
debugPrint('🔔 OneSignal: login - external_id set to $phoneNumber');
} catch (e) {
debugPrint('🔔 OneSignal error: Failed to set external user ID - $e');
}
}
/// Logout user from OneSignal by removing external user ID.
///
/// This disassociates the device from the user,
/// so notifications won't be sent to this specific user anymore.
static Future<void> logout() async {
try {
await OneSignal.logout();
debugPrint('🔔 OneSignal: logout - external_id cleared');
} catch (e) {
debugPrint('🔔 OneSignal error: Failed to clear external user ID - $e');
}
}
/// Add a tag to the user for segmentation.
///
/// Tags can be used to segment users for targeted notifications.
/// Example: tier = "diamond", role = "contractor"
static Future<void> setTag(String key, String value) async {
try {
await OneSignal.User.addTagWithKey(key, value);
debugPrint('🔔 OneSignal: tag set - $key: $value');
} catch (e) {
debugPrint('🔔 OneSignal error: Failed to set tag - $e');
}
}
/// Add multiple tags at once.
static Future<void> setTags(Map<String, String> tags) async {
try {
await OneSignal.User.addTags(tags);
debugPrint('🔔 OneSignal: tags set - $tags');
} catch (e) {
debugPrint('🔔 OneSignal error: Failed to set tags - $e');
}
}
/// Remove a tag from the user.
static Future<void> removeTag(String key) async {
try {
await OneSignal.User.removeTag(key);
debugPrint('🔔 OneSignal: tag removed - $key');
} catch (e) {
debugPrint('🔔 OneSignal error: Failed to remove tag - $e');
}
}
/// Get the OneSignal subscription ID (player ID).
///
/// This is the device-specific ID used by OneSignal.
static String? get subscriptionId => OneSignal.User.pushSubscription.id;
/// Check if push notifications are enabled.
static bool get isPushEnabled =>
OneSignal.User.pushSubscription.optedIn ?? false;
}