diff --git a/whatsapp_app/ios/Runner.xcodeproj/project.pbxproj b/whatsapp_app/ios/Runner.xcodeproj/project.pbxproj index 9f6a0a1..ceb2d27 100644 --- a/whatsapp_app/ios/Runner.xcodeproj/project.pbxproj +++ b/whatsapp_app/ios/Runner.xcodeproj/project.pbxproj @@ -67,6 +67,7 @@ 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; BE672457097ACB02A0172419 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; + C67DFB872FBB6A460051E88E /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = ""; }; F120D236BB7566D5DE73F0B9 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; F90E4DAFC6F0443563808446 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ @@ -109,7 +110,6 @@ 5FAD3FB76264405B9D466D11 /* Pods-RunnerTests.release.xcconfig */, BE672457097ACB02A0172419 /* Pods-RunnerTests.profile.xcconfig */, ); - name = Pods; path = Pods; sourceTree = ""; }; @@ -149,6 +149,7 @@ 97C146F01CF9000F007C117D /* Runner */ = { isa = PBXGroup; children = ( + C67DFB872FBB6A460051E88E /* Runner.entitlements */, 97C146FA1CF9000F007C117D /* Main.storyboard */, 97C146FD1CF9000F007C117D /* Assets.xcassets */, 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, @@ -478,6 +479,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = 63CVT8G5P8; ENABLE_BITCODE = NO; @@ -661,6 +663,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = 63CVT8G5P8; ENABLE_BITCODE = NO; @@ -684,6 +687,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = 63CVT8G5P8; ENABLE_BITCODE = NO; diff --git a/whatsapp_app/ios/Runner/Info.plist b/whatsapp_app/ios/Runner/Info.plist index 93aa880..f3df2a5 100644 --- a/whatsapp_app/ios/Runner/Info.plist +++ b/whatsapp_app/ios/Runner/Info.plist @@ -26,8 +26,20 @@ $(FLUTTER_BUILD_NUMBER) LSRequiresIPhoneOS + NSCameraUsageDescription + This app requires camera access to take and send photos via WhatsApp. + NSContactsUsageDescription + This app requires contacts access to match phone numbers with your local address book names. + NSMicrophoneUsageDescription + This app requires microphone access to record and send audio messages via WhatsApp. + NSPhotoLibraryUsageDescription + This app requires photo library access to choose and send photos via WhatsApp. UIApplicationSupportsIndirectInputEvents + UIBackgroundModes + + remote-notification + UILaunchStoryboardName LaunchScreen UIMainStoryboardFile @@ -45,13 +57,5 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight - NSContactsUsageDescription - This app requires contacts access to match phone numbers with your local address book names. - NSCameraUsageDescription - This app requires camera access to take and send photos via WhatsApp. - NSPhotoLibraryUsageDescription - This app requires photo library access to choose and send photos via WhatsApp. - NSMicrophoneUsageDescription - This app requires microphone access to record and send audio messages via WhatsApp. diff --git a/whatsapp_app/ios/Runner/Runner.entitlements b/whatsapp_app/ios/Runner/Runner.entitlements new file mode 100644 index 0000000..903def2 --- /dev/null +++ b/whatsapp_app/ios/Runner/Runner.entitlements @@ -0,0 +1,8 @@ + + + + + aps-environment + development + + diff --git a/whatsapp_app/lib/services/firebase_service.dart b/whatsapp_app/lib/services/firebase_service.dart index 95cfedc..1587330 100644 --- a/whatsapp_app/lib/services/firebase_service.dart +++ b/whatsapp_app/lib/services/firebase_service.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'dart:convert'; import 'dart:io'; import 'package:firebase_messaging/firebase_messaging.dart'; +import 'package:flutter/widgets.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:get/get.dart'; import '../models/conversation_model.dart'; @@ -158,6 +159,14 @@ class FirebaseService extends GetxService { final name = data['name'] ?? 'WhatsApp'; final body = data['body'] ?? 'New Message'; + // Only show local notifications when the app is actively in the foreground (resumed). + // If the app is in the background or suspended, the native FCM notification will handle it natively. + // This fully prevents duplicate notifications! + if (WidgetsBinding.instance.lifecycleState != AppLifecycleState.resumed) { + print('[FCM] Skipping WebSocket local notification: app is in background.'); + return; + } + // Smart Notification: Only show if we are NOT currently in this chat final activeChatId = Get.find().activeChatId.value; if (chatId != null && activeChatId == chatId) { diff --git a/whatsapp_app/lib/services/whatsapp_service.dart b/whatsapp_app/lib/services/whatsapp_service.dart index 22a81e0..473ffa1 100644 --- a/whatsapp_app/lib/services/whatsapp_service.dart +++ b/whatsapp_app/lib/services/whatsapp_service.dart @@ -3,6 +3,7 @@ import 'dart:convert'; import 'package:get/get.dart'; import 'package:web_socket_channel/web_socket_channel.dart'; import '../config/app_config.dart'; +import 'contacts_service.dart'; import 'firebase_service.dart'; enum WsStatus { disconnected, connecting, connected, waReady } @@ -104,9 +105,15 @@ class WhatsAppService extends GetxService { body = '📷 Media/Audio message'; } try { + final String cleanNumber = chatId?.split('@')[0] ?? ''; + final String senderName = Get.find().getContactName( + cleanNumber, + cleanNumber.isNotEmpty ? '+$cleanNumber' : 'WhatsApp', + ); + Get.find().showLocalNotificationFromData({ 'chatId': chatId, - 'name': chatId?.split('@')[0] ?? 'WhatsApp', + 'name': senderName, 'body': body, }); } catch (e) {