feat: Enable Firebase Cloud Messaging for iOS with platform-specific configurations and update Android build settings.
This commit is contained in:
@@ -12,6 +12,7 @@ android {
|
|||||||
ndkVersion = flutter.ndkVersion
|
ndkVersion = flutter.ndkVersion
|
||||||
|
|
||||||
compileOptions {
|
compileOptions {
|
||||||
|
isCoreLibraryDesugaringEnabled = true
|
||||||
sourceCompatibility = JavaVersion.VERSION_17
|
sourceCompatibility = JavaVersion.VERSION_17
|
||||||
targetCompatibility = JavaVersion.VERSION_17
|
targetCompatibility = JavaVersion.VERSION_17
|
||||||
}
|
}
|
||||||
@@ -55,6 +56,10 @@ android {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.4")
|
||||||
|
}
|
||||||
|
|
||||||
flutter {
|
flutter {
|
||||||
source = "../.."
|
source = "../.."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import Flutter
|
import Flutter
|
||||||
import UIKit
|
import UIKit
|
||||||
|
import FirebaseMessaging
|
||||||
|
|
||||||
@main
|
@main
|
||||||
@objc class AppDelegate: FlutterAppDelegate {
|
@objc class AppDelegate: FlutterAppDelegate {
|
||||||
@@ -10,4 +11,13 @@ import UIKit
|
|||||||
GeneratedPluginRegistrant.register(with: self)
|
GeneratedPluginRegistrant.register(with: self)
|
||||||
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:firebase_core/firebase_core.dart';
|
import 'package:firebase_core/firebase_core.dart';
|
||||||
import 'package:real_estate_mobile/config/app_config.dart';
|
import 'package:real_estate_mobile/config/app_config.dart';
|
||||||
|
|
||||||
@@ -5,44 +7,68 @@ class FirebaseConfig {
|
|||||||
static FirebaseOptions get currentOptions {
|
static FirebaseOptions get currentOptions {
|
||||||
switch (AppConfig.flavor) {
|
switch (AppConfig.flavor) {
|
||||||
case Flavor.dev:
|
case Flavor.dev:
|
||||||
return _dev;
|
return Platform.isIOS ? _devIos : _devAndroid;
|
||||||
case Flavor.demo:
|
case Flavor.demo:
|
||||||
return _demo;
|
return Platform.isIOS ? _demoIos : _demoAndroid;
|
||||||
case Flavor.local:
|
case Flavor.local:
|
||||||
return _local;
|
return Platform.isIOS ? _localIos : _localAndroid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Dev ──
|
// ── Dev (Android) ──
|
||||||
static const _dev = FirebaseOptions(
|
static const _devAndroid = FirebaseOptions(
|
||||||
apiKey: 'AIzaSyAwb_9fc7n9gbN_IQqWeYRkHSSykzVHCyc', // Android
|
apiKey: 'AIzaSyAwb_9fc7n9gbN_IQqWeYRkHSSykzVHCyc',
|
||||||
appId: '1:703616926518:android:4342b796fbabb690fca997',
|
appId: '1:703616926518:android:4342b796fbabb690fca997',
|
||||||
messagingSenderId: '703616926518',
|
messagingSenderId: '703616926518',
|
||||||
projectId: 'real-estate-2d71e',
|
projectId: 'real-estate-2d71e',
|
||||||
storageBucket: 'real-estate-2d71e.firebasestorage.app',
|
storageBucket: 'real-estate-2d71e.firebasestorage.app',
|
||||||
iosBundleId: 'com.requestn.realEstateMobile.dev',
|
|
||||||
iosClientId: null,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// ── Demo ──
|
// ── Dev (iOS) ──
|
||||||
static const _demo = FirebaseOptions(
|
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',
|
apiKey: 'AIzaSyAwb_9fc7n9gbN_IQqWeYRkHSSykzVHCyc',
|
||||||
appId: '1:703616926518:android:270639d6887d2cb4fca997',
|
appId: '1:703616926518:android:270639d6887d2cb4fca997',
|
||||||
messagingSenderId: '703616926518',
|
messagingSenderId: '703616926518',
|
||||||
projectId: 'real-estate-2d71e',
|
projectId: 'real-estate-2d71e',
|
||||||
storageBucket: 'real-estate-2d71e.firebasestorage.app',
|
storageBucket: 'real-estate-2d71e.firebasestorage.app',
|
||||||
iosBundleId: 'com.requestn.realEstateMobile.demo',
|
|
||||||
iosClientId: null,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// ── Local ──
|
// ── Demo (iOS) ──
|
||||||
static const _local = FirebaseOptions(
|
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',
|
apiKey: 'AIzaSyAwb_9fc7n9gbN_IQqWeYRkHSSykzVHCyc',
|
||||||
appId: '1:703616926518:android:2eb242f07b174c25fca997',
|
appId: '1:703616926518:android:2eb242f07b174c25fca997',
|
||||||
messagingSenderId: '703616926518',
|
messagingSenderId: '703616926518',
|
||||||
projectId: 'real-estate-2d71e',
|
projectId: 'real-estate-2d71e',
|
||||||
storageBucket: 'real-estate-2d71e.firebasestorage.app',
|
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',
|
iosBundleId: 'com.requestn.realEstateMobile.local',
|
||||||
iosClientId: null,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,16 +30,8 @@ class PushNotificationService {
|
|||||||
void Function(String? actionUrl)? onNotificationTap;
|
void Function(String? actionUrl)? onNotificationTap;
|
||||||
|
|
||||||
/// Initialize Firebase Messaging and local notifications.
|
/// Initialize Firebase Messaging and local notifications.
|
||||||
/// Skipped on iOS until Firebase iOS app is configured.
|
|
||||||
Future<void> initialize() async {
|
Future<void> initialize() async {
|
||||||
if (_initialized) return;
|
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;
|
_initialized = true;
|
||||||
|
|
||||||
_messaging = FirebaseMessaging.instance;
|
_messaging = FirebaseMessaging.instance;
|
||||||
@@ -188,7 +180,7 @@ class PushNotificationService {
|
|||||||
|
|
||||||
/// Unregister FCM token from backend (call on logout).
|
/// Unregister FCM token from backend (call on logout).
|
||||||
Future<void> unregister() async {
|
Future<void> unregister() async {
|
||||||
if (Platform.isIOS || _currentToken == null) return;
|
if (_currentToken == null) return;
|
||||||
try {
|
try {
|
||||||
await _repo.removeFcmToken(_currentToken!);
|
await _repo.removeFcmToken(_currentToken!);
|
||||||
debugPrint('[FCM] Token unregistered from backend');
|
debugPrint('[FCM] Token unregistered from backend');
|
||||||
@@ -200,7 +192,6 @@ class PushNotificationService {
|
|||||||
|
|
||||||
/// Re-register token after login.
|
/// Re-register token after login.
|
||||||
Future<void> registerAfterLogin() async {
|
Future<void> registerAfterLogin() async {
|
||||||
if (Platform.isIOS) return;
|
|
||||||
await _getAndRegisterToken();
|
await _getAndRegisterToken();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,12 +10,7 @@ Future<void> mainCommon(Flavor flavor) async {
|
|||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
await AppConfig.init(flavor);
|
await AppConfig.init(flavor);
|
||||||
|
|
||||||
// Initialize Firebase — iOS may fail if no iOS app configured in Firebase Console
|
await Firebase.initializeApp(options: FirebaseConfig.currentOptions);
|
||||||
try {
|
|
||||||
await Firebase.initializeApp(options: FirebaseConfig.currentOptions);
|
|
||||||
} catch (e) {
|
|
||||||
debugPrint('[Firebase] Init failed (expected on iOS without config): $e'); // ignore: avoid_print
|
|
||||||
}
|
|
||||||
|
|
||||||
runApp(const ProviderScope(child: MyApp()));
|
runApp(const ProviderScope(child: MyApp()));
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user