mirror of
https://gitlab.linphone.org/BC/public/linphone-iphone.git
synced 2026-01-17 11:08:06 +00:00
Merge remote-tracking branch 'refs/remotes/origin/master'
Conflicts: Linphone/Core/CoreContext.swift Linphone/Localizable.xcstrings Linphone/UI/Assistant/Viewmodel/AccountLoginViewModel.swift
This commit is contained in:
commit
bf4e4042d3
19 changed files with 756 additions and 85 deletions
|
|
@ -7,14 +7,22 @@
|
|||
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 */; };
|
||||
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 */; };
|
||||
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 */; };
|
||||
D70959F12B8DF3EC0014AC0B /* ConversationModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D70959F02B8DF3EC0014AC0B /* ConversationModel.swift */; };
|
||||
D70A26EE2B7CF60B006CC8FC /* ConversationsListBottomSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = D70A26ED2B7CF60B006CC8FC /* ConversationsListBottomSheet.swift */; };
|
||||
|
|
@ -112,10 +120,38 @@
|
|||
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 = "<group>"; };
|
||||
660D8A702B517D260092694D /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = "<group>"; };
|
||||
662B69D82B25DE18007118BF /* TelecomManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TelecomManager.swift; sourceTree = "<group>"; };
|
||||
662B69DA2B25DE25007118BF /* ProviderDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProviderDelegate.swift; sourceTree = "<group>"; };
|
||||
667E5D802B8E444D00EBCFC4 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = "<group>"; };
|
||||
6691CA7D2B839C2D00B2A7B8 /* NotificationService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotificationService.swift; sourceTree = "<group>"; };
|
||||
66C491F82B24D25A00CEA16D /* ConfigExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConfigExtension.swift; sourceTree = "<group>"; };
|
||||
66C491FA2B24D32600CEA16D /* CoreExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreExtension.swift; sourceTree = "<group>"; };
|
||||
66C491FC2B24D36500CEA16D /* AudioRouteUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioRouteUtils.swift; sourceTree = "<group>"; };
|
||||
|
|
@ -222,6 +258,13 @@
|
|||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
660AAF782B839271004C0FA6 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
D719ABB02ABC67BF00B41C10 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
|
|
@ -232,6 +275,16 @@
|
|||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
660AAF7C2B839272004C0FA6 /* msgNotificationService */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
667E5D802B8E444D00EBCFC4 /* GoogleService-Info.plist */,
|
||||
6691CA7D2B839C2D00B2A7B8 /* NotificationService.swift */,
|
||||
660AAF842B8392E0004C0FA6 /* msgNotificationService.entitlements */,
|
||||
);
|
||||
path = msgNotificationService;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
662B69D72B25DDF6007118BF /* TelecomManager */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
|
@ -294,6 +347,7 @@
|
|||
children = (
|
||||
660D8A702B517D260092694D /* GoogleService-Info.plist */,
|
||||
D719ABB52ABC67BF00B41C10 /* Linphone */,
|
||||
660AAF7C2B839272004C0FA6 /* msgNotificationService */,
|
||||
D719ABB42ABC67BF00B41C10 /* Products */,
|
||||
A31AF2AB8C6A3D7B7EA3B424 /* Pods */,
|
||||
);
|
||||
|
|
@ -303,6 +357,7 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
D719ABB32ABC67BF00B41C10 /* Linphone.app */,
|
||||
660AAF7B2B839271004C0FA6 /* msgNotificationService.appex */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -619,12 +674,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 */,
|
||||
|
|
@ -632,6 +705,7 @@
|
|||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
660AAF7E2B839272004C0FA6 /* PBXTargetDependency */,
|
||||
);
|
||||
name = Linphone;
|
||||
productName = Linphone;
|
||||
|
|
@ -648,6 +722,10 @@
|
|||
LastSwiftUpdateCheck = 1430;
|
||||
LastUpgradeCheck = 1430;
|
||||
TargetAttributes = {
|
||||
660AAF7A2B839271004C0FA6 = {
|
||||
CreatedOnToolsVersion = 15.0.1;
|
||||
LastSwiftMigration = 1500;
|
||||
};
|
||||
D719ABB22ABC67BF00B41C10 = {
|
||||
CreatedOnToolsVersion = 14.3.1;
|
||||
};
|
||||
|
|
@ -667,11 +745,21 @@
|
|||
projectRoot = "";
|
||||
targets = (
|
||||
D719ABB22ABC67BF00B41C10 /* Linphone */,
|
||||
660AAF7A2B839271004C0FA6 /* msgNotificationService */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
660AAF792B839271004C0FA6 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
667E5D7F2B8E430C00EBCFC4 /* linphonerc-factory in Resources */,
|
||||
667E5D812B8E444E00EBCFC4 /* GoogleService-Info.plist in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
D719ABB12ABC67BF00B41C10 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
|
|
@ -741,6 +829,18 @@
|
|||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
660AAF772B839271004C0FA6 /* Sources */ = {
|
||||
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;
|
||||
};
|
||||
D719ABAF2ABC67BF00B41C10 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
|
|
@ -839,7 +939,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 = {
|
||||
|
|
@ -958,6 +1146,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;
|
||||
|
|
@ -1013,6 +1202,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;
|
||||
|
|
@ -1064,6 +1254,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 = (
|
||||
|
|
|
|||
|
|
@ -26,6 +26,10 @@ import Combine
|
|||
import UniformTypeIdentifiers
|
||||
import Network
|
||||
|
||||
#if USE_CRASHLYTICS
|
||||
import Firebase
|
||||
#endif
|
||||
|
||||
final class CoreContext: ObservableObject {
|
||||
|
||||
static let shared = CoreContext()
|
||||
|
|
@ -66,36 +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
|
||||
|
|
@ -169,9 +172,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 {
|
||||
|
|
@ -198,8 +198,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
|
||||
|
|
@ -266,27 +269,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()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@
|
|||
<true/>
|
||||
<key>ITSEncryptionExportComplianceCode</key>
|
||||
<string>b5cb085f-772a-4a4f-8c77-5d1332b1f93f</string>
|
||||
<key>NSSupportsSuddenTermination</key>
|
||||
<false/>
|
||||
<key>UIAppFonts</key>
|
||||
<array>
|
||||
<string>NotoSans-Light.ttf</string>
|
||||
|
|
|
|||
|
|
@ -13,9 +13,12 @@
|
|||
<string>group.belledonne-communications.linphone</string>
|
||||
<string>group.org.linphone.phone.linphoneExtension</string>
|
||||
<string>group.org.linphone.phone.msgNotification</string>
|
||||
<string>group.org.linphone.phone.logs</string>
|
||||
</array>
|
||||
<key>com.apple.security.files.user-selected.read-only</key>
|
||||
<true/>
|
||||
<key>keychain-access-groups</key>
|
||||
<array>
|
||||
<string>$(AppIdentifierPrefix)org.linphone.phone</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
|
|||
|
|
@ -18,23 +18,54 @@
|
|||
*/
|
||||
|
||||
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
|
||||
|
||||
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("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)*/
|
||||
}
|
||||
|
||||
func applicationWillTerminate(_ application: UIApplication) {
|
||||
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")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@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
|
||||
|
|
@ -96,6 +127,15 @@ struct LinphoneApp: App {
|
|||
conversationViewModel = ConversationViewModel()
|
||||
}
|
||||
}
|
||||
}.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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -340,6 +340,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" : {
|
||||
|
||||
|
|
@ -355,6 +372,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" : {
|
||||
|
||||
|
|
@ -379,6 +413,9 @@
|
|||
},
|
||||
"Job title" : {
|
||||
|
||||
},
|
||||
"Key" : {
|
||||
"extractionState" : "manual"
|
||||
},
|
||||
"Last name" : {
|
||||
|
||||
|
|
@ -656,4 +693,4 @@
|
|||
}
|
||||
},
|
||||
"version" : "1.0"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
<entry name="conference_factory_uri" overwrite="true">sip:conference-factory@sip.linphone.org</entry>
|
||||
<entry name="audio_video_conference_factory_uri" overwrite="true">sip:videoconference-factory@sip.linphone.org</entry>
|
||||
<entry name="push_notification_allowed" overwrite="true">1</entry>
|
||||
<entry name="remote_push_notification_allowed" overwrite="true">1</entry>
|
||||
<entry name="cpim_in_basic_chat_rooms_enabled" overwrite="true">1</entry>
|
||||
<entry name="rtp_bundle" overwrite="true">1</entry>
|
||||
<entry name="lime_server_url" overwrite="true">https://lime.linphone.org/lime-server/lime-server.php</entry>
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ size=vga
|
|||
tunnel=disabled
|
||||
auto_start=1
|
||||
record_aware=1
|
||||
disable_chat_feature=0
|
||||
|
||||
[tunnel]
|
||||
host=
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -894,25 +894,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() {
|
||||
|
|
|
|||
|
|
@ -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: "")
|
||||
|
|
|
|||
|
|
@ -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 ?? ""
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
9
Podfile
9
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|
|
||||
|
|
|
|||
36
msgNotificationService/GoogleService-Info.plist
Normal file
36
msgNotificationService/GoogleService-Info.plist
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CLIENT_ID</key>
|
||||
<string>221368768663-b8e48em01it3pt04vp1k0ddrgrcrju65.apps.googleusercontent.com</string>
|
||||
<key>REVERSED_CLIENT_ID</key>
|
||||
<string>com.googleusercontent.apps.221368768663-b8e48em01it3pt04vp1k0ddrgrcrju65</string>
|
||||
<key>API_KEY</key>
|
||||
<string>AIzaSyDJTtlRCM7IqdVUU2dSIYq2YIsTz6bqnkI</string>
|
||||
<key>GCM_SENDER_ID</key>
|
||||
<string>221368768663</string>
|
||||
<key>PLIST_VERSION</key>
|
||||
<string>1</string>
|
||||
<key>BUNDLE_ID</key>
|
||||
<string>org.linphone.phone.msgNotificationService</string>
|
||||
<key>PROJECT_ID</key>
|
||||
<string>linphone-iphone</string>
|
||||
<key>STORAGE_BUCKET</key>
|
||||
<string>linphone-iphone.appspot.com</string>
|
||||
<key>IS_ADS_ENABLED</key>
|
||||
<false></false>
|
||||
<key>IS_ANALYTICS_ENABLED</key>
|
||||
<false></false>
|
||||
<key>IS_APPINVITE_ENABLED</key>
|
||||
<true></true>
|
||||
<key>IS_GCM_ENABLED</key>
|
||||
<true></true>
|
||||
<key>IS_SIGNIN_ENABLED</key>
|
||||
<true></true>
|
||||
<key>GOOGLE_APP_ID</key>
|
||||
<string>1:221368768663:ios:ccf2c32eadcd3a0f9431d2</string>
|
||||
<key>DATABASE_URL</key>
|
||||
<string>https://linphone-iphone.firebaseio.com</string>
|
||||
</dict>
|
||||
</plist>
|
||||
31
msgNotificationService/Info.plist
Normal file
31
msgNotificationService/Info.plist
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>msgNotificationService</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>$(MARKETING_VERSION)</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
<key>NSExtension</key>
|
||||
<dict>
|
||||
<key>NSExtensionPointIdentifier</key>
|
||||
<string>com.apple.usernotifications.service</string>
|
||||
<key>NSExtensionPrincipalClass</key>
|
||||
<string>$(PRODUCT_MODULE_NAME).NotificationService</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
284
msgNotificationService/NotificationService.swift
Normal file
284
msgNotificationService/NotificationService.swift
Normal file
|
|
@ -0,0 +1,284 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// swiftlint:disable identifier_name
|
||||
|
||||
import UserNotifications
|
||||
import linphonesw
|
||||
#if USE_CRASHLYTICS
|
||||
import Firebase
|
||||
#endif
|
||||
|
||||
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: Config.appGroupName)
|
||||
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?
|
||||
}
|
||||
|
||||
class NotificationService: UNNotificationServiceExtension {
|
||||
|
||||
var contentHandler: ((UNNotificationContent) -> Void)?
|
||||
var bestAttemptContent: UNMutableNotificationContent?
|
||||
|
||||
var lc: Core?
|
||||
|
||||
override init() {
|
||||
super.init()
|
||||
#if USE_CRASHLYTICS
|
||||
FirebaseApp.configure()
|
||||
#endif
|
||||
}
|
||||
|
||||
override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
|
||||
|
||||
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: Config.appGroupName) && !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: Config.appGroupName)
|
||||
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!
|
||||
}
|
||||
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 = ""
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
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")
|
||||
|
||||
lc = try? Factory.Instance.createSharedCoreWithConfig(config: Config.get(), systemContext: nil, appGroupId: Config.appGroupName, 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
|
||||
14
msgNotificationService/msgNotificationService.entitlements
Normal file
14
msgNotificationService/msgNotificationService.entitlements
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.application-groups</key>
|
||||
<array>
|
||||
<string>group.org.linphone.phone.msgNotification</string>
|
||||
</array>
|
||||
<key>keychain-access-groups</key>
|
||||
<array>
|
||||
<string>$(AppIdentifierPrefix)org.linphone.phone</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
Loading…
Add table
Reference in a new issue