From 6c77fe7850d202824b07695e0c678b99e0efadab Mon Sep 17 00:00:00 2001 From: QuentinArguillere Date: Mon, 19 Feb 2024 17:08:10 +0100 Subject: [PATCH 01/18] Add msgNotificationService app extension --- Linphone.xcodeproj/project.pbxproj | 185 ++++++++++++++++++ Linphone/Linphone.entitlements | 4 + Linphone/Localizable.xcstrings | 6 - Podfile | 9 + .../GoogleService-Info.plist | 36 ++++ msgNotificationService/Info.plist | 31 +++ .../NotificationService.swift | 83 ++++++++ .../msgNotificationService.entitlements | 14 ++ 8 files changed, 362 insertions(+), 6 deletions(-) create mode 100644 msgNotificationService/GoogleService-Info.plist create mode 100644 msgNotificationService/Info.plist create mode 100644 msgNotificationService/NotificationService.swift create mode 100644 msgNotificationService/msgNotificationService.entitlements diff --git a/Linphone.xcodeproj/project.pbxproj b/Linphone.xcodeproj/project.pbxproj index 87d0917df..67231e24a 100644 --- a/Linphone.xcodeproj/project.pbxproj +++ b/Linphone.xcodeproj/project.pbxproj @@ -7,9 +7,11 @@ objects = { /* Begin PBXBuildFile section */ + 660AAF7F2B839272004C0FA6 /* msgNotificationService.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 660AAF7B2B839271004C0FA6 /* msgNotificationService.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 660D8A712B517D260092694D /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 660D8A702B517D260092694D /* GoogleService-Info.plist */; }; 662B69D92B25DE18007118BF /* TelecomManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 662B69D82B25DE18007118BF /* TelecomManager.swift */; }; 662B69DB2B25DE25007118BF /* ProviderDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 662B69DA2B25DE25007118BF /* ProviderDelegate.swift */; }; + 6691CA7E2B839C2D00B2A7B8 /* NotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6691CA7D2B839C2D00B2A7B8 /* NotificationService.swift */; }; 66C491F92B24D25B00CEA16D /* ConfigExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66C491F82B24D25A00CEA16D /* ConfigExtension.swift */; }; 66C491FB2B24D32600CEA16D /* CoreExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66C491FA2B24D32600CEA16D /* CoreExtension.swift */; }; 66C491FD2B24D36500CEA16D /* AudioRouteUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66C491FC2B24D36500CEA16D /* AudioRouteUtils.swift */; }; @@ -99,10 +101,37 @@ D7FB55112AD447FD00A5AB15 /* RegisterFragment.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7FB55102AD447FD00A5AB15 /* RegisterFragment.swift */; }; /* End PBXBuildFile section */ +/* Begin PBXContainerItemProxy section */ + 660AAF7D2B839272004C0FA6 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D719ABAB2ABC67BF00B41C10 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 660AAF7A2B839271004C0FA6; + remoteInfo = msgNotificationService; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 660AAF802B839272004C0FA6 /* Embed Foundation Extensions */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 13; + files = ( + 660AAF7F2B839272004C0FA6 /* msgNotificationService.appex in Embed Foundation Extensions */, + ); + name = "Embed Foundation Extensions"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + /* Begin PBXFileReference section */ + 660AAF7B2B839271004C0FA6 /* msgNotificationService.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = msgNotificationService.appex; sourceTree = BUILT_PRODUCTS_DIR; }; + 660AAF842B8392E0004C0FA6 /* msgNotificationService.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = msgNotificationService.entitlements; sourceTree = ""; }; 660D8A702B517D260092694D /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; 662B69D82B25DE18007118BF /* TelecomManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TelecomManager.swift; sourceTree = ""; }; 662B69DA2B25DE25007118BF /* ProviderDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProviderDelegate.swift; sourceTree = ""; }; + 6691CA7D2B839C2D00B2A7B8 /* NotificationService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotificationService.swift; sourceTree = ""; }; 66C491F82B24D25A00CEA16D /* ConfigExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConfigExtension.swift; sourceTree = ""; }; 66C491FA2B24D32600CEA16D /* CoreExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreExtension.swift; sourceTree = ""; }; 66C491FC2B24D36500CEA16D /* AudioRouteUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioRouteUtils.swift; sourceTree = ""; }; @@ -196,6 +225,13 @@ /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ + 660AAF782B839271004C0FA6 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; D719ABB02ABC67BF00B41C10 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -206,6 +242,15 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 660AAF7C2B839272004C0FA6 /* msgNotificationService */ = { + isa = PBXGroup; + children = ( + 6691CA7D2B839C2D00B2A7B8 /* NotificationService.swift */, + 660AAF842B8392E0004C0FA6 /* msgNotificationService.entitlements */, + ); + path = msgNotificationService; + sourceTree = ""; + }; 662B69D72B25DDF6007118BF /* TelecomManager */ = { isa = PBXGroup; children = ( @@ -257,6 +302,7 @@ children = ( 660D8A702B517D260092694D /* GoogleService-Info.plist */, D719ABB52ABC67BF00B41C10 /* Linphone */, + 660AAF7C2B839272004C0FA6 /* msgNotificationService */, D719ABB42ABC67BF00B41C10 /* Products */, A31AF2AB8C6A3D7B7EA3B424 /* Pods */, ); @@ -266,6 +312,7 @@ isa = PBXGroup; children = ( D719ABB32ABC67BF00B41C10 /* Linphone.app */, + 660AAF7B2B839271004C0FA6 /* msgNotificationService.appex */, ); name = Products; sourceTree = ""; @@ -548,12 +595,30 @@ /* End PBXGroup section */ /* Begin PBXNativeTarget section */ + 660AAF7A2B839271004C0FA6 /* msgNotificationService */ = { + isa = PBXNativeTarget; + buildConfigurationList = 660AAF832B839272004C0FA6 /* Build configuration list for PBXNativeTarget "msgNotificationService" */; + buildPhases = ( + 660AAF772B839271004C0FA6 /* Sources */, + 660AAF782B839271004C0FA6 /* Frameworks */, + 660AAF792B839271004C0FA6 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = msgNotificationService; + productName = msgNotificationService; + productReference = 660AAF7B2B839271004C0FA6 /* msgNotificationService.appex */; + productType = "com.apple.product-type.app-extension"; + }; D719ABB22ABC67BF00B41C10 /* Linphone */ = { isa = PBXNativeTarget; buildConfigurationList = D719ABC22ABC67BF00B41C10 /* Build configuration list for PBXNativeTarget "Linphone" */; buildPhases = ( D719ABAF2ABC67BF00B41C10 /* Sources */, D719ABB02ABC67BF00B41C10 /* Frameworks */, + 660AAF802B839272004C0FA6 /* Embed Foundation Extensions */, D719ABB12ABC67BF00B41C10 /* Resources */, D7FB55122AD53FE200A5AB15 /* Run Script */, 66BF2D4B2B558A3100A5F2E3 /* Crashlytics */, @@ -561,6 +626,7 @@ buildRules = ( ); dependencies = ( + 660AAF7E2B839272004C0FA6 /* PBXTargetDependency */, ); name = Linphone; productName = Linphone; @@ -577,6 +643,10 @@ LastSwiftUpdateCheck = 1430; LastUpgradeCheck = 1430; TargetAttributes = { + 660AAF7A2B839271004C0FA6 = { + CreatedOnToolsVersion = 15.0.1; + LastSwiftMigration = 1500; + }; D719ABB22ABC67BF00B41C10 = { CreatedOnToolsVersion = 14.3.1; }; @@ -596,11 +666,19 @@ projectRoot = ""; targets = ( D719ABB22ABC67BF00B41C10 /* Linphone */, + 660AAF7A2B839271004C0FA6 /* msgNotificationService */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ + 660AAF792B839271004C0FA6 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; D719ABB12ABC67BF00B41C10 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -670,6 +748,14 @@ /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ + 660AAF772B839271004C0FA6 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 6691CA7E2B839C2D00B2A7B8 /* NotificationService.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; D719ABAF2ABC67BF00B41C10 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -755,7 +841,95 @@ }; /* End PBXSourcesBuildPhase section */ +/* Begin PBXTargetDependency section */ + 660AAF7E2B839272004C0FA6 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 660AAF7A2B839271004C0FA6 /* msgNotificationService */; + targetProxy = 660AAF7D2B839272004C0FA6 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + /* Begin XCBuildConfiguration section */ + 660AAF812B839272004C0FA6 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = msgNotificationService/msgNotificationService.entitlements; + CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = Z2V957B3D6; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_PREPROCESSOR_DEFINITIONS = ( + "$(inherited)", + "DEBUG=1", + ); + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = msgNotificationService/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = msgNotificationService; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + IPHONEOS_DEPLOYMENT_TARGET = 17.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@executable_path/../../Frameworks", + ); + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MARKETING_VERSION = 1.0; + OTHER_SWIFT_FLAGS = "$(inherited)"; + PRODUCT_BUNDLE_IDENTIFIER = org.linphone.phone.msgNotificationService; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 660AAF822B839272004C0FA6 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = msgNotificationService/msgNotificationService.entitlements; + CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = Z2V957B3D6; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_PREPROCESSOR_DEFINITIONS = "$(inherited)"; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = msgNotificationService/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = msgNotificationService; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + IPHONEOS_DEPLOYMENT_TARGET = 17.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@executable_path/../../Frameworks", + ); + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MARKETING_VERSION = 1.0; + OTHER_SWIFT_FLAGS = "$(inherited)"; + PRODUCT_BUNDLE_IDENTIFIER = org.linphone.phone.msgNotificationService; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; D719ABC02ABC67BF00B41C10 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -874,6 +1048,7 @@ D719ABC32ABC67BF00B41C10 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO; @@ -929,6 +1104,7 @@ D719ABC42ABC67BF00B41C10 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO; @@ -980,6 +1156,15 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ + 660AAF832B839272004C0FA6 /* Build configuration list for PBXNativeTarget "msgNotificationService" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 660AAF812B839272004C0FA6 /* Debug */, + 660AAF822B839272004C0FA6 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; D719ABAE2ABC67BF00B41C10 /* Build configuration list for PBXProject "Linphone" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/Linphone/Linphone.entitlements b/Linphone/Linphone.entitlements index f88b0a974..6a0769bbd 100644 --- a/Linphone/Linphone.entitlements +++ b/Linphone/Linphone.entitlements @@ -17,5 +17,9 @@ com.apple.security.files.user-selected.read-only + keychain-access-groups + + $(AppIdentifierPrefix)org.linphone.phone + diff --git a/Linphone/Localizable.xcstrings b/Linphone/Localizable.xcstrings index 589a8fa68..b5592f0d7 100644 --- a/Linphone/Localizable.xcstrings +++ b/Linphone/Localizable.xcstrings @@ -244,9 +244,6 @@ }, "Contacts" : { - }, - "Content" : { - }, "Continue" : { @@ -567,9 +564,6 @@ }, "This contact will be deleted definitively." : { - }, - "Title" : { - }, "TLS" : { diff --git a/Podfile b/Podfile index 696a25e90..cc53ba162 100644 --- a/Podfile +++ b/Podfile @@ -30,6 +30,15 @@ target 'Linphone' do end +target 'msgNotificationService' do + # Uncomment the next line if you're using Swift or would like to use dynamic frameworks + use_frameworks! + + # Pods for messagesNotification + basic_pods + +end + post_install do |installer| app_project = Xcodeproj::Project.open(Dir.glob("*.xcodeproj")[0]) app_project.native_targets.each do |target| diff --git a/msgNotificationService/GoogleService-Info.plist b/msgNotificationService/GoogleService-Info.plist new file mode 100644 index 000000000..98867592f --- /dev/null +++ b/msgNotificationService/GoogleService-Info.plist @@ -0,0 +1,36 @@ + + + + + CLIENT_ID + + REVERSED_CLIENT_ID + + API_KEY + + GCM_SENDER_ID + + PLIST_VERSION + 1 + BUNDLE_ID + org.linphone.phone.msgNotificationService + PROJECT_ID + linphone-iphone + STORAGE_BUCKET + linphone-iphone.appspot.com + IS_ADS_ENABLED + + IS_ANALYTICS_ENABLED + + IS_APPINVITE_ENABLED + + IS_GCM_ENABLED + + IS_SIGNIN_ENABLED + + GOOGLE_APP_ID + + DATABASE_URL + + + diff --git a/msgNotificationService/Info.plist b/msgNotificationService/Info.plist new file mode 100644 index 000000000..59a92df5e --- /dev/null +++ b/msgNotificationService/Info.plist @@ -0,0 +1,31 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + msgNotificationService + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + $(MARKETING_VERSION) + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSExtension + + NSExtensionPointIdentifier + com.apple.usernotifications.service + NSExtensionPrincipalClass + $(PRODUCT_MODULE_NAME).NotificationService + + + diff --git a/msgNotificationService/NotificationService.swift b/msgNotificationService/NotificationService.swift new file mode 100644 index 000000000..de2092700 --- /dev/null +++ b/msgNotificationService/NotificationService.swift @@ -0,0 +1,83 @@ +/* +* Copyright (c) 2010-2020 Belledonne Communications SARL. +* +* This file is part of linphone-iphone +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +// swiftlint:disable identifier_name + +import UserNotifications +import linphonesw +#if USE_CRASHLYTICS +import Firebase +#endif + +var APP_GROUP_ID = "group.org.linphone.phone.msgNotification" +var LINPHONE_DUMMY_SUBJECT = "dummy subject" + +struct MsgData: Codable { + var from: String? + var body: String? + var subtitle: String? + var callId: String? + var localAddr: String? + var peerAddr: String? +} + +class NotificationService: UNNotificationServiceExtension { + + var contentHandler: ((UNNotificationContent) -> Void)? + var bestAttemptContent: UNMutableNotificationContent? + + var lc: Core? +// static var logDelegate: LinphoneLoggingServiceManager! +// static var log: LoggingService! + + override init() { + super.init() +#if USE_CRASHLYTICS + FirebaseApp.configure() +#endif + } + + override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) { + + } + + override func serviceExtensionTimeWillExpire() { + // Called just before the extension will be terminated by the system. + // Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used. + //NotificationService.log.warning(message: "serviceExtensionTimeWillExpire") + //stopCore() + if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent { + NSLog("[msgNotificationService] serviceExtensionTimeWillExpire") + bestAttemptContent.categoryIdentifier = "app_active" + + if let chatRoomInviteAddr = bestAttemptContent.userInfo["chat-room-addr"] as? String, !chatRoomInviteAddr.isEmpty { + bestAttemptContent.title = NSLocalizedString("GC_MSG", comment: "") + bestAttemptContent.body = "" + bestAttemptContent.sound = UNNotificationSound(named: UNNotificationSoundName("msg.caf")) // TODO : temporary fix, to be removed after flexisip release + } else { + bestAttemptContent.title = NSLocalizedString("Message received", comment: "") + bestAttemptContent.body = NSLocalizedString("IM_MSG", comment: "") + } + contentHandler(bestAttemptContent) + } + } + +} + +// swiftlint:enable identifier_name diff --git a/msgNotificationService/msgNotificationService.entitlements b/msgNotificationService/msgNotificationService.entitlements new file mode 100644 index 000000000..b63a67474 --- /dev/null +++ b/msgNotificationService/msgNotificationService.entitlements @@ -0,0 +1,14 @@ + + + + + com.apple.security.application-groups + + group.org.linphone.phone.msgNotification + + keychain-access-groups + + $(AppIdentifierPrefix)org.linphone.phone + + + From fd61bca29f45b9ad765e02f14c5ee4d2432ad6e2 Mon Sep 17 00:00:00 2001 From: QuentinArguillere Date: Fri, 26 Jan 2024 15:37:46 +0100 Subject: [PATCH 02/18] Add remote push notification support, which will be required to receive and process the account creation token --- Linphone/LinphoneApp.swift | 25 +++++++++++++++++++ .../Viewmodel/AccountLoginViewModel.swift | 2 +- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/Linphone/LinphoneApp.swift b/Linphone/LinphoneApp.swift index 95378929c..e82ea23f1 100644 --- a/Linphone/LinphoneApp.swift +++ b/Linphone/LinphoneApp.swift @@ -22,6 +22,8 @@ import SwiftUI import Firebase #endif +let accountTokenNotification = Notification.Name("AccountCreationTokenReceived") + class AppDelegate: NSObject, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { @@ -30,6 +32,29 @@ class AppDelegate: NSObject, UIApplicationDelegate { #endif return true } + + func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { + let tokenStr = deviceToken.map { String(format: "%02.2hhx", $0) }.joined() + Log.info("Received remote push token : \(tokenStr)") + CoreContext.shared.doOnCoreQueue { core in + Log.info("Forwarding remote push token to core") + core.didRegisterForRemotePushWithStringifiedToken(deviceTokenStr: tokenStr + ":remote") + } + } + + func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) { + Log.error("Failed to register for push notifications : \(error.localizedDescription)") + } + + func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { + Log.info("debugtrace -- Received background push notification, payload = \(userInfo.description)") + + let creationToken = (userInfo["customPayload"] as? NSDictionary)?["token"] as? String + if let creationToken = creationToken { + NotificationCenter.default.post(name: accountTokenNotification, object: nil, userInfo: ["token": creationToken]) + } + completionHandler(UIBackgroundFetchResult.newData) + } } @main diff --git a/Linphone/UI/Assistant/Viewmodel/AccountLoginViewModel.swift b/Linphone/UI/Assistant/Viewmodel/AccountLoginViewModel.swift index 98a4f43f9..5c2a3f1ad 100644 --- a/Linphone/UI/Assistant/Viewmodel/AccountLoginViewModel.swift +++ b/Linphone/UI/Assistant/Viewmodel/AccountLoginViewModel.swift @@ -90,7 +90,7 @@ class AccountLoginViewModel: ObservableObject { // And we ensure the account will start the registration process accountParams.registerEnabled = true accountParams.pushNotificationAllowed = true - accountParams.remotePushNotificationAllowed = false + accountParams.remotePushNotificationAllowed = true #if DEBUG let pushEnvironment = ".dev" #else From 3461b096ebd49f6bc410c5e9f4c9777ace5e97a2 Mon Sep 17 00:00:00 2001 From: QuentinArguillere Date: Fri, 26 Jan 2024 16:33:16 +0100 Subject: [PATCH 03/18] Add push notification permission request --- Linphone/Utils/PermissionManager.swift | 36 +++++++++++++++++++------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/Linphone/Utils/PermissionManager.swift b/Linphone/Utils/PermissionManager.swift index bad8532a5..e20bc2d51 100644 --- a/Linphone/Utils/PermissionManager.swift +++ b/Linphone/Utils/PermissionManager.swift @@ -20,25 +20,41 @@ import Foundation import Photos import Contacts +import UserNotifications +import SwiftUI class PermissionManager: ObservableObject { static let shared = PermissionManager() + @Published var pushPermissionGranted = false @Published var photoLibraryPermissionGranted = false @Published var cameraPermissionGranted = false - @Published var contactsPermissionGranted = false + @Published var contactsPermissionGranted = false @Published var microphonePermissionGranted = false private init() {} func getPermissions() { + pushNotificationRequestPermission() microphoneRequestPermission() photoLibraryRequestPermission() cameraRequestPermission() contactsRequestPermission() } + func pushNotificationRequestPermission() { + let options: UNAuthorizationOptions = [.alert, .sound, .badge] + UNUserNotificationCenter.current().requestAuthorization(options: options) { (granted, error) in + if let error = error { + Log.error("Unexpected error when asking for Push permission : \(error.localizedDescription)") + } + DispatchQueue.main.async { + self.pushPermissionGranted = granted + } + } + } + func microphoneRequestPermission() { AVAudioSession.sharedInstance().requestRecordPermission({ granted in DispatchQueue.main.async { @@ -62,13 +78,13 @@ class PermissionManager: ObservableObject { } }) } - - func contactsRequestPermission() { - let store = CNContactStore() - store.requestAccess(for: .contacts) { success, _ in - DispatchQueue.main.async { - self.contactsPermissionGranted = success - } - } - } + + func contactsRequestPermission() { + let store = CNContactStore() + store.requestAccess(for: .contacts) { success, _ in + DispatchQueue.main.async { + self.contactsPermissionGranted = success + } + } + } } From 89d4926798b302536a68a75ba1c22804b7b2c2fa Mon Sep 17 00:00:00 2001 From: QuentinArguillere Date: Fri, 26 Jan 2024 16:34:01 +0100 Subject: [PATCH 04/18] Enable remote push notification by default in the assistant file --- Linphone/Ressources/assistant_linphone_default_values | 1 + 1 file changed, 1 insertion(+) diff --git a/Linphone/Ressources/assistant_linphone_default_values b/Linphone/Ressources/assistant_linphone_default_values index f3723d7a9..c1e26073c 100644 --- a/Linphone/Ressources/assistant_linphone_default_values +++ b/Linphone/Ressources/assistant_linphone_default_values @@ -18,6 +18,7 @@ sip:conference-factory@sip.linphone.org sip:videoconference-factory@sip.linphone.org 1 + 1 1 1 https://lime.linphone.org/lime-server/lime-server.php From b999f2f1e3fcb41c7ebcfe3965edf151359f7535 Mon Sep 17 00:00:00 2001 From: QuentinArguillere Date: Tue, 20 Feb 2024 10:33:02 +0100 Subject: [PATCH 05/18] Import linphone 5.2 msgNotificationService implementation --- Linphone.xcodeproj/project.pbxproj | 8 + .../NotificationService.swift | 304 +++++++++++++++--- 2 files changed, 264 insertions(+), 48 deletions(-) diff --git a/Linphone.xcodeproj/project.pbxproj b/Linphone.xcodeproj/project.pbxproj index 67231e24a..8dfb1c299 100644 --- a/Linphone.xcodeproj/project.pbxproj +++ b/Linphone.xcodeproj/project.pbxproj @@ -17,6 +17,10 @@ 66C491FD2B24D36500CEA16D /* AudioRouteUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66C491FC2B24D36500CEA16D /* AudioRouteUtils.swift */; }; 66C491FF2B24D4AC00CEA16D /* FileUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66C491FE2B24D4AC00CEA16D /* FileUtils.swift */; }; 66C492012B24DB6900CEA16D /* Log.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66C492002B24DB6900CEA16D /* Log.swift */; }; + 66FBFC482B83B8CC00BC6AB1 /* Log.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66C492002B24DB6900CEA16D /* Log.swift */; }; + 66FBFC492B83BD2400BC6AB1 /* ConfigExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66C491F82B24D25A00CEA16D /* ConfigExtension.swift */; }; + 66FBFC4A2B83BD3300BC6AB1 /* FileUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66C491FE2B24D4AC00CEA16D /* FileUtils.swift */; }; + 66FBFC4B2B83BD7B00BC6AB1 /* CoreExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66C491FA2B24D32600CEA16D /* CoreExtension.swift */; }; D706BA822ADD72D100278F45 /* DeviceRotationViewModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = D706BA812ADD72D100278F45 /* DeviceRotationViewModifier.swift */; }; D70C93DE2AC2D0F60063CA3B /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = D70C93DD2AC2D0F60063CA3B /* Localizable.xcstrings */; }; D717071E2AC5922E0037746F /* ColorExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D717071D2AC5922E0037746F /* ColorExtension.swift */; }; @@ -752,7 +756,11 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 66FBFC482B83B8CC00BC6AB1 /* Log.swift in Sources */, 6691CA7E2B839C2D00B2A7B8 /* NotificationService.swift in Sources */, + 66FBFC492B83BD2400BC6AB1 /* ConfigExtension.swift in Sources */, + 66FBFC4A2B83BD3300BC6AB1 /* FileUtils.swift in Sources */, + 66FBFC4B2B83BD7B00BC6AB1 /* CoreExtension.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/msgNotificationService/NotificationService.swift b/msgNotificationService/NotificationService.swift index de2092700..45a81b621 100644 --- a/msgNotificationService/NotificationService.swift +++ b/msgNotificationService/NotificationService.swift @@ -1,21 +1,21 @@ /* -* Copyright (c) 2010-2020 Belledonne Communications SARL. -* -* This file is part of linphone-iphone -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -*/ + * Copyright (c) 2010-2020 Belledonne Communications SARL. + * + * This file is part of linphone-iphone + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ // swiftlint:disable identifier_name @@ -28,23 +28,52 @@ import Firebase var APP_GROUP_ID = "group.org.linphone.phone.msgNotification" var LINPHONE_DUMMY_SUBJECT = "dummy subject" +extension String { + func getDisplayNameFromSipAddress(lc: Core) -> String? { + Log.info("looking for display name for \(self)") + + let defaults = UserDefaults.init(suiteName: APP_GROUP_ID) + let addressBook = defaults?.dictionary(forKey: "addressBook") + + if addressBook == nil { + Log.info("address book not found in userDefaults") + return nil + } + + var usePrefix = true + if let account = lc.defaultAccount, let params = account.params { + usePrefix = params.useInternationalPrefixForCallsAndChats + } + + if let simpleAddr = lc.interpretUrl(url: self, applyInternationalPrefix: usePrefix) { + simpleAddr.clean() + let nomalSipaddr = simpleAddr.asString() + if let displayName = addressBook?[nomalSipaddr] as? String { + Log.info("display name for \(self): \(displayName)") + return displayName + } + } + + Log.info("display name for \(self) not found in userDefaults") + return nil + } +} + struct MsgData: Codable { - var from: String? - var body: String? - var subtitle: String? - var callId: String? - var localAddr: String? - var peerAddr: String? + var from: String? + var body: String? + var subtitle: String? + var callId: String? + var localAddr: String? + var peerAddr: String? } class NotificationService: UNNotificationServiceExtension { - - var contentHandler: ((UNNotificationContent) -> Void)? - var bestAttemptContent: UNMutableNotificationContent? - - var lc: Core? -// static var logDelegate: LinphoneLoggingServiceManager! -// static var log: LoggingService! + + var contentHandler: ((UNNotificationContent) -> Void)? + var bestAttemptContent: UNMutableNotificationContent? + + var lc: Core? override init() { super.init() @@ -52,20 +81,117 @@ class NotificationService: UNNotificationServiceExtension { FirebaseApp.configure() #endif } - - override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) { - - } - - override func serviceExtensionTimeWillExpire() { - // Called just before the extension will be terminated by the system. - // Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used. - //NotificationService.log.warning(message: "serviceExtensionTimeWillExpire") - //stopCore() - if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent { - NSLog("[msgNotificationService] serviceExtensionTimeWillExpire") - bestAttemptContent.categoryIdentifier = "app_active" - + + override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) { + + self.contentHandler = contentHandler + bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent) + Log.info("[msgNotificationService] start msgNotificationService extension") + /* + if (VFSUtil.vfsEnabled(groupName: APP_GROUP_ID) && !VFSUtil.activateVFS()) { + VFSUtil.log("[VFS] Error unable to activate.", .error) + } + */ + if let bestAttemptContent = bestAttemptContent { + createCore() + + if !lc!.config!.getBool(section: "app", key: "disable_chat_feature", defaultValue: true) { + Log.info("received push payload : \(bestAttemptContent.userInfo.debugDescription)") + + /* + let defaults = UserDefaults.init(suiteName: APP_GROUP_ID) + if let chatroomsPushStatus = defaults?.dictionary(forKey: "chatroomsPushStatus") { + let aps = bestAttemptContent.userInfo["aps"] as? NSDictionary + let alert = aps?["alert"] as? NSDictionary + let fromAddresses = alert?["loc-args"] as? [String] + + if let from = fromAddresses?.first { + if ((chatroomsPushStatus[from] as? String) == "disabled") { + NotificationService.log.message(message: "message comes from a muted chatroom, ignore it") + contentHandler(UNNotificationContent()) + } + } + } + */ + if let chatRoomInviteAddr = bestAttemptContent.userInfo["chat-room-addr"] as? String, !chatRoomInviteAddr.isEmpty { + Log.info("fetch chat room for invite, addr: \(chatRoomInviteAddr)") + let chatRoom = lc!.getNewChatRoomFromConfAddr(chatRoomAddr: chatRoomInviteAddr) + + if let chatRoom = chatRoom { + stopCore() + Log.info("chat room invite received") + bestAttemptContent.title = NSLocalizedString("GC_MSG", comment: "") + if chatRoom.hasCapability(mask: ChatRoom.Capabilities.OneToOne.rawValue) { + if chatRoom.peerAddress?.displayName?.isEmpty != true { + bestAttemptContent.body = chatRoom.peerAddress!.displayName! + } else { + bestAttemptContent.body = chatRoom.peerAddress!.username! + } + } else { + bestAttemptContent.body = chatRoom.subject! + } + + bestAttemptContent.sound = UNNotificationSound(named: UNNotificationSoundName("msg.caf")) // TODO : temporary fix, to be removed after flexisip release + contentHandler(bestAttemptContent) + return + } + } else if let callId = bestAttemptContent.userInfo["call-id"] as? String { + Log.info("fetch msg for callid ["+callId+"]") + let message = lc!.getNewMessageFromCallid(callId: callId) + + if let message = message { + let msgData = parseMessage(message: message) + + // Extension only upates app's badge when main shared core is Off = extension's core is On. + // Otherwise, the app will update the badge. + if lc?.globalState == GlobalState.On, let badge = updateBadge() as NSNumber? { + bestAttemptContent.badge = badge + } + + stopCore() + + bestAttemptContent.sound = UNNotificationSound(named: UNNotificationSoundName(rawValue: "msg.caf")) + bestAttemptContent.title = NSLocalizedString("Message received", comment: "") + if let subtitle = msgData?.subtitle { + bestAttemptContent.subtitle = subtitle + } + if let body = msgData?.body { + bestAttemptContent.body = body + } + + bestAttemptContent.categoryIdentifier = "msg_cat" + + bestAttemptContent.userInfo.updateValue(msgData?.callId as Any, forKey: "CallId") + bestAttemptContent.userInfo.updateValue(msgData?.from as Any, forKey: "from") + bestAttemptContent.userInfo.updateValue(msgData?.peerAddr as Any, forKey: "peer_addr") + bestAttemptContent.userInfo.updateValue(msgData?.localAddr as Any, forKey: "local_addr") + + if message.reactionContent != " " { + contentHandler(bestAttemptContent) + } else { + contentHandler(UNNotificationContent()) + } + + return + } else { + Log.info("Message not found for callid ["+callId+"]") + } + } + } + serviceExtensionTimeWillExpire() + } + + } + + override func serviceExtensionTimeWillExpire() { + // Called just before the extension will be terminated by the system. + // Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used. + Log.warn("serviceExtensionTimeWillExpire") + stopCore() + if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent { + NSLog("[msgNotificationService] serviceExtensionTimeWillExpire") + bestAttemptContent.categoryIdentifier = "app_active" + if let chatRoomInviteAddr = bestAttemptContent.userInfo["chat-room-addr"] as? String, !chatRoomInviteAddr.isEmpty { bestAttemptContent.title = NSLocalizedString("GC_MSG", comment: "") bestAttemptContent.body = "" @@ -74,10 +200,92 @@ class NotificationService: UNNotificationServiceExtension { bestAttemptContent.title = NSLocalizedString("Message received", comment: "") bestAttemptContent.body = NSLocalizedString("IM_MSG", comment: "") } - contentHandler(bestAttemptContent) - } - } - + contentHandler(bestAttemptContent) + } + } + + func parseMessage(message: PushNotificationMessage) -> MsgData? { + + var content = "" + if message.isConferenceInvitationNew { + content = NSLocalizedString("📅 You are invited to a meeting", comment: "") + } else if message.isConferenceInvitationUpdate { + content = NSLocalizedString("📅 Meeting has been modified", comment: "") + } else if message.isConferenceInvitationCancellation { + content = NSLocalizedString("📅 Meeting has been cancelled", comment: "") + } else { + content = message.isText ? message.textContent! : "🗻" + } + + let fromAddr = message.fromAddr?.username + let callId = message.callId + let localUri = message.localAddr?.asStringUriOnly() + let peerUri = message.peerAddr?.asStringUriOnly() + let reactionContent = message.reactionContent + let from: String + if let fromDisplayName = message.fromAddr?.asStringUriOnly().getDisplayNameFromSipAddress(lc: lc!) { + from = fromDisplayName + } else { + from = fromAddr! + } + + var msgData = MsgData(from: fromAddr, body: "", subtitle: "", callId: callId, localAddr: localUri, peerAddr: peerUri) + + if let showMsg = lc!.config?.getBool(section: "app", key: "show_msg_in_notif", defaultValue: true), showMsg == true { + if let subject = message.subject as String?, !subject.isEmpty { + msgData.subtitle = subject + if reactionContent == nil { + msgData.body = from + " : " + content + } else { + msgData.body = from + NSLocalizedString(" has reacted by ", comment: "") + reactionContent! + NSLocalizedString(" to: ", comment: "") + content + } + } else { + msgData.subtitle = from + msgData.body = content + } + } else { + if let subject = message.subject as String?, !subject.isEmpty { + msgData.body = subject + " : " + from + } else { + msgData.body = from + } + } + + Log.info("received msg size : \(content.count) \n") + return msgData + } + + func createCore() { + Log.info("[msgNotificationService] create core") + + let config = Config.newForSharedCore(appGroupId: APP_GROUP_ID, configFilename: "linphonerc", factoryConfigFilename: "") + + LoggingService.Instance.logLevel = LogLevel.Debug + let configDir = Factory.Instance.getConfigDir(context: nil) + + Factory.Instance.logCollectionPath = configDir + Factory.Instance.enableLogCollection(state: LogCollectionState.Enabled) + + lc = try? Factory.Instance.createSharedCoreWithConfig(config: config!, systemContext: nil, appGroupId: APP_GROUP_ID, mainCore: false) + } + + func stopCore() { + Log.info("stop core") + if let lc = lc { + lc.stop() + } + } + + func updateBadge() -> Int { + var count = 0 + count += lc!.unreadChatMessageCount + count += lc!.missedCallsCount + count += lc!.callsNb + Log.info("badge: \(count)\n") + + return count + } + } // swiftlint:enable identifier_name From fd9ede62f8ff709092d4edb276bbfc9eee3ec567 Mon Sep 17 00:00:00 2001 From: QuentinArguillere Date: Mon, 26 Feb 2024 18:04:32 +0100 Subject: [PATCH 06/18] Add ApplicationWillTerminate and ApplicationWillResignActive App delegate functions --- Linphone/LinphoneApp.swift | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/Linphone/LinphoneApp.swift b/Linphone/LinphoneApp.swift index e82ea23f1..a9468c755 100644 --- a/Linphone/LinphoneApp.swift +++ b/Linphone/LinphoneApp.swift @@ -55,6 +55,30 @@ class AppDelegate: NSObject, UIApplicationDelegate { } completionHandler(UIBackgroundFetchResult.newData) } + + func applicationWillTerminate(_ application: UIApplication) { + Log.info("debugtrace -- applicationWillTerminate") + CoreContext.shared.doOnCoreQueue { core in + Log.info("debugtrace COREQUEUE -- applicationWillTerminate") + core.stop() + } + } + + func applicationWillResignActive(_ application: UIApplication) { + Log.info("debugtrace -- applicationWillResignActive") + CoreContext.shared.doOnCoreQueue { core in + Log.info("debugtrace COREQUEUE -- applicationWillResignActive") + if let userDefaults = UserDefaults(suiteName: Config.appGroupName) { + userDefaults.set(false, forKey: "appactive") + } + try? Config.get().sync() + core.enterBackground() + if core.callsNb == 0 { + core.stop() + } + } + } + } @main From ea1420356d322b6d3cc8e5a31b38adfa4cfb98f4 Mon Sep 17 00:00:00 2001 From: QuentinArguillere Date: Mon, 26 Feb 2024 18:05:19 +0100 Subject: [PATCH 07/18] Move firebase initialisation from appdelegate didFinishLaunchingWithOptionsto Corecontext init, which is called earlier --- Linphone/Core/CoreContext.swift | 7 +++++++ Linphone/LinphoneApp.swift | 8 ++------ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/Linphone/Core/CoreContext.swift b/Linphone/Core/CoreContext.swift index 173e36237..1cadfdcbd 100644 --- a/Linphone/Core/CoreContext.swift +++ b/Linphone/Core/CoreContext.swift @@ -26,6 +26,10 @@ import Combine import UniformTypeIdentifiers import Network +#if USE_CRASHLYTICS +import Firebase +#endif + final class CoreContext: ObservableObject { static let shared = CoreContext() @@ -67,6 +71,9 @@ final class CoreContext: ObservableObject { func initialiseCore() throws { +#if USE_CRASHLYTICS + FirebaseApp.configure() +#endif coreQueue.async { LoggingService.Instance.logLevel = LogLevel.Debug diff --git a/Linphone/LinphoneApp.swift b/Linphone/LinphoneApp.swift index a9468c755..dd68f6b7b 100644 --- a/Linphone/LinphoneApp.swift +++ b/Linphone/LinphoneApp.swift @@ -18,18 +18,14 @@ */ import SwiftUI -#if USE_CRASHLYTICS -import Firebase -#endif +import linphonesw let accountTokenNotification = Notification.Name("AccountCreationTokenReceived") class AppDelegate: NSObject, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { -#if USE_CRASHLYTICS - FirebaseApp.configure() -#endif + return true } From c0a16e62be9a718149f31cbc45dfd2f4af078f2e Mon Sep 17 00:00:00 2001 From: QuentinArguillere Date: Mon, 26 Feb 2024 18:06:29 +0100 Subject: [PATCH 08/18] Switch app Core to SharedCore, which will be required to have a working AppExtension --- Linphone/Core/CoreContext.swift | 39 +++++++++---------- Linphone/Linphone.entitlements | 1 - .../Utils/Extensions/ConfigExtension.swift | 5 ++- 3 files changed, 21 insertions(+), 24 deletions(-) diff --git a/Linphone/Core/CoreContext.swift b/Linphone/Core/CoreContext.swift index 1cadfdcbd..3746a3f2c 100644 --- a/Linphone/Core/CoreContext.swift +++ b/Linphone/Core/CoreContext.swift @@ -70,38 +70,35 @@ final class CoreContext: ObservableObject { } func initialiseCore() throws { - #if USE_CRASHLYTICS FirebaseApp.configure() #endif coreQueue.async { - LoggingService.Instance.logLevel = LogLevel.Debug - let configDir = Factory.Instance.getConfigDir(context: nil) - - Factory.Instance.logCollectionPath = configDir + Factory.Instance.logCollectionPath = Factory.Instance.getConfigDir(context: nil) Factory.Instance.enableLogCollection(state: LogCollectionState.Enabled) - Log.info("Initialising core") - let url = NSURL(fileURLWithPath: configDir) - if let pathComponent = url.appendingPathComponent("linphonerc") { - let filePath = pathComponent.path - let fileManager = FileManager.default - if !fileManager.fileExists(atPath: filePath) { - let path = Bundle.main.path(forResource: "linphonerc-default", ofType: nil) - if path != nil { - try? FileManager.default.copyItem(at: NSURL(fileURLWithPath: path!) as URL, to: pathComponent) + Log.info("Checking if linphonerc file exists already. If not, creating one as a copy of linphonerc-default") + if let rcDir = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: Config.appGroupName)? + .appendingPathComponent("Library/Preferences/linphone") { + let rcFileUrl = rcDir.appendingPathComponent("linphonerc") + if !FileManager.default.fileExists(atPath: rcFileUrl.path) { + do { + try FileManager.default.createDirectory(at: rcDir, withIntermediateDirectories: true) + if let pathToDefaultConfig = Bundle.main.path(forResource: "linphonerc-default", ofType: nil) { + try FileManager.default.copyItem(at: URL(fileURLWithPath: pathToDefaultConfig), to: rcFileUrl) + Log.info("Successfully copied linphonerc-default configuration") + } + } catch let error { + Log.error("Failed to copy default linphonerc file: \(error.localizedDescription)") } + } else { + Log.info("Found existing linphonerc file, skip copying of linphonerc-default configuration") } } - let config = try? Factory.Instance.createConfigWithFactory( - path: "\(configDir)/linphonerc", - factoryPath: Bundle.main.path(forResource: "linphonerc-factory", ofType: nil) - ) - if config != nil { - self.mCore = try? Factory.Instance.createCoreWithConfig(config: config!, systemContext: nil) - } + Log.info("Initialising core") + self.mCore = try? Factory.Instance.createSharedCoreWithConfig(config: Config.get(), systemContext: nil, appGroupId: Config.appGroupName, mainCore: true) linphone_core_set_push_registry_dispatch_queue(self.mCore.getCobject, Unmanaged.passUnretained(coreQueue).toOpaque()) self.mCore.autoIterateEnabled = false diff --git a/Linphone/Linphone.entitlements b/Linphone/Linphone.entitlements index 6a0769bbd..5ac776606 100644 --- a/Linphone/Linphone.entitlements +++ b/Linphone/Linphone.entitlements @@ -13,7 +13,6 @@ group.belledonne-communications.linphone group.org.linphone.phone.linphoneExtension group.org.linphone.phone.msgNotification - group.org.linphone.phone.logs com.apple.security.files.user-selected.read-only diff --git a/Linphone/Utils/Extensions/ConfigExtension.swift b/Linphone/Utils/Extensions/ConfigExtension.swift index 9d83cd891..b7b308c0a 100644 --- a/Linphone/Utils/Extensions/ConfigExtension.swift +++ b/Linphone/Utils/Extensions/ConfigExtension.swift @@ -36,7 +36,8 @@ extension Config { public static func get() -> Config { if _instance == nil { - let factoryPath = FileUtil.bundleFilePath(Core.runsInsideExtension() ? "linphonerc-factory-appex" : "linphonerc-factory-app")! + let factoryPath = FileUtil.bundleFilePath("linphonerc-factory")! + let configDir = Factory.Instance.getConfigDir(context: nil) _instance = Config.newForSharedCore(appGroupId: Config.appGroupName, configFilename: "linphonerc", factoryConfigFilename: factoryPath)! } return _instance! @@ -46,7 +47,7 @@ extension Config { return hasEntry(section: section, key: key) == 1 ? getString(section: section, key: key, defaultString: "") : nil } - static let appGroupName = "group.org.linphone.phone.logs" + static let appGroupName = "group.org.linphone.phone.msgNotification" // Needs to be the same name in App Group (capabilities in ALL targets - app & extensions - content + service), can't be stored in the Config itself the Config needs this value to get created static let teamID = Config.get().getString(section: "app", key: "team_id", defaultString: "") static let earlymediaContentExtCatIdentifier = Config.get().getString(section: "app", key: "extension_category", defaultString: "") From 0d4efd7a198a246f0416a5d611825ecf5715ccdb Mon Sep 17 00:00:00 2001 From: QuentinArguillere Date: Mon, 26 Feb 2024 18:12:09 +0100 Subject: [PATCH 09/18] Restore groupchat and lime spec --- Linphone/Core/CoreContext.swift | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Linphone/Core/CoreContext.swift b/Linphone/Core/CoreContext.swift index 3746a3f2c..d7b838985 100644 --- a/Linphone/Core/CoreContext.swift +++ b/Linphone/Core/CoreContext.swift @@ -139,10 +139,6 @@ final class CoreContext: ObservableObject { self.mCore.removeLinphoneSpec(spec: "conference") Log.info("Removing spec 'ephemeral' from core for this version") self.mCore.removeLinphoneSpec(spec: "ephemeral") - Log.info("Removing spec 'groupchat' from core for this version") - self.mCore.removeLinphoneSpec(spec: "groupchat") - Log.info("Removing spec 'lime' from core for this version") - self.mCore.removeLinphoneSpec(spec: "lime") } }) From 944115fb4df919add097f45849ad5c7df60ded8b Mon Sep 17 00:00:00 2001 From: QuentinArguillere Date: Tue, 5 Mar 2024 16:17:23 +0100 Subject: [PATCH 10/18] Add linphonerc-factory and GoogleService-Info.plist to msgNotificationService app extension --- Linphone.xcodeproj/project.pbxproj | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Linphone.xcodeproj/project.pbxproj b/Linphone.xcodeproj/project.pbxproj index 8dfb1c299..6a8dd8b81 100644 --- a/Linphone.xcodeproj/project.pbxproj +++ b/Linphone.xcodeproj/project.pbxproj @@ -11,6 +11,8 @@ 660D8A712B517D260092694D /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 660D8A702B517D260092694D /* GoogleService-Info.plist */; }; 662B69D92B25DE18007118BF /* TelecomManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 662B69D82B25DE18007118BF /* TelecomManager.swift */; }; 662B69DB2B25DE25007118BF /* ProviderDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 662B69DA2B25DE25007118BF /* ProviderDelegate.swift */; }; + 667E5D7F2B8E430C00EBCFC4 /* linphonerc-factory in Resources */ = {isa = PBXBuildFile; fileRef = D732A90B2B0376F500DB42BA /* linphonerc-factory */; }; + 667E5D812B8E444E00EBCFC4 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 667E5D802B8E444D00EBCFC4 /* GoogleService-Info.plist */; }; 6691CA7E2B839C2D00B2A7B8 /* NotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6691CA7D2B839C2D00B2A7B8 /* NotificationService.swift */; }; 66C491F92B24D25B00CEA16D /* ConfigExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66C491F82B24D25A00CEA16D /* ConfigExtension.swift */; }; 66C491FB2B24D32600CEA16D /* CoreExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66C491FA2B24D32600CEA16D /* CoreExtension.swift */; }; @@ -135,6 +137,7 @@ 660D8A702B517D260092694D /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; 662B69D82B25DE18007118BF /* TelecomManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TelecomManager.swift; sourceTree = ""; }; 662B69DA2B25DE25007118BF /* ProviderDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProviderDelegate.swift; sourceTree = ""; }; + 667E5D802B8E444D00EBCFC4 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; 6691CA7D2B839C2D00B2A7B8 /* NotificationService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotificationService.swift; sourceTree = ""; }; 66C491F82B24D25A00CEA16D /* ConfigExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConfigExtension.swift; sourceTree = ""; }; 66C491FA2B24D32600CEA16D /* CoreExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreExtension.swift; sourceTree = ""; }; @@ -249,6 +252,7 @@ 660AAF7C2B839272004C0FA6 /* msgNotificationService */ = { isa = PBXGroup; children = ( + 667E5D802B8E444D00EBCFC4 /* GoogleService-Info.plist */, 6691CA7D2B839C2D00B2A7B8 /* NotificationService.swift */, 660AAF842B8392E0004C0FA6 /* msgNotificationService.entitlements */, ); @@ -680,6 +684,8 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 667E5D7F2B8E430C00EBCFC4 /* linphonerc-factory in Resources */, + 667E5D812B8E444E00EBCFC4 /* GoogleService-Info.plist in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; From a0fdd54b70c8a3fb85262b3bf46de296f6694136 Mon Sep 17 00:00:00 2001 From: QuentinArguillere Date: Tue, 5 Mar 2024 16:17:57 +0100 Subject: [PATCH 11/18] Add NSSupportsSuddentTermination key set to FALSE in info.plist --- Linphone/Info.plist | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Linphone/Info.plist b/Linphone/Info.plist index 0cc800b37..1639aabd3 100644 --- a/Linphone/Info.plist +++ b/Linphone/Info.plist @@ -6,6 +6,8 @@ ITSEncryptionExportComplianceCode b5cb085f-772a-4a4f-8c77-5d1332b1f93f + NSSupportsSuddenTermination + UIAppFonts NotoSans-Light.ttf From c2a1f7bc28605b38d99f7454591dcd9608dffe37 Mon Sep 17 00:00:00 2001 From: QuentinArguillere Date: Tue, 5 Mar 2024 16:19:39 +0100 Subject: [PATCH 12/18] Now stop/starts the core when entering background/foreground. Also moved the presence related code inside this new trigger for phase change --- Linphone/Core/CoreContext.swift | 48 +++++++++++++---------- Linphone/LinphoneApp.swift | 41 +++++++++---------- Linphone/UI/Main/ContentView.swift | 19 --------- Linphone/Utils/MagicSearchSingleton.swift | 4 ++ 4 files changed, 50 insertions(+), 62 deletions(-) diff --git a/Linphone/Core/CoreContext.swift b/Linphone/Core/CoreContext.swift index d7b838985..df718cd9e 100644 --- a/Linphone/Core/CoreContext.swift +++ b/Linphone/Core/CoreContext.swift @@ -166,9 +166,6 @@ final class CoreContext: ObservableObject { if cbVal.state == .Ok { self.loggingInProgress = false self.loggedIn = true - if self.mCore.consolidatedPresence != ConsolidatedPresence.Online { - self.onForeground() - } } else if cbVal.state == .Progress { self.loggingInProgress = true } else { @@ -195,8 +192,11 @@ final class CoreContext: ObservableObject { }) self.mCoreSuscriptions.insert(self.mCore.publisher?.onAccountRegistrationStateChanged?.postOnCoreQueue { (cbVal: (core: Core, account: Account, state: RegistrationState, message: String)) in - // If registration failed, remove account from core - if cbVal.state != .Ok && cbVal.state != .Progress { + if cbVal.state == .Ok { + if self.mCore.consolidatedPresence != ConsolidatedPresence.Online { + self.updatePresence(core: self.mCore, presence: ConsolidatedPresence.Online) + } + } else if cbVal.state != .Ok && cbVal.state != .Progress { // If registration failed, remove account from core let params = cbVal.account.params let clonedParams = params?.clone() clonedParams?.registerEnabled = false @@ -263,27 +263,35 @@ final class CoreContext: ObservableObject { try? self.mCore.start() } } - func onForeground() { - coreQueue.async { - // We can't rely on defaultAccount?.params?.isPublishEnabled - // as it will be modified by the SDK when changing the presence status - if self.mCore.config!.getBool(section: "app", key: "publish_presence", defaultValue: true) { - Log.info("App is in foreground, PUBLISHING presence as Online") - self.mCore.consolidatedPresence = ConsolidatedPresence.Online - } + + func updatePresence(core : Core, presence : ConsolidatedPresence) { + if core.config!.getBool(section: "app", key: "publish_presence", defaultValue: true) { + core.consolidatedPresence = presence } } - func onBackground() { + func onEnterForeground() { coreQueue.async { // We can't rely on defaultAccount?.params?.isPublishEnabled // as it will be modified by the SDK when changing the presence status - if self.mCore.config!.getBool(section: "app", key: "publish_presence", defaultValue: true) { - Log.info("App is in background, un-PUBLISHING presence info") - // We don't use ConsolidatedPresence.Busy but Offline to do an unsubscribe, - // Flexisip will handle the Busy status depending on other devices - self.mCore.consolidatedPresence = ConsolidatedPresence.Offline - } + + Log.info("App is in foreground, PUBLISHING presence as Online") + self.updatePresence(core: self.mCore, presence: ConsolidatedPresence.Online) + try? self.mCore.start() + } + } + + func onEnterBackground() { + coreQueue.async { + // We can't rely on defaultAccount?.params?.isPublishEnabled + // as it will be modified by the SDK when changing the presence status + Log.info("App is in background, un-PUBLISHING presence info") + + // We don't use ConsolidatedPresence.Busy but Offline to do an unsubscribe, + // Flexisip will handle the Busy status depending on other devices + self.updatePresence(core: self.mCore, presence: ConsolidatedPresence.Offline) + // self.mCore.iterate() + self.mCore.stop() } } diff --git a/Linphone/LinphoneApp.swift b/Linphone/LinphoneApp.swift index dd68f6b7b..dcc46dea3 100644 --- a/Linphone/LinphoneApp.swift +++ b/Linphone/LinphoneApp.swift @@ -23,11 +23,6 @@ import linphonesw let accountTokenNotification = Notification.Name("AccountCreationTokenReceived") class AppDelegate: NSObject, UIApplicationDelegate { - func application(_ application: UIApplication, - didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { - - return true - } func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { let tokenStr = deviceToken.map { String(format: "%02.2hhx", $0) }.joined() @@ -43,7 +38,7 @@ class AppDelegate: NSObject, UIApplicationDelegate { } func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { - Log.info("debugtrace -- Received background push notification, payload = \(userInfo.description)") + Log.info("Received background push notification, payload = \(userInfo.description)") let creationToken = (userInfo["customPayload"] as? NSDictionary)?["token"] as? String if let creationToken = creationToken { @@ -53,24 +48,14 @@ class AppDelegate: NSObject, UIApplicationDelegate { } func applicationWillTerminate(_ application: UIApplication) { - Log.info("debugtrace -- applicationWillTerminate") - CoreContext.shared.doOnCoreQueue { core in - Log.info("debugtrace COREQUEUE -- applicationWillTerminate") - core.stop() - } - } - - func applicationWillResignActive(_ application: UIApplication) { - Log.info("debugtrace -- applicationWillResignActive") - CoreContext.shared.doOnCoreQueue { core in - Log.info("debugtrace COREQUEUE -- applicationWillResignActive") - if let userDefaults = UserDefaults(suiteName: Config.appGroupName) { - userDefaults.set(false, forKey: "appactive") - } - try? Config.get().sync() - core.enterBackground() - if core.callsNb == 0 { + Log.info("IOS applicationWillTerminate") + CoreContext.shared.doOnCoreQueue(synchronous: true) { core in + Log.info("applicationWillTerminate - Stopping linphone core") + MagicSearchSingleton.shared.destroyMagicSearch() + if core.globalState != GlobalState.Off { core.stop() + } else { + Log.info("applicationWillTerminate - Core already stopped") } } } @@ -80,6 +65,7 @@ class AppDelegate: NSObject, UIApplicationDelegate { @main struct LinphoneApp: App { + @Environment(\.scenePhase) var scenePhase @UIApplicationDelegateAdaptor(AppDelegate.self) var delegate @ObservedObject private var coreContext = CoreContext.shared @ObservedObject private var sharedMainViewModel = SharedMainViewModel.shared @@ -133,6 +119,15 @@ struct LinphoneApp: App { callViewModel = CallViewModel() } } + }.onChange(of: scenePhase) { newPhase in + if newPhase == .active { + Log.info("Entering foreground") + coreContext.onEnterForeground() + } else if newPhase == .inactive { + } else if newPhase == .background { + Log.info("Entering background") + coreContext.onEnterBackground() + } } } } diff --git a/Linphone/UI/Main/ContentView.swift b/Linphone/UI/Main/ContentView.swift index aef8efb45..33529d2b3 100644 --- a/Linphone/UI/Main/ContentView.swift +++ b/Linphone/UI/Main/ContentView.swift @@ -710,25 +710,6 @@ struct ContentView: View { } orientation = newOrientation } - .onChange(of: scenePhase) { newPhase in - if newPhase == .active { - coreContext.onForeground() - /* - if !isShowStartCallFragment { - contactsManager.fetchContacts() - DispatchQueue.global().asyncAfter(deadline: .now() + 0.5) { - historyListViewModel.computeCallLogsList() - } - } - */ - print("Active") - } else if newPhase == .inactive { - print("Inactive") - } else if newPhase == .background { - coreContext.onBackground() - print("Background") - } - } } func openMenu() { diff --git a/Linphone/Utils/MagicSearchSingleton.swift b/Linphone/Utils/MagicSearchSingleton.swift index b65c09bf5..3593e26a2 100644 --- a/Linphone/Utils/MagicSearchSingleton.swift +++ b/Linphone/Utils/MagicSearchSingleton.swift @@ -43,6 +43,10 @@ final class MagicSearchSingleton: ObservableObject { var searchSubscription: AnyCancellable? + func destroyMagicSearch() { + magicSearch = nil + } + private init() { coreContext.doOnCoreQueue { core in self.domainDefaultAccount = core.defaultAccount?.params?.domain ?? "" From 3b20c47f1d342f9031f1a32b00effc8dcac27cd5 Mon Sep 17 00:00:00 2001 From: QuentinArguillere Date: Tue, 5 Mar 2024 16:20:00 +0100 Subject: [PATCH 13/18] For crashlytics : add informations in the msgNotificationService googleService-info.plist file --- .../GoogleService-Info.plist | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/msgNotificationService/GoogleService-Info.plist b/msgNotificationService/GoogleService-Info.plist index 98867592f..b493c102e 100644 --- a/msgNotificationService/GoogleService-Info.plist +++ b/msgNotificationService/GoogleService-Info.plist @@ -3,13 +3,13 @@ CLIENT_ID - + 221368768663-b8e48em01it3pt04vp1k0ddrgrcrju65.apps.googleusercontent.com REVERSED_CLIENT_ID - + com.googleusercontent.apps.221368768663-b8e48em01it3pt04vp1k0ddrgrcrju65 API_KEY - + AIzaSyDJTtlRCM7IqdVUU2dSIYq2YIsTz6bqnkI GCM_SENDER_ID - + 221368768663 PLIST_VERSION 1 BUNDLE_ID @@ -19,18 +19,18 @@ STORAGE_BUCKET linphone-iphone.appspot.com IS_ADS_ENABLED - + IS_ANALYTICS_ENABLED - + IS_APPINVITE_ENABLED - + IS_GCM_ENABLED - + IS_SIGNIN_ENABLED - + GOOGLE_APP_ID - + 1:221368768663:ios:ccf2c32eadcd3a0f9431d2 DATABASE_URL - + https://linphone-iphone.firebaseio.com - + \ No newline at end of file From 8e5a3b703f586c853a1f456d65d13970a1fa29a9 Mon Sep 17 00:00:00 2001 From: QuentinArguillere Date: Tue, 5 Mar 2024 16:21:39 +0100 Subject: [PATCH 14/18] Add "disable_chat_feature=0" key to rc files --- Linphone/Ressources/linphonerc-default | 1 + Linphone/Ressources/linphonerc-factory | 1 + 2 files changed, 2 insertions(+) diff --git a/Linphone/Ressources/linphonerc-default b/Linphone/Ressources/linphonerc-default index ea5356429..d0fb013ee 100644 --- a/Linphone/Ressources/linphonerc-default +++ b/Linphone/Ressources/linphonerc-default @@ -24,6 +24,7 @@ size=vga tunnel=disabled auto_start=1 record_aware=1 +disable_chat_feature=0 [tunnel] host= diff --git a/Linphone/Ressources/linphonerc-factory b/Linphone/Ressources/linphonerc-factory index 0abf8269d..eb16b25f2 100644 --- a/Linphone/Ressources/linphonerc-factory +++ b/Linphone/Ressources/linphonerc-factory @@ -45,6 +45,7 @@ store_friends=0 activation_code_length=4 prefer_basic_chat_room=1 record_aware=1 +disable_chat_feature=0 [account_creator] backend=1 From 66361d730941cab9049700dee8a7e782a0be5683 Mon Sep 17 00:00:00 2001 From: QuentinArguillere Date: Tue, 5 Mar 2024 16:22:23 +0100 Subject: [PATCH 15/18] Use centralised Config file in app extension --- .../NotificationService.swift | 25 +++++++------------ 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/msgNotificationService/NotificationService.swift b/msgNotificationService/NotificationService.swift index 45a81b621..ef3f6439e 100644 --- a/msgNotificationService/NotificationService.swift +++ b/msgNotificationService/NotificationService.swift @@ -25,14 +25,13 @@ import linphonesw import Firebase #endif -var APP_GROUP_ID = "group.org.linphone.phone.msgNotification" var LINPHONE_DUMMY_SUBJECT = "dummy subject" extension String { func getDisplayNameFromSipAddress(lc: Core) -> String? { Log.info("looking for display name for \(self)") - let defaults = UserDefaults.init(suiteName: APP_GROUP_ID) + let defaults = UserDefaults.init(suiteName: Config.appGroupName) let addressBook = defaults?.dictionary(forKey: "addressBook") if addressBook == nil { @@ -86,9 +85,13 @@ class NotificationService: UNNotificationServiceExtension { self.contentHandler = contentHandler bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent) + + LoggingService.Instance.logLevel = LogLevel.Debug + Factory.Instance.logCollectionPath = Factory.Instance.getConfigDir(context: nil) + Factory.Instance.enableLogCollection(state: LogCollectionState.Enabled) Log.info("[msgNotificationService] start msgNotificationService extension") /* - if (VFSUtil.vfsEnabled(groupName: APP_GROUP_ID) && !VFSUtil.activateVFS()) { + if (VFSUtil.vfsEnabled(groupName: Config.appGroupName) && !VFSUtil.activateVFS()) { VFSUtil.log("[VFS] Error unable to activate.", .error) } */ @@ -99,7 +102,7 @@ class NotificationService: UNNotificationServiceExtension { Log.info("received push payload : \(bestAttemptContent.userInfo.debugDescription)") /* - let defaults = UserDefaults.init(suiteName: APP_GROUP_ID) + let defaults = UserDefaults.init(suiteName: Config.appGroupName) if let chatroomsPushStatus = defaults?.dictionary(forKey: "chatroomsPushStatus") { let aps = bestAttemptContent.userInfo["aps"] as? NSDictionary let alert = aps?["alert"] as? NSDictionary @@ -130,8 +133,6 @@ class NotificationService: UNNotificationServiceExtension { } else { bestAttemptContent.body = chatRoom.subject! } - - bestAttemptContent.sound = UNNotificationSound(named: UNNotificationSoundName("msg.caf")) // TODO : temporary fix, to be removed after flexisip release contentHandler(bestAttemptContent) return } @@ -257,16 +258,8 @@ class NotificationService: UNNotificationServiceExtension { func createCore() { Log.info("[msgNotificationService] create core") - - let config = Config.newForSharedCore(appGroupId: APP_GROUP_ID, configFilename: "linphonerc", factoryConfigFilename: "") - - LoggingService.Instance.logLevel = LogLevel.Debug - let configDir = Factory.Instance.getConfigDir(context: nil) - - Factory.Instance.logCollectionPath = configDir - Factory.Instance.enableLogCollection(state: LogCollectionState.Enabled) - - lc = try? Factory.Instance.createSharedCoreWithConfig(config: config!, systemContext: nil, appGroupId: APP_GROUP_ID, mainCore: false) + + lc = try? Factory.Instance.createSharedCoreWithConfig(config: Config.get(), systemContext: nil, appGroupId: Config.appGroupName, mainCore: false) } func stopCore() { From 56caacfe1c9b9fe6a8eabf3296c7223acf8fdcf7 Mon Sep 17 00:00:00 2001 From: QuentinArguillere Date: Tue, 5 Mar 2024 17:39:33 +0100 Subject: [PATCH 16/18] =?UTF-8?q?Ajout=20des=20traductions=20anglaises=20e?= =?UTF-8?q?t=20fran=C3=A7aises=20pour=20les=20clefs=20IM=5FMSG=20et=20GC?= =?UTF-8?q?=5FMSG?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Linphone/Localizable.xcstrings | 37 ++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/Linphone/Localizable.xcstrings b/Linphone/Localizable.xcstrings index b5592f0d7..d2f5f86f4 100644 --- a/Linphone/Localizable.xcstrings +++ b/Linphone/Localizable.xcstrings @@ -337,6 +337,23 @@ }, "First name*" : { + }, + "GC_MSG" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "You have been added to a chat room" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vous avez été ajouté à une conversation" + } + } + } }, "Hang up call" : { @@ -352,6 +369,23 @@ }, "I understand" : { + }, + "IM_MSG" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "You have received a message" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vous avez reçu un message" + } + } + } }, "Incoming call" : { @@ -376,6 +410,9 @@ }, "Job title" : { + }, + "Key" : { + "extractionState" : "manual" }, "Last name" : { From 533bc26d6db60d6df4c7bd09c60fb16b56ea12ce Mon Sep 17 00:00:00 2001 From: QuentinArguillere Date: Tue, 5 Mar 2024 17:40:02 +0100 Subject: [PATCH 17/18] =?UTF-8?q?R=C3=A9activation=20des=20settings=20de?= =?UTF-8?q?=20lime=20et=20de=20conf=C3=A9rence=20au=20login=20des=20compte?= =?UTF-8?q?s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Linphone/UI/Assistant/Viewmodel/AccountLoginViewModel.swift | 6 ------ 1 file changed, 6 deletions(-) diff --git a/Linphone/UI/Assistant/Viewmodel/AccountLoginViewModel.swift b/Linphone/UI/Assistant/Viewmodel/AccountLoginViewModel.swift index 5c2a3f1ad..57dd6688d 100644 --- a/Linphone/UI/Assistant/Viewmodel/AccountLoginViewModel.swift +++ b/Linphone/UI/Assistant/Viewmodel/AccountLoginViewModel.swift @@ -98,12 +98,6 @@ class AccountLoginViewModel: ObservableObject { #endif accountParams.pushNotificationConfig?.provider = "apns" + pushEnvironment - // Temporary disable these features are they are not used for 6.0 first version - accountParams.conferenceFactoryUri = nil - accountParams.conferenceFactoryAddress = nil - accountParams.audioVideoConferenceFactoryAddress = nil - accountParams.limeServerUrl = nil - // Now that our AccountParams is configured, we can create the Account object let account = try core.createAccount(params: accountParams) From 8d6f09658251f463af731c2f38a8c5f5bb85acd9 Mon Sep 17 00:00:00 2001 From: QuentinArguillere Date: Thu, 7 Mar 2024 12:01:04 +0100 Subject: [PATCH 18/18] Disable background notification process for now (will be used later for account creation token processing) --- Linphone/LinphoneApp.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Linphone/LinphoneApp.swift b/Linphone/LinphoneApp.swift index dcc46dea3..a5135b9c1 100644 --- a/Linphone/LinphoneApp.swift +++ b/Linphone/LinphoneApp.swift @@ -39,12 +39,12 @@ class AppDelegate: NSObject, UIApplicationDelegate { func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { Log.info("Received background push notification, payload = \(userInfo.description)") - + /* let creationToken = (userInfo["customPayload"] as? NSDictionary)?["token"] as? String if let creationToken = creationToken { NotificationCenter.default.post(name: accountTokenNotification, object: nil, userInfo: ["token": creationToken]) } - completionHandler(UIBackgroundFetchResult.newData) + completionHandler(UIBackgroundFetchResult.newData)*/ } func applicationWillTerminate(_ application: UIApplication) {