feat: Enable Firebase Cloud Messaging for iOS with platform-specific configurations and update Android build settings.

This commit is contained in:
pradeepkumar
2026-03-09 06:07:36 +05:30
parent 0102617dc7
commit f1003be757
5 changed files with 58 additions and 31 deletions

View File

@@ -12,6 +12,7 @@ android {
ndkVersion = flutter.ndkVersion
compileOptions {
isCoreLibraryDesugaringEnabled = true
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
@@ -55,6 +56,10 @@ android {
}
}
dependencies {
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.4")
}
flutter {
source = "../.."
}

View File

@@ -1,5 +1,6 @@
import Flutter
import UIKit
import FirebaseMessaging
@main
@objc class AppDelegate: FlutterAppDelegate {
@@ -10,4 +11,13 @@ import UIKit
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
// Forward APNs token to Firebase for FCM
override func application(
_ application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data
) {
Messaging.messaging().apnsToken = deviceToken
super.application(application, didRegisterForRemoteNotificationsWithDeviceToken: deviceToken)
}
}

View File

@@ -1,3 +1,5 @@
import 'dart:io';
import 'package:firebase_core/firebase_core.dart';
import 'package:real_estate_mobile/config/app_config.dart';
@@ -5,44 +7,68 @@ class FirebaseConfig {
static FirebaseOptions get currentOptions {
switch (AppConfig.flavor) {
case Flavor.dev:
return _dev;
return Platform.isIOS ? _devIos : _devAndroid;
case Flavor.demo:
return _demo;
return Platform.isIOS ? _demoIos : _demoAndroid;
case Flavor.local:
return _local;
return Platform.isIOS ? _localIos : _localAndroid;
}
}
// ── Dev ──
static const _dev = FirebaseOptions(
apiKey: 'AIzaSyAwb_9fc7n9gbN_IQqWeYRkHSSykzVHCyc', // Android
// ── Dev (Android) ──
static const _devAndroid = FirebaseOptions(
apiKey: 'AIzaSyAwb_9fc7n9gbN_IQqWeYRkHSSykzVHCyc',
appId: '1:703616926518:android:4342b796fbabb690fca997',
messagingSenderId: '703616926518',
projectId: 'real-estate-2d71e',
storageBucket: 'real-estate-2d71e.firebasestorage.app',
iosBundleId: 'com.requestn.realEstateMobile.dev',
iosClientId: null,
);
// ── Demo ──
static const _demo = FirebaseOptions(
// ── Dev (iOS) ──
static const _devIos = FirebaseOptions(
apiKey: 'AIzaSyD67KPio-70XW_yGjrRUyq9ejdZoZA1rmE',
appId: '1:703616926518:ios:301cac94994fbdc3fca997',
messagingSenderId: '703616926518',
projectId: 'real-estate-2d71e',
storageBucket: 'real-estate-2d71e.firebasestorage.app',
iosBundleId: 'com.requestn.realEstateMobile.dev',
);
// ── Demo (Android) ──
static const _demoAndroid = FirebaseOptions(
apiKey: 'AIzaSyAwb_9fc7n9gbN_IQqWeYRkHSSykzVHCyc',
appId: '1:703616926518:android:270639d6887d2cb4fca997',
messagingSenderId: '703616926518',
projectId: 'real-estate-2d71e',
storageBucket: 'real-estate-2d71e.firebasestorage.app',
iosBundleId: 'com.requestn.realEstateMobile.demo',
iosClientId: null,
);
// ── Local ──
static const _local = FirebaseOptions(
// ── Demo (iOS) ──
static const _demoIos = FirebaseOptions(
apiKey: 'AIzaSyD67KPio-70XW_yGjrRUyq9ejdZoZA1rmE',
appId: '1:703616926518:ios:2d2f7d163774722dfca997',
messagingSenderId: '703616926518',
projectId: 'real-estate-2d71e',
storageBucket: 'real-estate-2d71e.firebasestorage.app',
iosBundleId: 'com.requestn.realEstateMobile.demo',
);
// ── Local (Android) ──
static const _localAndroid = FirebaseOptions(
apiKey: 'AIzaSyAwb_9fc7n9gbN_IQqWeYRkHSSykzVHCyc',
appId: '1:703616926518:android:2eb242f07b174c25fca997',
messagingSenderId: '703616926518',
projectId: 'real-estate-2d71e',
storageBucket: 'real-estate-2d71e.firebasestorage.app',
);
// ── Local (iOS) ──
static const _localIos = FirebaseOptions(
apiKey: 'AIzaSyD67KPio-70XW_yGjrRUyq9ejdZoZA1rmE',
appId: '1:703616926518:ios:15652d299f9f2d7ffca997',
messagingSenderId: '703616926518',
projectId: 'real-estate-2d71e',
storageBucket: 'real-estate-2d71e.firebasestorage.app',
iosBundleId: 'com.requestn.realEstateMobile.local',
iosClientId: null,
);
}

View File

@@ -30,16 +30,8 @@ class PushNotificationService {
void Function(String? actionUrl)? onNotificationTap;
/// Initialize Firebase Messaging and local notifications.
/// Skipped on iOS until Firebase iOS app is configured.
Future<void> initialize() async {
if (_initialized) return;
// Skip on iOS — no Firebase iOS app configured yet
if (Platform.isIOS) {
debugPrint('[FCM] Skipped on iOS — no Firebase iOS app configured');
return;
}
_initialized = true;
_messaging = FirebaseMessaging.instance;
@@ -188,7 +180,7 @@ class PushNotificationService {
/// Unregister FCM token from backend (call on logout).
Future<void> unregister() async {
if (Platform.isIOS || _currentToken == null) return;
if (_currentToken == null) return;
try {
await _repo.removeFcmToken(_currentToken!);
debugPrint('[FCM] Token unregistered from backend');
@@ -200,7 +192,6 @@ class PushNotificationService {
/// Re-register token after login.
Future<void> registerAfterLogin() async {
if (Platform.isIOS) return;
await _getAndRegisterToken();
}
}

View File

@@ -10,12 +10,7 @@ Future<void> mainCommon(Flavor flavor) async {
WidgetsFlutterBinding.ensureInitialized();
await AppConfig.init(flavor);
// Initialize Firebase — iOS may fail if no iOS app configured in Firebase Console
try {
await Firebase.initializeApp(options: FirebaseConfig.currentOptions);
} catch (e) {
debugPrint('[Firebase] Init failed (expected on iOS without config): $e'); // ignore: avoid_print
}
await Firebase.initializeApp(options: FirebaseConfig.currentOptions);
runApp(const ProviderScope(child: MyApp()));
}