mirror of
https://gitlab.linphone.org/BC/public/linphone-iphone.git
synced 2026-04-17 20:08:31 +00:00
Merge branch 'feature/mdm' into 'release/6.2'
MDM configuration See merge request BC/public/linphone-iphone!414
This commit is contained in:
commit
30b025fadf
18 changed files with 1549 additions and 21 deletions
|
|
@ -65,7 +65,60 @@ class CoreContext: ObservableObject {
|
||||||
do {
|
do {
|
||||||
try initialiseCore()
|
try initialiseCore()
|
||||||
} catch {
|
} catch {
|
||||||
|
|
||||||
|
}
|
||||||
|
observeMDMNotifications()
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - MDM notifications
|
||||||
|
|
||||||
|
private func observeMDMNotifications() {
|
||||||
|
NotificationCenter.default.addObserver(self, selector: #selector(onMDMConfigurationApplied(_:)), name: MDMManager.configurationAppliedNotification, object: nil)
|
||||||
|
NotificationCenter.default.addObserver(self, selector: #selector(onMDMConfigurationRemoved), name: MDMManager.configurationRemovedNotification, object: nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc private func onMDMConfigurationApplied(_ notification: Notification) {
|
||||||
|
Log.info("[CoreContext] MDM configuration applied, refreshing configuration")
|
||||||
|
CoreContext.shared.performActionOnCoreQueueWhenCoreIsStarted { core in
|
||||||
|
self.handleConfigurationChanged(status: .Successful)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc private func onMDMConfigurationRemoved() {
|
||||||
|
doOnCoreQueue { core in
|
||||||
|
Log.info("[CoreContext] MDM configuration removed, re-initializing app to default state")
|
||||||
|
var startCore = false
|
||||||
|
if core.globalState == .On {
|
||||||
|
core.stop()
|
||||||
|
startCore = true
|
||||||
|
}
|
||||||
|
AppServices.resetConfig()
|
||||||
|
self.mCore.config?.reload()
|
||||||
|
if startCore {
|
||||||
|
try?core.start()
|
||||||
|
}
|
||||||
|
self.handleConfigurationChanged(status: .Successful)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Shared handler for configuration changes (both from core provisioning and MDM).
|
||||||
|
private func handleConfigurationChanged(status: ConfiguringState) {
|
||||||
|
let themeMainColor = AppServices.corePreferences.themeMainColor
|
||||||
|
SharedMainViewModel.shared.updateConfigChanges()
|
||||||
|
if status == .Successful {
|
||||||
|
var accountModels: [AccountModel] = []
|
||||||
|
for account in self.mCore.accountList {
|
||||||
|
accountModels.append(AccountModel(account: account, core: self.mCore))
|
||||||
|
}
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
self.accounts = accountModels
|
||||||
|
if accountModels.isEmpty {
|
||||||
|
self.loggingInProgress = false
|
||||||
|
self.loggedIn = false
|
||||||
|
}
|
||||||
|
ThemeManager.shared.applyTheme(named: themeMainColor)
|
||||||
|
self.reloadID = UUID()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -143,8 +196,14 @@ class CoreContext: ObservableObject {
|
||||||
Log.info("Found existing linphonerc file, skip copying of linphonerc-default configuration")
|
Log.info("Found existing linphonerc file, skip copying of linphonerc-default configuration")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MDMManager.shared.loadXMLConfigFromMdm(config: AppServices.config)
|
||||||
|
|
||||||
self.mCore = try? Factory.Instance.createSharedCoreWithConfig(config: AppServices.config, systemContext: Unmanaged.passUnretained(coreQueue).toOpaque(), appGroupId: SharedMainViewModel.appGroupName, mainCore: true)
|
self.mCore = try? Factory.Instance.createSharedCoreWithConfig(config: AppServices.config, systemContext: Unmanaged.passUnretained(coreQueue).toOpaque(), appGroupId: SharedMainViewModel.appGroupName, mainCore: true)
|
||||||
|
|
||||||
|
MDMManager.shared.applyMdmConfigToCore(core: self.mCore)
|
||||||
|
self.startObservingMDMConfigurationUpdates()
|
||||||
|
|
||||||
|
|
||||||
self.mCore.callkitEnabled = true
|
self.mCore.callkitEnabled = true
|
||||||
self.mCore.pushNotificationEnabled = true
|
self.mCore.pushNotificationEnabled = true
|
||||||
|
|
@ -348,19 +407,7 @@ class CoreContext: ObservableObject {
|
||||||
}
|
}
|
||||||
}, onConfiguringStatus: { (_: Core, status: ConfiguringState, message: String) in
|
}, onConfiguringStatus: { (_: Core, status: ConfiguringState, message: String) in
|
||||||
Log.info("New configuration state is \(status) = \(message)\n")
|
Log.info("New configuration state is \(status) = \(message)\n")
|
||||||
let themeMainColor = AppServices.corePreferences.themeMainColor
|
self.handleConfigurationChanged(status: status)
|
||||||
SharedMainViewModel.shared.updateConfigChanges()
|
|
||||||
DispatchQueue.main.async {
|
|
||||||
if status == ConfiguringState.Successful {
|
|
||||||
var accountModels: [AccountModel] = []
|
|
||||||
for account in self.mCore.accountList {
|
|
||||||
accountModels.append(AccountModel(account: account, core: self.mCore))
|
|
||||||
}
|
|
||||||
self.accounts = accountModels
|
|
||||||
ThemeManager.shared.applyTheme(named: themeMainColor)
|
|
||||||
self.reloadID = UUID()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, onLogCollectionUploadStateChanged: { (_: Core, _: Core.LogCollectionUploadState, info: String) in
|
}, onLogCollectionUploadStateChanged: { (_: Core, _: Core.LogCollectionUploadState, info: String) in
|
||||||
if info.starts(with: "https") {
|
if info.starts(with: "https") {
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
|
|
@ -563,6 +610,24 @@ class CoreContext: ObservableObject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func startObservingMDMConfigurationUpdates() {
|
||||||
|
NotificationCenter.default.addObserver(
|
||||||
|
self,
|
||||||
|
selector: #selector(mdmConfigDidChange),
|
||||||
|
name: UserDefaults.didChangeNotification,
|
||||||
|
object: nil
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc private func mdmConfigDidChange() {
|
||||||
|
guard MDMManager.shared.managedConfigChangedSinceLastCheck() else { return }
|
||||||
|
CoreContext.shared.doOnCoreQueue { core in
|
||||||
|
MDMManager.shared.applyMdmConfigToCore(core: core)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum AppServices {
|
enum AppServices {
|
||||||
|
|
@ -589,8 +654,30 @@ enum AppServices {
|
||||||
}
|
}
|
||||||
return config
|
return config
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static func resetConfig() {
|
||||||
|
if let rcDir = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: SharedMainViewModel.appGroupName)?
|
||||||
|
.appendingPathComponent("Library/Preferences/linphone") {
|
||||||
|
let rcFileUrl = rcDir.appendingPathComponent("linphonerc")
|
||||||
|
do {
|
||||||
|
try FileManager.default.createDirectory(at: rcDir, withIntermediateDirectories: true)
|
||||||
|
if let pathToDefaultConfig = Bundle.main.path(forResource: "linphonerc-default", ofType: nil) {
|
||||||
|
if FileManager.default.fileExists(atPath: rcFileUrl.path) {
|
||||||
|
try FileManager.default.removeItem(at: rcFileUrl)
|
||||||
|
}
|
||||||
|
try FileManager.default.copyItem(at: URL(fileURLWithPath: pathToDefaultConfig), to: rcFileUrl)
|
||||||
|
Log.info("Successfully copied linphonerc-default configuration")
|
||||||
|
_config = nil
|
||||||
|
let _ = configIfAvailable
|
||||||
|
corePreferences = CorePreferences(config: config)
|
||||||
|
}
|
||||||
|
} catch let error {
|
||||||
|
Log.error("Failed to copy default linphonerc file: \(error.localizedDescription)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static let corePreferences = CorePreferences(config: config)
|
static var corePreferences = CorePreferences(config: config)
|
||||||
}
|
}
|
||||||
|
|
||||||
// swiftlint:enable line_length
|
// swiftlint:enable line_length
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,7 @@ class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDele
|
||||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
||||||
// Set up notifications
|
// Set up notifications
|
||||||
UNUserNotificationCenter.current().delegate = self
|
UNUserNotificationCenter.current().delegate = self
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -159,6 +159,9 @@ struct LinphoneApp: App {
|
||||||
private let voipRegistry = PKPushRegistry(queue: coreQueue)
|
private let voipRegistry = PKPushRegistry(queue: coreQueue)
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
|
#if DEBUG
|
||||||
|
LinphoneApp.applyUITestMDMConfigIfNeeded()
|
||||||
|
#endif
|
||||||
if !configAvailable {
|
if !configAvailable {
|
||||||
voipRegistry.delegate = earlyPushDelegate
|
voipRegistry.delegate = earlyPushDelegate
|
||||||
voipRegistry.desiredPushTypes = [.voIP]
|
voipRegistry.desiredPushTypes = [.voIP]
|
||||||
|
|
@ -168,6 +171,26 @@ struct LinphoneApp: App {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
/// UI-test hook: reads `UITEST_MDM_CONFIG` (JSON) or `UITEST_MDM_CONFIG_CLEAR=1` from
|
||||||
|
/// the launch environment and writes it to the managed config key before MDMManager runs.
|
||||||
|
/// Only active in DEBUG builds.
|
||||||
|
private static func applyUITestMDMConfigIfNeeded() {
|
||||||
|
let env = ProcessInfo.processInfo.environment
|
||||||
|
let key = "com.apple.configuration.managed"
|
||||||
|
if env["UITEST_MDM_CONFIG_CLEAR"] == "1" {
|
||||||
|
UserDefaults.standard.removeObject(forKey: key)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
guard let json = env["UITEST_MDM_CONFIG"],
|
||||||
|
let data = json.data(using: .utf8),
|
||||||
|
let dict = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
UserDefaults.standard.set(dict, forKey: key)
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
var body: some Scene {
|
var body: some Scene {
|
||||||
WindowGroup {
|
WindowGroup {
|
||||||
if configAvailable {
|
if configAvailable {
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,8 @@ struct SplashScreen: View {
|
||||||
.foregroundColor(ThemeManager.shared.currentTheme.main500)
|
.foregroundColor(ThemeManager.shared.currentTheme.main500)
|
||||||
|
|
||||||
if showSpinner {
|
if showSpinner {
|
||||||
ProgressView()
|
PopupLoadingView()
|
||||||
|
.background(.black.opacity(0.65))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||||
|
|
|
||||||
|
|
@ -180,6 +180,7 @@ struct PermissionsFragment: View {
|
||||||
)
|
)
|
||||||
.frame(maxWidth: SharedMainViewModel.shared.maxWidth)
|
.frame(maxWidth: SharedMainViewModel.shared.maxWidth)
|
||||||
.padding(.horizontal)
|
.padding(.horizontal)
|
||||||
|
.accessibilityIdentifier("permissions_skip_button")
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
permissionManager.getPermissions()
|
permissionManager.getPermissions()
|
||||||
|
|
|
||||||
|
|
@ -370,7 +370,7 @@ struct ContentView: View {
|
||||||
|
|
||||||
Button(action: {
|
Button(action: {
|
||||||
resetFilter()
|
resetFilter()
|
||||||
|
|
||||||
sharedMainViewModel.changeIndexView(indexViewInt: 1)
|
sharedMainViewModel.changeIndexView(indexViewInt: 1)
|
||||||
sharedMainViewModel.displayedFriend = nil
|
sharedMainViewModel.displayedFriend = nil
|
||||||
sharedMainViewModel.displayedConversation = nil
|
sharedMainViewModel.displayedConversation = nil
|
||||||
|
|
@ -395,6 +395,7 @@ struct ContentView: View {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.padding(.top)
|
.padding(.top)
|
||||||
|
.accessibilityIdentifier("bottom_bar_calls_button")
|
||||||
}
|
}
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
@ -435,7 +436,7 @@ struct ContentView: View {
|
||||||
.resizable()
|
.resizable()
|
||||||
.foregroundStyle(sharedMainViewModel.indexView == 2 ? Color.orangeMain500 : Color.grayMain2c600)
|
.foregroundStyle(sharedMainViewModel.indexView == 2 ? Color.orangeMain500 : Color.grayMain2c600)
|
||||||
.frame(width: 25, height: 25)
|
.frame(width: 25, height: 25)
|
||||||
|
|
||||||
if sharedMainViewModel.indexView == 2 {
|
if sharedMainViewModel.indexView == 2 {
|
||||||
Text("bottom_navigation_conversations_label")
|
Text("bottom_navigation_conversations_label")
|
||||||
.default_text_style_700(styleSize: 10)
|
.default_text_style_700(styleSize: 10)
|
||||||
|
|
@ -446,6 +447,7 @@ struct ContentView: View {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.padding(.top)
|
.padding(.top)
|
||||||
|
.accessibilityIdentifier("bottom_bar_chat_button")
|
||||||
}
|
}
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ struct WelcomeView: View {
|
||||||
Text("welcome_carousel_skip")
|
Text("welcome_carousel_skip")
|
||||||
.underline()
|
.underline()
|
||||||
.default_text_style_600(styleSize: 15)
|
.default_text_style_600(styleSize: 15)
|
||||||
|
|
||||||
})
|
})
|
||||||
.padding(.top, -35)
|
.padding(.top, -35)
|
||||||
.padding(.trailing, 20)
|
.padding(.trailing, 20)
|
||||||
|
|
@ -64,6 +64,7 @@ struct WelcomeView: View {
|
||||||
self.index = 2
|
self.index = 2
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
.accessibilityIdentifier("welcome_skip_button")
|
||||||
Text("welcome_page_title")
|
Text("welcome_page_title")
|
||||||
.default_text_style_800(styleSize: 35)
|
.default_text_style_800(styleSize: 35)
|
||||||
.padding(.trailing, 100)
|
.padding(.trailing, 100)
|
||||||
|
|
|
||||||
173
Linphone/Utils/MDMManager.swift
Normal file
173
Linphone/Utils/MDMManager.swift
Normal file
|
|
@ -0,0 +1,173 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010-2023 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import CryptoKit
|
||||||
|
import linphonesw
|
||||||
|
|
||||||
|
class MDMManager {
|
||||||
|
|
||||||
|
static let shared = MDMManager()
|
||||||
|
|
||||||
|
static let configurationRemovedNotification = Notification.Name("MDMManager.configurationRemoved")
|
||||||
|
static let configurationAppliedNotification = Notification.Name("MDMManager.configurationApplied")
|
||||||
|
|
||||||
|
private static let hasMDMConfigKey = "MDMManager.hasMDMConfig"
|
||||||
|
private static let lastXMLConfigSHA256Key = "MDMManager.lastXMLConfigSHA256"
|
||||||
|
private static let lastCoreConfigSHA256Key = "MDMManager.lastCoreConfigSHA256"
|
||||||
|
|
||||||
|
private var hasMDMConfig: Bool {
|
||||||
|
get { UserDefaults.standard.bool(forKey: MDMManager.hasMDMConfigKey) }
|
||||||
|
set {
|
||||||
|
guard UserDefaults.standard.bool(forKey: MDMManager.hasMDMConfigKey) != newValue else { return }
|
||||||
|
UserDefaults.standard.set(newValue, forKey: MDMManager.hasMDMConfigKey)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var lastXMLConfigSHA256: String? {
|
||||||
|
get { UserDefaults.standard.string(forKey: MDMManager.lastXMLConfigSHA256Key) }
|
||||||
|
set {
|
||||||
|
guard UserDefaults.standard.string(forKey: MDMManager.lastXMLConfigSHA256Key) != newValue else { return }
|
||||||
|
UserDefaults.standard.set(newValue, forKey: MDMManager.lastXMLConfigSHA256Key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var lastCoreConfigSHA256: String? {
|
||||||
|
get { UserDefaults.standard.string(forKey: MDMManager.lastCoreConfigSHA256Key) }
|
||||||
|
set {
|
||||||
|
guard UserDefaults.standard.string(forKey: MDMManager.lastCoreConfigSHA256Key) != newValue else { return }
|
||||||
|
UserDefaults.standard.set(newValue, forKey: MDMManager.lastCoreConfigSHA256Key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var isApplyingConfig = false
|
||||||
|
|
||||||
|
private var lastSeenManagedConfigSignature: String?
|
||||||
|
|
||||||
|
func managedConfigChangedSinceLastCheck() -> Bool {
|
||||||
|
let signature: String
|
||||||
|
if let mdmConfig = UserDefaults.standard.dictionary(forKey: "com.apple.configuration.managed") {
|
||||||
|
signature = sha256Hash(of: mdmConfig)
|
||||||
|
} else {
|
||||||
|
signature = ""
|
||||||
|
}
|
||||||
|
if signature == lastSeenManagedConfigSignature { return false }
|
||||||
|
lastSeenManagedConfigSignature = signature
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadXMLConfigFromMdm(config: Config) {
|
||||||
|
guard let mdmConfig = UserDefaults.standard.dictionary(forKey: "com.apple.configuration.managed"),
|
||||||
|
let xmlConfig = mdmConfig["xml-config"] as? String else {
|
||||||
|
lastXMLConfigSHA256 = nil
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let hash = sha256Hash(of: ["xml-config": xmlConfig])
|
||||||
|
if hash == lastXMLConfigSHA256 {
|
||||||
|
Log.info("[MDMManager] xml-config unchanged (SHA256: \(hash)), skipping")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
lastXMLConfigSHA256 = hash
|
||||||
|
|
||||||
|
do {
|
||||||
|
try config.loadFromXmlString(buffer: xmlConfig)
|
||||||
|
Log.info("[MDMManager] xml-config applied (\(xmlConfig.count) chars)")
|
||||||
|
} catch let error {
|
||||||
|
Log.error("[MDMManager] Failed loading xml-config: error = \(error) xml = \(xmlConfig)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func applyMdmConfigToCore(core: Core) {
|
||||||
|
guard !isApplyingConfig else { return }
|
||||||
|
isApplyingConfig = true
|
||||||
|
defer {
|
||||||
|
isApplyingConfig = false
|
||||||
|
_ = managedConfigChangedSinceLastCheck()
|
||||||
|
}
|
||||||
|
|
||||||
|
loadXMLConfigFromMdm(config: core.config!)
|
||||||
|
|
||||||
|
guard let mdmConfig = UserDefaults.standard.dictionary(forKey: "com.apple.configuration.managed") else {
|
||||||
|
if hasMDMConfig {
|
||||||
|
Log.info("[MDMManager] Managed configuration was removed")
|
||||||
|
lastXMLConfigSHA256 = nil
|
||||||
|
lastCoreConfigSHA256 = nil
|
||||||
|
hasMDMConfig = false
|
||||||
|
handleConfigurationRemoved()
|
||||||
|
} else {
|
||||||
|
Log.info("[MDMManager] Managed configuration is empty")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
hasMDMConfig = true
|
||||||
|
|
||||||
|
let subset: [String: Any] = [
|
||||||
|
"root-ca": mdmConfig["root-ca"] ?? "",
|
||||||
|
"config-uri": mdmConfig["config-uri"] ?? ""
|
||||||
|
]
|
||||||
|
let hash = sha256Hash(of: subset)
|
||||||
|
if hash == lastCoreConfigSHA256 {
|
||||||
|
Log.info("[MDMManager] root-ca/config-uri unchanged (SHA256: \(hash)), skipping")
|
||||||
|
NotificationCenter.default.post(name: MDMManager.configurationAppliedNotification, object: self, userInfo: ["config": mdmConfig])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
lastCoreConfigSHA256 = hash
|
||||||
|
|
||||||
|
let currentProvisioningUri = core.provisioningUri
|
||||||
|
|
||||||
|
if let rootCa = mdmConfig["root-ca"] as? String {
|
||||||
|
core.rootCaData = rootCa
|
||||||
|
Log.info("[MDMManager] root-ca applied (\(rootCa.count) chars)")
|
||||||
|
}
|
||||||
|
if let configUri = mdmConfig["config-uri"] as? String {
|
||||||
|
do {
|
||||||
|
if configUri != currentProvisioningUri {
|
||||||
|
try core.setProvisioninguri(newValue: configUri)
|
||||||
|
Log.info("[MDMManager] config-uri applied \(configUri)")
|
||||||
|
}
|
||||||
|
} catch let error {
|
||||||
|
Log.error("[MDMManager] Failed setting provisioning URI: error = \(error) configUri = \(configUri)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if core.globalState == .On {
|
||||||
|
do {
|
||||||
|
core.stop()
|
||||||
|
try core.start()
|
||||||
|
} catch let error {
|
||||||
|
Log.error("[MDMManager] Failed restarting core: error = \(error)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NotificationCenter.default.post(name: MDMManager.configurationAppliedNotification, object: self, userInfo: ["config": mdmConfig])
|
||||||
|
}
|
||||||
|
|
||||||
|
private func handleConfigurationRemoved() {
|
||||||
|
Log.info("[MDMManager] handleConfigurationRemoved - posting notification")
|
||||||
|
NotificationCenter.default.post(name: MDMManager.configurationRemovedNotification, object: self)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func sha256Hash(of dict: [String: Any]) -> String {
|
||||||
|
let description = dict.sorted(by: { $0.key < $1.key }).map { "\($0.key)=\($0.value)" }.joined(separator: "&")
|
||||||
|
let digest = SHA256.hash(data: Data(description.utf8))
|
||||||
|
return digest.map { String(format: "%02x", $0) }.joined()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -50,6 +50,7 @@
|
||||||
C642277C2E8E4D900094FEDC /* ThemeManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C642277A2E8E4AC50094FEDC /* ThemeManager.swift */; };
|
C642277C2E8E4D900094FEDC /* ThemeManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C642277A2E8E4AC50094FEDC /* ThemeManager.swift */; };
|
||||||
C642277D2E8E4E2B0094FEDC /* ColorExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D717071D2AC5922E0037746F /* ColorExtension.swift */; };
|
C642277D2E8E4E2B0094FEDC /* ColorExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D717071D2AC5922E0037746F /* ColorExtension.swift */; };
|
||||||
C65270F82F879D2700FF248C /* EarlyPushkitDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C65270F72F879D2700FF248C /* EarlyPushkitDelegate.swift */; };
|
C65270F82F879D2700FF248C /* EarlyPushkitDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C65270F72F879D2700FF248C /* EarlyPushkitDelegate.swift */; };
|
||||||
|
C65271062F87D3E600FF248C /* MDMManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C65271052F87D3E600FF248C /* MDMManager.swift */; };
|
||||||
C67586AE2C09F23C002E77BF /* URLExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C67586AD2C09F23C002E77BF /* URLExtension.swift */; };
|
C67586AE2C09F23C002E77BF /* URLExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C67586AD2C09F23C002E77BF /* URLExtension.swift */; };
|
||||||
C67586B02C09F247002E77BF /* URIHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = C67586AF2C09F247002E77BF /* URIHandler.swift */; };
|
C67586B02C09F247002E77BF /* URIHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = C67586AF2C09F247002E77BF /* URIHandler.swift */; };
|
||||||
C67586B52C09F617002E77BF /* SingleSignOnManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C67586B22C09F617002E77BF /* SingleSignOnManager.swift */; };
|
C67586B52C09F617002E77BF /* SingleSignOnManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C67586B22C09F617002E77BF /* SingleSignOnManager.swift */; };
|
||||||
|
|
@ -240,6 +241,20 @@
|
||||||
remoteGlobalIDString = 660AAF7A2B839271004C0FA6;
|
remoteGlobalIDString = 660AAF7A2B839271004C0FA6;
|
||||||
remoteInfo = msgNotificationService;
|
remoteInfo = msgNotificationService;
|
||||||
};
|
};
|
||||||
|
C65271122F88D1CA00FF248C /* PBXContainerItemProxy */ = {
|
||||||
|
isa = PBXContainerItemProxy;
|
||||||
|
containerPortal = D719ABAB2ABC67BF00B41C10 /* Project object */;
|
||||||
|
proxyType = 1;
|
||||||
|
remoteGlobalIDString = D719ABB22ABC67BF00B41C10;
|
||||||
|
remoteInfo = LinphoneApp;
|
||||||
|
};
|
||||||
|
C6E408B32F8E1A33003E0F8C /* PBXContainerItemProxy */ = {
|
||||||
|
isa = PBXContainerItemProxy;
|
||||||
|
containerPortal = D719ABAB2ABC67BF00B41C10 /* Project object */;
|
||||||
|
proxyType = 1;
|
||||||
|
remoteGlobalIDString = D719ABB22ABC67BF00B41C10;
|
||||||
|
remoteInfo = LinphoneApp;
|
||||||
|
};
|
||||||
D7458F372E0BDCF4000C957A /* PBXContainerItemProxy */ = {
|
D7458F372E0BDCF4000C957A /* PBXContainerItemProxy */ = {
|
||||||
isa = PBXContainerItemProxy;
|
isa = PBXContainerItemProxy;
|
||||||
containerPortal = D719ABAB2ABC67BF00B41C10 /* Project object */;
|
containerPortal = D719ABAB2ABC67BF00B41C10 /* Project object */;
|
||||||
|
|
@ -309,6 +324,8 @@
|
||||||
C62817332C1C7C7400DBA646 /* HelpView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HelpView.swift; sourceTree = "<group>"; };
|
C62817332C1C7C7400DBA646 /* HelpView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HelpView.swift; sourceTree = "<group>"; };
|
||||||
C642277A2E8E4AC50094FEDC /* ThemeManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemeManager.swift; sourceTree = "<group>"; };
|
C642277A2E8E4AC50094FEDC /* ThemeManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemeManager.swift; sourceTree = "<group>"; };
|
||||||
C65270F72F879D2700FF248C /* EarlyPushkitDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EarlyPushkitDelegate.swift; sourceTree = "<group>"; };
|
C65270F72F879D2700FF248C /* EarlyPushkitDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EarlyPushkitDelegate.swift; sourceTree = "<group>"; };
|
||||||
|
C65271052F87D3E600FF248C /* MDMManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MDMManager.swift; sourceTree = "<group>"; };
|
||||||
|
C652710C2F88D1CA00FF248C /* LinphoneAppUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = LinphoneAppUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
C67586AD2C09F23C002E77BF /* URLExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URLExtension.swift; sourceTree = "<group>"; };
|
C67586AD2C09F23C002E77BF /* URLExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URLExtension.swift; sourceTree = "<group>"; };
|
||||||
C67586AF2C09F247002E77BF /* URIHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URIHandler.swift; sourceTree = "<group>"; };
|
C67586AF2C09F247002E77BF /* URIHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URIHandler.swift; sourceTree = "<group>"; };
|
||||||
C67586B22C09F617002E77BF /* SingleSignOnManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SingleSignOnManager.swift; sourceTree = "<group>"; };
|
C67586B22C09F617002E77BF /* SingleSignOnManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SingleSignOnManager.swift; sourceTree = "<group>"; };
|
||||||
|
|
@ -318,6 +335,7 @@
|
||||||
C6A5A9472C10B6A30070FEA4 /* AuthState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthState.swift; sourceTree = "<group>"; };
|
C6A5A9472C10B6A30070FEA4 /* AuthState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthState.swift; sourceTree = "<group>"; };
|
||||||
C6DC4E3C2C199C4E009096FD /* BundleExtenion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BundleExtenion.swift; sourceTree = "<group>"; };
|
C6DC4E3C2C199C4E009096FD /* BundleExtenion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BundleExtenion.swift; sourceTree = "<group>"; };
|
||||||
C6DC4E3E2C19C289009096FD /* SideMenuEntry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SideMenuEntry.swift; sourceTree = "<group>"; };
|
C6DC4E3E2C19C289009096FD /* SideMenuEntry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SideMenuEntry.swift; sourceTree = "<group>"; };
|
||||||
|
C6E408AF2F8E1A33003E0F8C /* LinphoneAppTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = LinphoneAppTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
D703F7072DC8C5FF005B8F75 /* FilePicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilePicker.swift; sourceTree = "<group>"; };
|
D703F7072DC8C5FF005B8F75 /* FilePicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilePicker.swift; sourceTree = "<group>"; };
|
||||||
D706BA812ADD72D100278F45 /* DeviceRotationViewModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceRotationViewModifier.swift; sourceTree = "<group>"; };
|
D706BA812ADD72D100278F45 /* DeviceRotationViewModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceRotationViewModifier.swift; sourceTree = "<group>"; };
|
||||||
D70959F02B8DF3EC0014AC0B /* ConversationModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConversationModel.swift; sourceTree = "<group>"; };
|
D70959F02B8DF3EC0014AC0B /* ConversationModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConversationModel.swift; sourceTree = "<group>"; };
|
||||||
|
|
@ -537,6 +555,8 @@
|
||||||
/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */
|
/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */
|
||||||
|
|
||||||
/* Begin PBXFileSystemSynchronizedRootGroup section */
|
/* Begin PBXFileSystemSynchronizedRootGroup section */
|
||||||
|
C652710D2F88D1CA00FF248C /* LinphoneAppUITests */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = LinphoneAppUITests; sourceTree = "<group>"; };
|
||||||
|
C6E408B02F8E1A33003E0F8C /* LinphoneAppTests */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = LinphoneAppTests; sourceTree = "<group>"; };
|
||||||
D7458F302E0BDCF4000C957A /* linphoneExtension */ = {isa = PBXFileSystemSynchronizedRootGroup; exceptions = (D7458F3C2E0BDCF4000C957A /* PBXFileSystemSynchronizedBuildFileExceptionSet */, ); explicitFileTypes = {}; explicitFolders = (); path = linphoneExtension; sourceTree = "<group>"; };
|
D7458F302E0BDCF4000C957A /* linphoneExtension */ = {isa = PBXFileSystemSynchronizedRootGroup; exceptions = (D7458F3C2E0BDCF4000C957A /* PBXFileSystemSynchronizedBuildFileExceptionSet */, ); explicitFileTypes = {}; explicitFolders = (); path = linphoneExtension; sourceTree = "<group>"; };
|
||||||
D792F15B2F02BCC2002E3225 /* intentsExtension */ = {isa = PBXFileSystemSynchronizedRootGroup; exceptions = (D792F1642F02BCC2002E3225 /* PBXFileSystemSynchronizedBuildFileExceptionSet */, ); explicitFileTypes = {}; explicitFolders = (); path = intentsExtension; sourceTree = "<group>"; };
|
D792F15B2F02BCC2002E3225 /* intentsExtension */ = {isa = PBXFileSystemSynchronizedRootGroup; exceptions = (D792F1642F02BCC2002E3225 /* PBXFileSystemSynchronizedBuildFileExceptionSet */, ); explicitFileTypes = {}; explicitFolders = (); path = intentsExtension; sourceTree = "<group>"; };
|
||||||
/* End PBXFileSystemSynchronizedRootGroup section */
|
/* End PBXFileSystemSynchronizedRootGroup section */
|
||||||
|
|
@ -552,6 +572,20 @@
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
C65271092F88D1CA00FF248C /* Frameworks */ = {
|
||||||
|
isa = PBXFrameworksBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
C6E408AC2F8E1A33003E0F8C /* Frameworks */ = {
|
||||||
|
isa = PBXFrameworksBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
D719ABB02ABC67BF00B41C10 /* Frameworks */ = {
|
D719ABB02ABC67BF00B41C10 /* Frameworks */ = {
|
||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
|
|
@ -698,6 +732,7 @@
|
||||||
D717071C2AC591EF0037746F /* Utils */ = {
|
D717071C2AC591EF0037746F /* Utils */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
C65271052F87D3E600FF248C /* MDMManager.swift */,
|
||||||
D7BC10D82F4EF64E00F09BDA /* AudioMode.swift */,
|
D7BC10D82F4EF64E00F09BDA /* AudioMode.swift */,
|
||||||
D7BC10D32F4EF18100F09BDA /* SoundPlayer.swift */,
|
D7BC10D32F4EF18100F09BDA /* SoundPlayer.swift */,
|
||||||
C642277A2E8E4AC50094FEDC /* ThemeManager.swift */,
|
C642277A2E8E4AC50094FEDC /* ThemeManager.swift */,
|
||||||
|
|
@ -732,6 +767,8 @@
|
||||||
660AAF7C2B839272004C0FA6 /* msgNotificationService */,
|
660AAF7C2B839272004C0FA6 /* msgNotificationService */,
|
||||||
D7458F302E0BDCF4000C957A /* linphoneExtension */,
|
D7458F302E0BDCF4000C957A /* linphoneExtension */,
|
||||||
D792F15B2F02BCC2002E3225 /* intentsExtension */,
|
D792F15B2F02BCC2002E3225 /* intentsExtension */,
|
||||||
|
C652710D2F88D1CA00FF248C /* LinphoneAppUITests */,
|
||||||
|
C6E408B02F8E1A33003E0F8C /* LinphoneAppTests */,
|
||||||
D7DF8BE52E2104DC003A3BC7 /* Frameworks */,
|
D7DF8BE52E2104DC003A3BC7 /* Frameworks */,
|
||||||
D719ABB42ABC67BF00B41C10 /* Products */,
|
D719ABB42ABC67BF00B41C10 /* Products */,
|
||||||
D7AEB9462F29128500298546 /* Shared.xcconfig */,
|
D7AEB9462F29128500298546 /* Shared.xcconfig */,
|
||||||
|
|
@ -745,6 +782,8 @@
|
||||||
660AAF7B2B839271004C0FA6 /* msgNotificationService.appex */,
|
660AAF7B2B839271004C0FA6 /* msgNotificationService.appex */,
|
||||||
D7458F2F2E0BDCF4000C957A /* linphoneExtension.appex */,
|
D7458F2F2E0BDCF4000C957A /* linphoneExtension.appex */,
|
||||||
D792F1582F02BCC2002E3225 /* intentsExtension.appex */,
|
D792F1582F02BCC2002E3225 /* intentsExtension.appex */,
|
||||||
|
C652710C2F88D1CA00FF248C /* LinphoneAppUITests.xctest */,
|
||||||
|
C6E408AF2F8E1A33003E0F8C /* LinphoneAppTests.xctest */,
|
||||||
);
|
);
|
||||||
name = Products;
|
name = Products;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
|
@ -1261,6 +1300,52 @@
|
||||||
productReference = 660AAF7B2B839271004C0FA6 /* msgNotificationService.appex */;
|
productReference = 660AAF7B2B839271004C0FA6 /* msgNotificationService.appex */;
|
||||||
productType = "com.apple.product-type.app-extension";
|
productType = "com.apple.product-type.app-extension";
|
||||||
};
|
};
|
||||||
|
C652710B2F88D1CA00FF248C /* LinphoneAppUITests */ = {
|
||||||
|
isa = PBXNativeTarget;
|
||||||
|
buildConfigurationList = C65271142F88D1CA00FF248C /* Build configuration list for PBXNativeTarget "LinphoneAppUITests" */;
|
||||||
|
buildPhases = (
|
||||||
|
C65271082F88D1CA00FF248C /* Sources */,
|
||||||
|
C65271092F88D1CA00FF248C /* Frameworks */,
|
||||||
|
C652710A2F88D1CA00FF248C /* Resources */,
|
||||||
|
);
|
||||||
|
buildRules = (
|
||||||
|
);
|
||||||
|
dependencies = (
|
||||||
|
C65271132F88D1CA00FF248C /* PBXTargetDependency */,
|
||||||
|
);
|
||||||
|
fileSystemSynchronizedGroups = (
|
||||||
|
C652710D2F88D1CA00FF248C /* LinphoneAppUITests */,
|
||||||
|
);
|
||||||
|
name = LinphoneAppUITests;
|
||||||
|
packageProductDependencies = (
|
||||||
|
);
|
||||||
|
productName = LinphoneAppUITests;
|
||||||
|
productReference = C652710C2F88D1CA00FF248C /* LinphoneAppUITests.xctest */;
|
||||||
|
productType = "com.apple.product-type.bundle.ui-testing";
|
||||||
|
};
|
||||||
|
C6E408AE2F8E1A33003E0F8C /* LinphoneAppTests */ = {
|
||||||
|
isa = PBXNativeTarget;
|
||||||
|
buildConfigurationList = C6E408B52F8E1A33003E0F8C /* Build configuration list for PBXNativeTarget "LinphoneAppTests" */;
|
||||||
|
buildPhases = (
|
||||||
|
C6E408AB2F8E1A33003E0F8C /* Sources */,
|
||||||
|
C6E408AC2F8E1A33003E0F8C /* Frameworks */,
|
||||||
|
C6E408AD2F8E1A33003E0F8C /* Resources */,
|
||||||
|
);
|
||||||
|
buildRules = (
|
||||||
|
);
|
||||||
|
dependencies = (
|
||||||
|
C6E408B42F8E1A33003E0F8C /* PBXTargetDependency */,
|
||||||
|
);
|
||||||
|
fileSystemSynchronizedGroups = (
|
||||||
|
C6E408B02F8E1A33003E0F8C /* LinphoneAppTests */,
|
||||||
|
);
|
||||||
|
name = LinphoneAppTests;
|
||||||
|
packageProductDependencies = (
|
||||||
|
);
|
||||||
|
productName = LinphoneAppTests;
|
||||||
|
productReference = C6E408AF2F8E1A33003E0F8C /* LinphoneAppTests.xctest */;
|
||||||
|
productType = "com.apple.product-type.bundle.unit-test";
|
||||||
|
};
|
||||||
D719ABB22ABC67BF00B41C10 /* LinphoneApp */ = {
|
D719ABB22ABC67BF00B41C10 /* LinphoneApp */ = {
|
||||||
isa = PBXNativeTarget;
|
isa = PBXNativeTarget;
|
||||||
buildConfigurationList = D719ABC22ABC67BF00B41C10 /* Build configuration list for PBXNativeTarget "LinphoneApp" */;
|
buildConfigurationList = D719ABC22ABC67BF00B41C10 /* Build configuration list for PBXNativeTarget "LinphoneApp" */;
|
||||||
|
|
@ -1342,6 +1427,14 @@
|
||||||
CreatedOnToolsVersion = 15.0.1;
|
CreatedOnToolsVersion = 15.0.1;
|
||||||
LastSwiftMigration = 1500;
|
LastSwiftMigration = 1500;
|
||||||
};
|
};
|
||||||
|
C652710B2F88D1CA00FF248C = {
|
||||||
|
CreatedOnToolsVersion = 26.2;
|
||||||
|
TestTargetID = D719ABB22ABC67BF00B41C10;
|
||||||
|
};
|
||||||
|
C6E408AE2F8E1A33003E0F8C = {
|
||||||
|
CreatedOnToolsVersion = 26.2;
|
||||||
|
TestTargetID = D719ABB22ABC67BF00B41C10;
|
||||||
|
};
|
||||||
D719ABB22ABC67BF00B41C10 = {
|
D719ABB22ABC67BF00B41C10 = {
|
||||||
CreatedOnToolsVersion = 14.3.1;
|
CreatedOnToolsVersion = 14.3.1;
|
||||||
};
|
};
|
||||||
|
|
@ -1392,6 +1485,8 @@
|
||||||
660AAF7A2B839271004C0FA6 /* msgNotificationService */,
|
660AAF7A2B839271004C0FA6 /* msgNotificationService */,
|
||||||
D7458F2E2E0BDCF4000C957A /* linphoneExtension */,
|
D7458F2E2E0BDCF4000C957A /* linphoneExtension */,
|
||||||
D792F1572F02BCC2002E3225 /* intentsExtension */,
|
D792F1572F02BCC2002E3225 /* intentsExtension */,
|
||||||
|
C652710B2F88D1CA00FF248C /* LinphoneAppUITests */,
|
||||||
|
C6E408AE2F8E1A33003E0F8C /* LinphoneAppTests */,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
/* End PBXProject section */
|
/* End PBXProject section */
|
||||||
|
|
@ -1407,6 +1502,20 @@
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
C652710A2F88D1CA00FF248C /* Resources */ = {
|
||||||
|
isa = PBXResourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
C6E408AD2F8E1A33003E0F8C /* Resources */ = {
|
||||||
|
isa = PBXResourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
D719ABB12ABC67BF00B41C10 /* Resources */ = {
|
D719ABB12ABC67BF00B41C10 /* Resources */ = {
|
||||||
isa = PBXResourcesBuildPhase;
|
isa = PBXResourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
|
|
@ -1500,6 +1609,20 @@
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
C65271082F88D1CA00FF248C /* Sources */ = {
|
||||||
|
isa = PBXSourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
C6E408AB2F8E1A33003E0F8C /* Sources */ = {
|
||||||
|
isa = PBXSourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
D719ABAF2ABC67BF00B41C10 /* Sources */ = {
|
D719ABAF2ABC67BF00B41C10 /* Sources */ = {
|
||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
|
|
@ -1571,6 +1694,7 @@
|
||||||
D7E2E69F2CE356C90080DA0D /* PopupViewWithTextField.swift in Sources */,
|
D7E2E69F2CE356C90080DA0D /* PopupViewWithTextField.swift in Sources */,
|
||||||
C67586B52C09F617002E77BF /* SingleSignOnManager.swift in Sources */,
|
C67586B52C09F617002E77BF /* SingleSignOnManager.swift in Sources */,
|
||||||
D7F4D9CB2B5FD27200CDCD76 /* CallsListFragment.swift in Sources */,
|
D7F4D9CB2B5FD27200CDCD76 /* CallsListFragment.swift in Sources */,
|
||||||
|
C65271062F87D3E600FF248C /* MDMManager.swift in Sources */,
|
||||||
C6A5A9482C10B6A30070FEA4 /* AuthState.swift in Sources */,
|
C6A5A9482C10B6A30070FEA4 /* AuthState.swift in Sources */,
|
||||||
D72992392ADD7F68003AF125 /* HistoryContactFragment.swift in Sources */,
|
D72992392ADD7F68003AF125 /* HistoryContactFragment.swift in Sources */,
|
||||||
D711B1342E93F18700DF8C71 /* LdapServerConfigurationFragment.swift in Sources */,
|
D711B1342E93F18700DF8C71 /* LdapServerConfigurationFragment.swift in Sources */,
|
||||||
|
|
@ -1712,6 +1836,16 @@
|
||||||
target = 660AAF7A2B839271004C0FA6 /* msgNotificationService */;
|
target = 660AAF7A2B839271004C0FA6 /* msgNotificationService */;
|
||||||
targetProxy = 660AAF7D2B839272004C0FA6 /* PBXContainerItemProxy */;
|
targetProxy = 660AAF7D2B839272004C0FA6 /* PBXContainerItemProxy */;
|
||||||
};
|
};
|
||||||
|
C65271132F88D1CA00FF248C /* PBXTargetDependency */ = {
|
||||||
|
isa = PBXTargetDependency;
|
||||||
|
target = D719ABB22ABC67BF00B41C10 /* LinphoneApp */;
|
||||||
|
targetProxy = C65271122F88D1CA00FF248C /* PBXContainerItemProxy */;
|
||||||
|
};
|
||||||
|
C6E408B42F8E1A33003E0F8C /* PBXTargetDependency */ = {
|
||||||
|
isa = PBXTargetDependency;
|
||||||
|
target = D719ABB22ABC67BF00B41C10 /* LinphoneApp */;
|
||||||
|
targetProxy = C6E408B32F8E1A33003E0F8C /* PBXContainerItemProxy */;
|
||||||
|
};
|
||||||
D7458F382E0BDCF4000C957A /* PBXTargetDependency */ = {
|
D7458F382E0BDCF4000C957A /* PBXTargetDependency */ = {
|
||||||
isa = PBXTargetDependency;
|
isa = PBXTargetDependency;
|
||||||
target = D7458F2E2E0BDCF4000C957A /* linphoneExtension */;
|
target = D7458F2E2E0BDCF4000C957A /* linphoneExtension */;
|
||||||
|
|
@ -1863,6 +1997,120 @@
|
||||||
};
|
};
|
||||||
name = Release;
|
name = Release;
|
||||||
};
|
};
|
||||||
|
C65271152F88D1CA00FF248C /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
DEVELOPMENT_TEAM = Z2V957B3D6;
|
||||||
|
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||||
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 26.2;
|
||||||
|
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
||||||
|
MARKETING_VERSION = 1.0;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = org.linphone.LinphoneAppUITests;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SDKROOT = iphoneos;
|
||||||
|
STRING_CATALOG_GENERATE_SYMBOLS = NO;
|
||||||
|
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
|
||||||
|
SWIFT_APPROACHABLE_CONCURRENCY = YES;
|
||||||
|
SWIFT_EMIT_LOC_STRINGS = NO;
|
||||||
|
SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
|
TEST_TARGET_NAME = LinphoneApp;
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
C65271162F88D1CA00FF248C /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
DEVELOPMENT_TEAM = Z2V957B3D6;
|
||||||
|
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||||
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 26.2;
|
||||||
|
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
||||||
|
MARKETING_VERSION = 1.0;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = org.linphone.LinphoneAppUITests;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SDKROOT = iphoneos;
|
||||||
|
STRING_CATALOG_GENERATE_SYMBOLS = NO;
|
||||||
|
SWIFT_APPROACHABLE_CONCURRENCY = YES;
|
||||||
|
SWIFT_EMIT_LOC_STRINGS = NO;
|
||||||
|
SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
|
TEST_TARGET_NAME = LinphoneApp;
|
||||||
|
VALIDATE_PRODUCT = YES;
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
C6E408B62F8E1A33003E0F8C /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||||
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
DEVELOPMENT_TEAM = Z2V957B3D6;
|
||||||
|
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||||
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 26.2;
|
||||||
|
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
||||||
|
MARKETING_VERSION = 1.0;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = org.linphone.LinphoneAppTests;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SDKROOT = iphoneos;
|
||||||
|
STRING_CATALOG_GENERATE_SYMBOLS = NO;
|
||||||
|
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
|
||||||
|
SWIFT_APPROACHABLE_CONCURRENCY = YES;
|
||||||
|
SWIFT_EMIT_LOC_STRINGS = NO;
|
||||||
|
SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
|
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/LinphoneApp.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/LinphoneApp";
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
C6E408B72F8E1A33003E0F8C /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||||
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
DEVELOPMENT_TEAM = Z2V957B3D6;
|
||||||
|
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||||
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 26.2;
|
||||||
|
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
||||||
|
MARKETING_VERSION = 1.0;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = org.linphone.LinphoneAppTests;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SDKROOT = iphoneos;
|
||||||
|
STRING_CATALOG_GENERATE_SYMBOLS = NO;
|
||||||
|
SWIFT_APPROACHABLE_CONCURRENCY = YES;
|
||||||
|
SWIFT_EMIT_LOC_STRINGS = NO;
|
||||||
|
SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
|
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/LinphoneApp.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/LinphoneApp";
|
||||||
|
VALIDATE_PRODUCT = YES;
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
D719ABC02ABC67BF00B41C10 /* Debug */ = {
|
D719ABC02ABC67BF00B41C10 /* Debug */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
baseConfigurationReference = D7AEB9462F29128500298546 /* Shared.xcconfig */;
|
baseConfigurationReference = D7AEB9462F29128500298546 /* Shared.xcconfig */;
|
||||||
|
|
@ -2260,6 +2508,24 @@
|
||||||
defaultConfigurationIsVisible = 0;
|
defaultConfigurationIsVisible = 0;
|
||||||
defaultConfigurationName = Release;
|
defaultConfigurationName = Release;
|
||||||
};
|
};
|
||||||
|
C65271142F88D1CA00FF248C /* Build configuration list for PBXNativeTarget "LinphoneAppUITests" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
C65271152F88D1CA00FF248C /* Debug */,
|
||||||
|
C65271162F88D1CA00FF248C /* Release */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
|
C6E408B52F8E1A33003E0F8C /* Build configuration list for PBXNativeTarget "LinphoneAppTests" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
C6E408B62F8E1A33003E0F8C /* Debug */,
|
||||||
|
C6E408B72F8E1A33003E0F8C /* Release */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
D719ABAE2ABC67BF00B41C10 /* Build configuration list for PBXProject "LinphoneApp" */ = {
|
D719ABAE2ABC67BF00B41C10 /* Build configuration list for PBXProject "LinphoneApp" */ = {
|
||||||
isa = XCConfigurationList;
|
isa = XCConfigurationList;
|
||||||
buildConfigurations = (
|
buildConfigurations = (
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,30 @@
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
shouldAutocreateTestPlan = "YES">
|
shouldAutocreateTestPlan = "YES">
|
||||||
|
<Testables>
|
||||||
|
<TestableReference
|
||||||
|
skipped = "NO"
|
||||||
|
parallelizable = "YES">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "C652710B2F88D1CA00FF248C"
|
||||||
|
BuildableName = "LinphoneAppUITests.xctest"
|
||||||
|
BlueprintName = "LinphoneAppUITests"
|
||||||
|
ReferencedContainer = "container:LinphoneApp.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</TestableReference>
|
||||||
|
<TestableReference
|
||||||
|
skipped = "NO"
|
||||||
|
parallelizable = "YES">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "C6E408AE2F8E1A33003E0F8C"
|
||||||
|
BuildableName = "LinphoneAppTests.xctest"
|
||||||
|
BlueprintName = "LinphoneAppTests"
|
||||||
|
ReferencedContainer = "container:LinphoneApp.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</TestableReference>
|
||||||
|
</Testables>
|
||||||
</TestAction>
|
</TestAction>
|
||||||
<LaunchAction
|
<LaunchAction
|
||||||
buildConfiguration = "Debug"
|
buildConfiguration = "Debug"
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,55 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Scheme
|
||||||
|
LastUpgradeVersion = "2620"
|
||||||
|
version = "1.7">
|
||||||
|
<BuildAction
|
||||||
|
parallelizeBuildables = "YES"
|
||||||
|
buildImplicitDependencies = "YES"
|
||||||
|
buildArchitectures = "Automatic">
|
||||||
|
</BuildAction>
|
||||||
|
<TestAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
|
shouldAutocreateTestPlan = "YES">
|
||||||
|
<Testables>
|
||||||
|
<TestableReference
|
||||||
|
skipped = "NO"
|
||||||
|
parallelizable = "YES">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "C6E408AE2F8E1A33003E0F8C"
|
||||||
|
BuildableName = "LinphoneAppTests.xctest"
|
||||||
|
BlueprintName = "LinphoneAppTests"
|
||||||
|
ReferencedContainer = "container:LinphoneApp.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</TestableReference>
|
||||||
|
</Testables>
|
||||||
|
</TestAction>
|
||||||
|
<LaunchAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
launchStyle = "0"
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
ignoresPersistentStateOnLaunch = "NO"
|
||||||
|
debugDocumentVersioning = "YES"
|
||||||
|
debugServiceExtension = "internal"
|
||||||
|
allowLocationSimulation = "YES">
|
||||||
|
</LaunchAction>
|
||||||
|
<ProfileAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
|
savedToolIdentifier = ""
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
debugDocumentVersioning = "YES">
|
||||||
|
</ProfileAction>
|
||||||
|
<AnalyzeAction
|
||||||
|
buildConfiguration = "Debug">
|
||||||
|
</AnalyzeAction>
|
||||||
|
<ArchiveAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
revealArchiveInOrganizer = "YES">
|
||||||
|
</ArchiveAction>
|
||||||
|
</Scheme>
|
||||||
|
|
@ -0,0 +1,55 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Scheme
|
||||||
|
LastUpgradeVersion = "2620"
|
||||||
|
version = "1.7">
|
||||||
|
<BuildAction
|
||||||
|
parallelizeBuildables = "YES"
|
||||||
|
buildImplicitDependencies = "YES"
|
||||||
|
buildArchitectures = "Automatic">
|
||||||
|
</BuildAction>
|
||||||
|
<TestAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
|
shouldAutocreateTestPlan = "YES">
|
||||||
|
<Testables>
|
||||||
|
<TestableReference
|
||||||
|
skipped = "NO"
|
||||||
|
parallelizable = "YES">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "C652710B2F88D1CA00FF248C"
|
||||||
|
BuildableName = "LinphoneAppUITests.xctest"
|
||||||
|
BlueprintName = "LinphoneAppUITests"
|
||||||
|
ReferencedContainer = "container:LinphoneApp.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</TestableReference>
|
||||||
|
</Testables>
|
||||||
|
</TestAction>
|
||||||
|
<LaunchAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
launchStyle = "0"
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
ignoresPersistentStateOnLaunch = "NO"
|
||||||
|
debugDocumentVersioning = "YES"
|
||||||
|
debugServiceExtension = "internal"
|
||||||
|
allowLocationSimulation = "YES">
|
||||||
|
</LaunchAction>
|
||||||
|
<ProfileAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
|
savedToolIdentifier = ""
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
debugDocumentVersioning = "YES">
|
||||||
|
</ProfileAction>
|
||||||
|
<AnalyzeAction
|
||||||
|
buildConfiguration = "Debug">
|
||||||
|
</AnalyzeAction>
|
||||||
|
<ArchiveAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
revealArchiveInOrganizer = "YES">
|
||||||
|
</ArchiveAction>
|
||||||
|
</Scheme>
|
||||||
|
|
@ -0,0 +1,110 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Scheme
|
||||||
|
LastUpgradeVersion = "2620"
|
||||||
|
wasCreatedForAppExtension = "YES"
|
||||||
|
version = "2.0">
|
||||||
|
<BuildAction
|
||||||
|
parallelizeBuildables = "YES"
|
||||||
|
buildImplicitDependencies = "YES"
|
||||||
|
buildArchitectures = "Automatic">
|
||||||
|
<BuildActionEntries>
|
||||||
|
<BuildActionEntry
|
||||||
|
buildForTesting = "YES"
|
||||||
|
buildForRunning = "YES"
|
||||||
|
buildForProfiling = "YES"
|
||||||
|
buildForArchiving = "YES"
|
||||||
|
buildForAnalyzing = "YES">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "D792F1572F02BCC2002E3225"
|
||||||
|
BuildableName = "intentsExtension.appex"
|
||||||
|
BlueprintName = "intentsExtension"
|
||||||
|
ReferencedContainer = "container:LinphoneApp.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildActionEntry>
|
||||||
|
<BuildActionEntry
|
||||||
|
buildForTesting = "YES"
|
||||||
|
buildForRunning = "YES"
|
||||||
|
buildForProfiling = "YES"
|
||||||
|
buildForArchiving = "YES"
|
||||||
|
buildForAnalyzing = "YES">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "D719ABB22ABC67BF00B41C10"
|
||||||
|
BuildableName = "LinphoneApp.app"
|
||||||
|
BlueprintName = "LinphoneApp"
|
||||||
|
ReferencedContainer = "container:LinphoneApp.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildActionEntry>
|
||||||
|
</BuildActionEntries>
|
||||||
|
</BuildAction>
|
||||||
|
<TestAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
|
shouldAutocreateTestPlan = "YES">
|
||||||
|
<Testables>
|
||||||
|
<TestableReference
|
||||||
|
skipped = "NO"
|
||||||
|
parallelizable = "YES">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "C6E408AE2F8E1A33003E0F8C"
|
||||||
|
BuildableName = "LinphoneAppTests.xctest"
|
||||||
|
BlueprintName = "LinphoneAppTests"
|
||||||
|
ReferencedContainer = "container:LinphoneApp.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</TestableReference>
|
||||||
|
</Testables>
|
||||||
|
</TestAction>
|
||||||
|
<LaunchAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
selectedDebuggerIdentifier = ""
|
||||||
|
selectedLauncherIdentifier = "Xcode.IDEFoundation.Launcher.PosixSpawn"
|
||||||
|
launchStyle = "0"
|
||||||
|
askForAppToLaunch = "Yes"
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
ignoresPersistentStateOnLaunch = "NO"
|
||||||
|
debugDocumentVersioning = "YES"
|
||||||
|
debugServiceExtension = "internal"
|
||||||
|
allowLocationSimulation = "YES"
|
||||||
|
launchAutomaticallySubstyle = "2">
|
||||||
|
<BuildableProductRunnable
|
||||||
|
runnableDebuggingMode = "0">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "D719ABB22ABC67BF00B41C10"
|
||||||
|
BuildableName = "LinphoneApp.app"
|
||||||
|
BlueprintName = "LinphoneApp"
|
||||||
|
ReferencedContainer = "container:LinphoneApp.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildableProductRunnable>
|
||||||
|
</LaunchAction>
|
||||||
|
<ProfileAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
|
savedToolIdentifier = ""
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
debugDocumentVersioning = "YES"
|
||||||
|
askForAppToLaunch = "Yes"
|
||||||
|
launchAutomaticallySubstyle = "2">
|
||||||
|
<BuildableProductRunnable
|
||||||
|
runnableDebuggingMode = "0">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "D719ABB22ABC67BF00B41C10"
|
||||||
|
BuildableName = "LinphoneApp.app"
|
||||||
|
BlueprintName = "LinphoneApp"
|
||||||
|
ReferencedContainer = "container:LinphoneApp.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildableProductRunnable>
|
||||||
|
</ProfileAction>
|
||||||
|
<AnalyzeAction
|
||||||
|
buildConfiguration = "Debug">
|
||||||
|
</AnalyzeAction>
|
||||||
|
<ArchiveAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
revealArchiveInOrganizer = "YES">
|
||||||
|
</ArchiveAction>
|
||||||
|
</Scheme>
|
||||||
|
|
@ -0,0 +1,110 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Scheme
|
||||||
|
LastUpgradeVersion = "2620"
|
||||||
|
wasCreatedForAppExtension = "YES"
|
||||||
|
version = "2.0">
|
||||||
|
<BuildAction
|
||||||
|
parallelizeBuildables = "YES"
|
||||||
|
buildImplicitDependencies = "YES"
|
||||||
|
buildArchitectures = "Automatic">
|
||||||
|
<BuildActionEntries>
|
||||||
|
<BuildActionEntry
|
||||||
|
buildForTesting = "YES"
|
||||||
|
buildForRunning = "YES"
|
||||||
|
buildForProfiling = "YES"
|
||||||
|
buildForArchiving = "YES"
|
||||||
|
buildForAnalyzing = "YES">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "D7458F2E2E0BDCF4000C957A"
|
||||||
|
BuildableName = "linphoneExtension.appex"
|
||||||
|
BlueprintName = "linphoneExtension"
|
||||||
|
ReferencedContainer = "container:LinphoneApp.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildActionEntry>
|
||||||
|
<BuildActionEntry
|
||||||
|
buildForTesting = "YES"
|
||||||
|
buildForRunning = "YES"
|
||||||
|
buildForProfiling = "YES"
|
||||||
|
buildForArchiving = "YES"
|
||||||
|
buildForAnalyzing = "YES">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "D719ABB22ABC67BF00B41C10"
|
||||||
|
BuildableName = "LinphoneApp.app"
|
||||||
|
BlueprintName = "LinphoneApp"
|
||||||
|
ReferencedContainer = "container:LinphoneApp.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildActionEntry>
|
||||||
|
</BuildActionEntries>
|
||||||
|
</BuildAction>
|
||||||
|
<TestAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
|
shouldAutocreateTestPlan = "YES">
|
||||||
|
<Testables>
|
||||||
|
<TestableReference
|
||||||
|
skipped = "NO"
|
||||||
|
parallelizable = "YES">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "C6E408AE2F8E1A33003E0F8C"
|
||||||
|
BuildableName = "LinphoneAppTests.xctest"
|
||||||
|
BlueprintName = "LinphoneAppTests"
|
||||||
|
ReferencedContainer = "container:LinphoneApp.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</TestableReference>
|
||||||
|
</Testables>
|
||||||
|
</TestAction>
|
||||||
|
<LaunchAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
selectedDebuggerIdentifier = ""
|
||||||
|
selectedLauncherIdentifier = "Xcode.IDEFoundation.Launcher.PosixSpawn"
|
||||||
|
launchStyle = "0"
|
||||||
|
askForAppToLaunch = "Yes"
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
ignoresPersistentStateOnLaunch = "NO"
|
||||||
|
debugDocumentVersioning = "YES"
|
||||||
|
debugServiceExtension = "internal"
|
||||||
|
allowLocationSimulation = "YES"
|
||||||
|
launchAutomaticallySubstyle = "2">
|
||||||
|
<BuildableProductRunnable
|
||||||
|
runnableDebuggingMode = "0">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "D719ABB22ABC67BF00B41C10"
|
||||||
|
BuildableName = "LinphoneApp.app"
|
||||||
|
BlueprintName = "LinphoneApp"
|
||||||
|
ReferencedContainer = "container:LinphoneApp.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildableProductRunnable>
|
||||||
|
</LaunchAction>
|
||||||
|
<ProfileAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
|
savedToolIdentifier = ""
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
debugDocumentVersioning = "YES"
|
||||||
|
askForAppToLaunch = "Yes"
|
||||||
|
launchAutomaticallySubstyle = "2">
|
||||||
|
<BuildableProductRunnable
|
||||||
|
runnableDebuggingMode = "0">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "D719ABB22ABC67BF00B41C10"
|
||||||
|
BuildableName = "LinphoneApp.app"
|
||||||
|
BlueprintName = "LinphoneApp"
|
||||||
|
ReferencedContainer = "container:LinphoneApp.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildableProductRunnable>
|
||||||
|
</ProfileAction>
|
||||||
|
<AnalyzeAction
|
||||||
|
buildConfiguration = "Debug">
|
||||||
|
</AnalyzeAction>
|
||||||
|
<ArchiveAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
revealArchiveInOrganizer = "YES">
|
||||||
|
</ArchiveAction>
|
||||||
|
</Scheme>
|
||||||
|
|
@ -0,0 +1,110 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Scheme
|
||||||
|
LastUpgradeVersion = "2620"
|
||||||
|
wasCreatedForAppExtension = "YES"
|
||||||
|
version = "2.0">
|
||||||
|
<BuildAction
|
||||||
|
parallelizeBuildables = "YES"
|
||||||
|
buildImplicitDependencies = "YES"
|
||||||
|
buildArchitectures = "Automatic">
|
||||||
|
<BuildActionEntries>
|
||||||
|
<BuildActionEntry
|
||||||
|
buildForTesting = "YES"
|
||||||
|
buildForRunning = "YES"
|
||||||
|
buildForProfiling = "YES"
|
||||||
|
buildForArchiving = "YES"
|
||||||
|
buildForAnalyzing = "YES">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "660AAF7A2B839271004C0FA6"
|
||||||
|
BuildableName = "msgNotificationService.appex"
|
||||||
|
BlueprintName = "msgNotificationService"
|
||||||
|
ReferencedContainer = "container:LinphoneApp.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildActionEntry>
|
||||||
|
<BuildActionEntry
|
||||||
|
buildForTesting = "YES"
|
||||||
|
buildForRunning = "YES"
|
||||||
|
buildForProfiling = "YES"
|
||||||
|
buildForArchiving = "YES"
|
||||||
|
buildForAnalyzing = "YES">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "D719ABB22ABC67BF00B41C10"
|
||||||
|
BuildableName = "LinphoneApp.app"
|
||||||
|
BlueprintName = "LinphoneApp"
|
||||||
|
ReferencedContainer = "container:LinphoneApp.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildActionEntry>
|
||||||
|
</BuildActionEntries>
|
||||||
|
</BuildAction>
|
||||||
|
<TestAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
|
shouldAutocreateTestPlan = "YES">
|
||||||
|
<Testables>
|
||||||
|
<TestableReference
|
||||||
|
skipped = "NO"
|
||||||
|
parallelizable = "YES">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "C6E408AE2F8E1A33003E0F8C"
|
||||||
|
BuildableName = "LinphoneAppTests.xctest"
|
||||||
|
BlueprintName = "LinphoneAppTests"
|
||||||
|
ReferencedContainer = "container:LinphoneApp.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</TestableReference>
|
||||||
|
</Testables>
|
||||||
|
</TestAction>
|
||||||
|
<LaunchAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
selectedDebuggerIdentifier = ""
|
||||||
|
selectedLauncherIdentifier = "Xcode.IDEFoundation.Launcher.PosixSpawn"
|
||||||
|
launchStyle = "0"
|
||||||
|
askForAppToLaunch = "Yes"
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
ignoresPersistentStateOnLaunch = "NO"
|
||||||
|
debugDocumentVersioning = "YES"
|
||||||
|
debugServiceExtension = "internal"
|
||||||
|
allowLocationSimulation = "YES"
|
||||||
|
launchAutomaticallySubstyle = "2">
|
||||||
|
<BuildableProductRunnable
|
||||||
|
runnableDebuggingMode = "0">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "D719ABB22ABC67BF00B41C10"
|
||||||
|
BuildableName = "LinphoneApp.app"
|
||||||
|
BlueprintName = "LinphoneApp"
|
||||||
|
ReferencedContainer = "container:LinphoneApp.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildableProductRunnable>
|
||||||
|
</LaunchAction>
|
||||||
|
<ProfileAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
|
savedToolIdentifier = ""
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
debugDocumentVersioning = "YES"
|
||||||
|
askForAppToLaunch = "Yes"
|
||||||
|
launchAutomaticallySubstyle = "2">
|
||||||
|
<BuildableProductRunnable
|
||||||
|
runnableDebuggingMode = "0">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "D719ABB22ABC67BF00B41C10"
|
||||||
|
BuildableName = "LinphoneApp.app"
|
||||||
|
BlueprintName = "LinphoneApp"
|
||||||
|
ReferencedContainer = "container:LinphoneApp.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildableProductRunnable>
|
||||||
|
</ProfileAction>
|
||||||
|
<AnalyzeAction
|
||||||
|
buildConfiguration = "Debug">
|
||||||
|
</AnalyzeAction>
|
||||||
|
<ArchiveAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
revealArchiveInOrganizer = "YES">
|
||||||
|
</ArchiveAction>
|
||||||
|
</Scheme>
|
||||||
72
LinphoneAppTests/MDMManagerTests.swift
Normal file
72
LinphoneAppTests/MDMManagerTests.swift
Normal file
|
|
@ -0,0 +1,72 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010-2023 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import XCTest
|
||||||
|
import linphonesw
|
||||||
|
@testable import LinphoneApp
|
||||||
|
|
||||||
|
class MDMManagerTests: XCTestCase {
|
||||||
|
|
||||||
|
private let managedKey = "com.apple.configuration.managed"
|
||||||
|
private let dummyRootCa = """
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDdummyTESTCERTIFICATEVALUEForUnitTestsOnly1234567890abcdefABCDEF
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
"""
|
||||||
|
|
||||||
|
override func setUp() {
|
||||||
|
super.setUp()
|
||||||
|
UserDefaults.standard.removeObject(forKey: managedKey)
|
||||||
|
UserDefaults.standard.removeObject(forKey: "MDMManager.hasMDMConfig")
|
||||||
|
UserDefaults.standard.removeObject(forKey: "MDMManager.lastConfigSHA256")
|
||||||
|
}
|
||||||
|
|
||||||
|
override func tearDown() {
|
||||||
|
UserDefaults.standard.removeObject(forKey: managedKey)
|
||||||
|
UserDefaults.standard.removeObject(forKey: "MDMManager.hasMDMConfig")
|
||||||
|
UserDefaults.standard.removeObject(forKey: "MDMManager.lastConfigSHA256")
|
||||||
|
super.tearDown()
|
||||||
|
}
|
||||||
|
|
||||||
|
func testApplyMdmConfigSetsRootCa() throws {
|
||||||
|
let mdmConfig: [String: Any] = ["root-ca": dummyRootCa]
|
||||||
|
UserDefaults.standard.set(mdmConfig, forKey: managedKey)
|
||||||
|
|
||||||
|
let config = Config.newForSharedCore(
|
||||||
|
appGroupId: Bundle.main.object(forInfoDictionaryKey: "APP_GROUP_NAME") as? String ?? "group.test",
|
||||||
|
configFilename: "linphonerc-test",
|
||||||
|
factoryConfigFilename: nil
|
||||||
|
)
|
||||||
|
|
||||||
|
let core = try Factory.Instance.createCoreWithConfig(config: config!, systemContext: nil)
|
||||||
|
|
||||||
|
let appliedExpectation = expectation(forNotification: MDMManager.configurationAppliedNotification, object: nil) { notification in
|
||||||
|
guard let config = notification.userInfo?["config"] as? [String: Any] else { return false }
|
||||||
|
return (config["root-ca"] as? String) == self.dummyRootCa
|
||||||
|
}
|
||||||
|
|
||||||
|
MDMManager.shared.applyMdmConfigToCore(core: core)
|
||||||
|
|
||||||
|
wait(for: [appliedExpectation], timeout: 5)
|
||||||
|
|
||||||
|
XCTAssertEqual(core.rootCaData, dummyRootCa,
|
||||||
|
"core.rootCaData should equal the MDM-provided root-ca after applyMdmConfigToCore")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
169
LinphoneAppUITests/MDMChatFeatureUITests.swift
Normal file
169
LinphoneAppUITests/MDMChatFeatureUITests.swift
Normal file
|
|
@ -0,0 +1,169 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010-2023 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import XCTest
|
||||||
|
|
||||||
|
class MDMChatFeatureUITests: XCTestCase {
|
||||||
|
|
||||||
|
let app = XCUIApplication()
|
||||||
|
private var permissionMonitor: NSObjectProtocol?
|
||||||
|
|
||||||
|
override func setUp() {
|
||||||
|
super.setUp()
|
||||||
|
continueAfterFailure = false
|
||||||
|
|
||||||
|
permissionMonitor = addUIInterruptionMonitor(withDescription: "System Permission Alert") { alert in
|
||||||
|
let prefixMatches = ["Share All", "Allow"]
|
||||||
|
for prefix in prefixMatches {
|
||||||
|
let match = alert.buttons.matching(NSPredicate(format: "label BEGINSWITH %@", prefix)).firstMatch
|
||||||
|
if match.exists {
|
||||||
|
match.tap()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let allowLabels = ["Continue", "OK", "Allow Once", "Always Allow"]
|
||||||
|
for label in allowLabels {
|
||||||
|
let button = alert.buttons[label]
|
||||||
|
if button.exists {
|
||||||
|
button.tap()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override func tearDown() {
|
||||||
|
if let monitor = permissionMonitor {
|
||||||
|
removeUIInterruptionMonitor(monitor)
|
||||||
|
}
|
||||||
|
super.tearDown()
|
||||||
|
}
|
||||||
|
|
||||||
|
private func requiredEnv(_ name: String) -> String {
|
||||||
|
guard let value = ProcessInfo.processInfo.environment[name], !value.isEmpty else {
|
||||||
|
XCTFail("Missing required env var \(name). Export TEST_RUNNER_\(name) before running scripts/run-mdm-tests.sh")
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
private func launchWithMDM(_ mdm: [String: Any]) {
|
||||||
|
let data = try! JSONSerialization.data(withJSONObject: mdm)
|
||||||
|
app.launchEnvironment["UITEST_MDM_CONFIG"] = String(data: data, encoding: .utf8)!
|
||||||
|
app.launch()
|
||||||
|
_ = app.wait(for: .runningForeground, timeout: 15)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func skipOnboardingIfShown() {
|
||||||
|
let welcomeSkip = app.buttons["welcome_skip_button"]
|
||||||
|
if welcomeSkip.waitForExistence(timeout: 5) {
|
||||||
|
welcomeSkip.tap()
|
||||||
|
}
|
||||||
|
let permissionsSkip = app.buttons["permissions_skip_button"]
|
||||||
|
if permissionsSkip.waitForExistence(timeout: 5) {
|
||||||
|
permissionsSkip.tap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func waitForMainPage(timeout: TimeInterval) -> Bool {
|
||||||
|
let callsButton = app.buttons.matching(NSPredicate(format: "label == %@", "Calls")).firstMatch
|
||||||
|
let springboard = XCUIApplication(bundleIdentifier: "com.apple.springboard")
|
||||||
|
let alertPrefixes = ["Share All", "Allow", "Continue", "OK"]
|
||||||
|
|
||||||
|
let deadline = Date().addingTimeInterval(timeout)
|
||||||
|
while Date() < deadline {
|
||||||
|
for prefix in alertPrefixes {
|
||||||
|
let button = springboard.buttons.matching(
|
||||||
|
NSPredicate(format: "label BEGINSWITH %@", prefix)
|
||||||
|
).firstMatch
|
||||||
|
if button.exists {
|
||||||
|
button.tap()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if callsButton.exists {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
_ = callsButton.waitForExistence(timeout: 1)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
private func dumpOnFailure(_ label: String) {
|
||||||
|
let springboard = XCUIApplication(bundleIdentifier: "com.apple.springboard")
|
||||||
|
print("=== APP DEBUG DESCRIPTION (\(label)) ===")
|
||||||
|
print(app.debugDescription)
|
||||||
|
print("=== SPRINGBOARD DEBUG DESCRIPTION =====================")
|
||||||
|
print(springboard.debugDescription)
|
||||||
|
print("=======================================================")
|
||||||
|
}
|
||||||
|
|
||||||
|
func testChatButtonHiddenWithMDMDisableChat() {
|
||||||
|
let username = requiredEnv("LINPHONE_TEST_USERNAME")
|
||||||
|
let ha1 = requiredEnv("LINPHONE_TEST_HA1")
|
||||||
|
let domain = ProcessInfo.processInfo.environment["LINPHONE_TEST_DOMAIN"] ?? "sip.linphone.org"
|
||||||
|
|
||||||
|
let xmlConfig = """
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<config xmlns="http://www.linphone.org/xsds/lpconfig.xsd">
|
||||||
|
<section name="ui">
|
||||||
|
<entry name="disable_chat_feature">1</entry>
|
||||||
|
</section>
|
||||||
|
<section name="proxy_0">
|
||||||
|
<entry name="reg_identity" overwrite="true">sip:\(username)@\(domain)</entry>
|
||||||
|
<entry name="reg_proxy" overwrite="true"><sip:\(domain);transport=tls></entry>
|
||||||
|
<entry name="reg_route" overwrite="true"><sip:\(domain);transport=tls></entry>
|
||||||
|
<entry name="realm" overwrite="true">\(domain)</entry>
|
||||||
|
<entry name="lime_server_url" overwrite="true">https://lime.linphone.org:443/lime-server/lime-server.php</entry>
|
||||||
|
</section>
|
||||||
|
<section name="auth_info_0">
|
||||||
|
<entry name="username" overwrite="true">\(username)</entry>
|
||||||
|
<entry name="domain" overwrite="true">\(domain)</entry>
|
||||||
|
<entry name="ha1" overwrite="true">\(ha1)</entry>
|
||||||
|
<entry name="realm" overwrite="true">\(domain)</entry>
|
||||||
|
<entry name="algorithm" overwrite="true">MD5</entry>
|
||||||
|
</section>
|
||||||
|
</config>
|
||||||
|
"""
|
||||||
|
|
||||||
|
launchWithMDM(["xml-config": xmlConfig])
|
||||||
|
skipOnboardingIfShown()
|
||||||
|
|
||||||
|
let landed = waitForMainPage(timeout: 30)
|
||||||
|
if !landed { dumpOnFailure("main screen not reached") }
|
||||||
|
XCTAssertTrue(landed, "Should have landed on the main screen after Welcome + Permissions")
|
||||||
|
|
||||||
|
let chatButton = app.buttons.matching(NSPredicate(format: "label == %@", "Conversations")).firstMatch
|
||||||
|
XCTAssertFalse(chatButton.exists,
|
||||||
|
"Chat button should NOT be visible when MDM disables chat feature")
|
||||||
|
}
|
||||||
|
|
||||||
|
func testConfigUriMDMLandsOnMainPage() {
|
||||||
|
let configUri = requiredEnv("LINPHONE_TEST_CONFIG_URI")
|
||||||
|
|
||||||
|
launchWithMDM(["config-uri": configUri])
|
||||||
|
skipOnboardingIfShown()
|
||||||
|
|
||||||
|
let landed = waitForMainPage(timeout: 60)
|
||||||
|
if !landed { dumpOnFailure("main screen not reached with config-uri \(configUri)") }
|
||||||
|
XCTAssertTrue(landed,
|
||||||
|
"Should have landed on the main screen after remote provisioning from \(configUri)")
|
||||||
|
}
|
||||||
|
}
|
||||||
114
README.md
114
README.md
|
|
@ -133,3 +133,117 @@ cmake --preset=ios-sdk -G Ninja -B spm-ios && cmake --build spm-ios
|
||||||
- Add it manually if needed.
|
- Add it manually if needed.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
# MDM (Mobile Device Management) configuration
|
||||||
|
|
||||||
|
Linphone iOS supports managed app configuration via the standard iOS MDM
|
||||||
|
`com.apple.configuration.managed` mechanism. When the app is deployed through
|
||||||
|
an MDM server, administrators can push a configuration dictionary that the app
|
||||||
|
reads at startup and whenever the managed configuration changes at runtime.
|
||||||
|
|
||||||
|
The following keys are supported:
|
||||||
|
|
||||||
|
| Key | Type | Description |
|
||||||
|
|---------------|--------|-------------------------------------------------------------------------------------------------|
|
||||||
|
| `xml-config` | String | A Linphone configuration in XML format (same schema as `linphonerc`). Applied via `Config.loadFromXmlString`. |
|
||||||
|
| `root-ca` | String | A PEM-encoded root CA certificate used by the Linphone SDK for TLS operations (SIPS, HTTPS provisioning, …). Applied to `core.rootCaData`. |
|
||||||
|
| `config-uri` | String | URI to a remote provisioning file. When set, it takes precedence over any `config-uri` that may be defined inside `xml-config`, and triggers a core restart to fetch the remote configuration. |
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
- All three keys are optional and can be combined.
|
||||||
|
- If `config-uri` is present, it is set last and the core is restarted so that
|
||||||
|
remote provisioning takes effect; any `config-uri` value embedded in
|
||||||
|
`xml-config` is therefore overridden.
|
||||||
|
- Applying and removing the managed configuration at runtime is supported:
|
||||||
|
removing it resets the core to its default configuration and returns to the
|
||||||
|
assistant/login screen.
|
||||||
|
|
||||||
|
## Testing MDM configuration
|
||||||
|
|
||||||
|
Two kinds of tests are provided:
|
||||||
|
|
||||||
|
### UI tests (end-to-end)
|
||||||
|
|
||||||
|
Located in `LinphoneAppUITests/MDMChatFeatureUITests.swift`. They inject a
|
||||||
|
managed configuration at launch via the app's DEBUG-only
|
||||||
|
`UITEST_MDM_CONFIG` launch-environment hook (implemented in
|
||||||
|
`Linphone/LinphoneApp.swift`), so no `xcrun simctl` setup is needed.
|
||||||
|
|
||||||
|
Note: the tests only cover MDM *application* (fresh launch with a managed
|
||||||
|
config). Live removal of MDM while the app is running cannot be simulated
|
||||||
|
from an XCUITest process (UserDefaults is per-process and we want the app
|
||||||
|
to stay alive for a realistic removal scenario), so that path is covered by
|
||||||
|
manual testing only.
|
||||||
|
|
||||||
|
Each MDM test case represents "a fresh device receiving a specific managed
|
||||||
|
configuration", so we uninstall the app before every test to avoid any
|
||||||
|
leakage of UserDefaults / keychain / provisioning / accounts between cases.
|
||||||
|
The wrapper script `scripts/run-mdm-tests.sh` does this for you.
|
||||||
|
|
||||||
|
The tests need a real SIP account to reach the main screen (the MDM XML
|
||||||
|
embeds proxy + auth_info sections) and a remote provisioning URL for the
|
||||||
|
config-uri test. Credentials can be provided three ways — the script
|
||||||
|
resolves them in this order, highest first:
|
||||||
|
|
||||||
|
1. CLI flags: `--username`, `--ha1`, `--domain`, `--config-uri` (and
|
||||||
|
`--device` for the sim UUID)
|
||||||
|
2. Shell env vars: `LINPHONE_TEST_USERNAME`, `LINPHONE_TEST_HA1`,
|
||||||
|
`LINPHONE_TEST_DOMAIN`, `LINPHONE_TEST_CONFIG_URI`
|
||||||
|
3. The gitignored file `scripts/test-credentials.env` (copy from `.env.example`)
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scripts/run-mdm-tests.sh --device <uuid> --username alice --ha1 <md5-hash> --config-uri https://example.com/provisioning.xml
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp scripts/test-credentials.env.example scripts/test-credentials.env
|
||||||
|
# edit scripts/test-credentials.env, fill in LINPHONE_TEST_USERNAME /
|
||||||
|
# LINPHONE_TEST_HA1 / LINPHONE_TEST_CONFIG_URI
|
||||||
|
scripts/run-mdm-tests.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
It will create+boot a throwaway simulator if `DEVICE_UUID` is not set,
|
||||||
|
uninstall the app before each test, run the tests one at a time with
|
||||||
|
`-parallel-testing-enabled NO`, and clean up at the end. To reuse an
|
||||||
|
already-booted simulator:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
DEVICE_UUID=<your-booted-simulator-uuid> scripts/run-mdm-tests.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
`-parallel-testing-enabled NO` avoids flaky UI test launch failures caused by
|
||||||
|
Xcode spinning up multiple simulator clones in parallel (the test-runner app
|
||||||
|
can fail to launch on a clone under pressure).
|
||||||
|
|
||||||
|
Covered cases:
|
||||||
|
- `testChatButtonHiddenWithMDMDisableChat` — MDM `xml-config` with
|
||||||
|
`disable_chat_feature=1`; the test reaches the main screen and asserts the
|
||||||
|
chat button is hidden.
|
||||||
|
- `testConfigUriMDMLandsOnMainPage` — MDM `config-uri` pointing at the URL
|
||||||
|
supplied via `--config-uri` / `LINPHONE_TEST_CONFIG_URI`; the test verifies
|
||||||
|
that remote provisioning completes and the app lands on the main screen.
|
||||||
|
|
||||||
|
### Unit tests (MDMManager)
|
||||||
|
|
||||||
|
Located in `LinphoneAppTests/MDMManagerTests.swift`. The unit test covers
|
||||||
|
only `root-ca` application: it calls
|
||||||
|
`MDMManager.shared.applyMdmConfigToCore(core:)` directly on a throwaway
|
||||||
|
`Core` and asserts `core.rootCaData` matches the MDM-provided certificate.
|
||||||
|
The `config-uri` and `xml-config` paths are exercised end-to-end by the UI
|
||||||
|
tests above.
|
||||||
|
|
||||||
|
This requires a **Unit Testing Bundle** target in Xcode (separate from the UI
|
||||||
|
test target, because `@testable import Linphone` only works from a unit test
|
||||||
|
bundle):
|
||||||
|
|
||||||
|
1. Xcode → File → New → Target → iOS → Unit Testing Bundle
|
||||||
|
2. Name it `LinphoneAppTests`, set "Target to be Tested" to `LinphoneApp`
|
||||||
|
3. Add `LinphoneAppTests/MDMManagerTests.swift` to that target
|
||||||
|
|
||||||
|
Then run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
xcodebuild test -project LinphoneApp.xcodeproj -scheme LinphoneAppTests -destination "platform=iOS Simulator,id=$DEVICE_UUID"
|
||||||
|
```
|
||||||
|
|
|
||||||
155
scripts/run-mdm-tests.sh
Executable file
155
scripts/run-mdm-tests.sh
Executable file
|
|
@ -0,0 +1,155 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# Run MDM UI tests with a clean app install before each test case.
|
||||||
|
#
|
||||||
|
# Each MDM UI test scenario represents a fresh device receiving a specific
|
||||||
|
# managed configuration. To reproduce that "closest to reality", we uninstall
|
||||||
|
# the app before every single test so no state (UserDefaults, keychain,
|
||||||
|
# provisioning, accounts) leaks between runs.
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# scripts/run-mdm-tests.sh [--device <uuid>] [--username <user>] [--ha1 <hash>] [--domain <domain>]
|
||||||
|
#
|
||||||
|
# Or with environment variables / the gitignored `scripts/test-credentials.env`:
|
||||||
|
# DEVICE_UUID=<uuid> LINPHONE_TEST_USERNAME=... LINPHONE_TEST_HA1=... scripts/run-mdm-tests.sh
|
||||||
|
#
|
||||||
|
# Resolution order (highest first): CLI flag > shell env > test-credentials.env > default.
|
||||||
|
#
|
||||||
|
# If no device UUID is given, the script creates and boots a throwaway
|
||||||
|
# "iPhone 15" simulator, then deletes it at the end.
|
||||||
|
#
|
||||||
|
# SIP test credentials are required for tests that need a working account.
|
||||||
|
# They are forwarded to the UI test runner via the `TEST_RUNNER_` prefix,
|
||||||
|
# which Xcode strips before exposing them to the test process.
|
||||||
|
# LINPHONE_TEST_USERNAME SIP username (required)
|
||||||
|
# LINPHONE_TEST_HA1 md5(username:realm:password) (required)
|
||||||
|
# LINPHONE_TEST_DOMAIN defaults to sip.linphone.org
|
||||||
|
# LINPHONE_TEST_CONFIG_URI remote provisioning URL (required for the
|
||||||
|
# config-uri UI test)
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
if [[ -f "$SCRIPT_DIR/test-credentials.env" ]]; then
|
||||||
|
# shellcheck source=/dev/null
|
||||||
|
source "$SCRIPT_DIR/test-credentials.env"
|
||||||
|
fi
|
||||||
|
|
||||||
|
CLI_DEVICE=""
|
||||||
|
CLI_USERNAME=""
|
||||||
|
CLI_HA1=""
|
||||||
|
CLI_DOMAIN=""
|
||||||
|
CLI_CONFIG_URI=""
|
||||||
|
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--device) CLI_DEVICE="$2"; shift 2 ;;
|
||||||
|
--username) CLI_USERNAME="$2"; shift 2 ;;
|
||||||
|
--ha1) CLI_HA1="$2"; shift 2 ;;
|
||||||
|
--domain) CLI_DOMAIN="$2"; shift 2 ;;
|
||||||
|
--config-uri) CLI_CONFIG_URI="$2"; shift 2 ;;
|
||||||
|
-h|--help)
|
||||||
|
sed -n '3,20p' "$0"
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
-*)
|
||||||
|
echo "Unknown flag: $1" >&2
|
||||||
|
exit 2
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
# First bare positional arg = device UUID (back-compat).
|
||||||
|
if [[ -z "$CLI_DEVICE" ]]; then CLI_DEVICE="$1"; shift
|
||||||
|
else echo "Unexpected argument: $1" >&2; exit 2
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
LINPHONE_TEST_USERNAME="${CLI_USERNAME:-${LINPHONE_TEST_USERNAME:-}}"
|
||||||
|
LINPHONE_TEST_HA1="${CLI_HA1:-${LINPHONE_TEST_HA1:-}}"
|
||||||
|
LINPHONE_TEST_DOMAIN="${CLI_DOMAIN:-${LINPHONE_TEST_DOMAIN:-sip.linphone.org}}"
|
||||||
|
LINPHONE_TEST_CONFIG_URI="${CLI_CONFIG_URI:-${LINPHONE_TEST_CONFIG_URI:-}}"
|
||||||
|
|
||||||
|
: "${LINPHONE_TEST_USERNAME:?LINPHONE_TEST_USERNAME is required (pass --username, export it, or put it in scripts/test-credentials.env)}"
|
||||||
|
: "${LINPHONE_TEST_HA1:?LINPHONE_TEST_HA1 is required (pass --ha1, export it, or put it in scripts/test-credentials.env)}"
|
||||||
|
: "${LINPHONE_TEST_CONFIG_URI:?LINPHONE_TEST_CONFIG_URI is required (pass --config-uri, export it, or put it in scripts/test-credentials.env)}"
|
||||||
|
export TEST_RUNNER_LINPHONE_TEST_USERNAME="$LINPHONE_TEST_USERNAME"
|
||||||
|
export TEST_RUNNER_LINPHONE_TEST_HA1="$LINPHONE_TEST_HA1"
|
||||||
|
export TEST_RUNNER_LINPHONE_TEST_DOMAIN="$LINPHONE_TEST_DOMAIN"
|
||||||
|
export TEST_RUNNER_LINPHONE_TEST_CONFIG_URI="$LINPHONE_TEST_CONFIG_URI"
|
||||||
|
|
||||||
|
BUNDLE_ID="org.linphone.phone"
|
||||||
|
PROJECT="LinphoneApp.xcodeproj"
|
||||||
|
SCHEME="LinphoneAppUITests"
|
||||||
|
TEST_CLASS="LinphoneAppUITests/MDMChatFeatureUITests"
|
||||||
|
|
||||||
|
# App groups survive `simctl uninstall`, so linphonerc / SDK state from a
|
||||||
|
# previous test leaks into the next fresh install. We nuke these between
|
||||||
|
# tests so each test really starts from scratch.
|
||||||
|
APP_GROUPS=(
|
||||||
|
"group.org.linphone.phone.msgNotification"
|
||||||
|
"group.org.linphone.phone.linphoneExtension"
|
||||||
|
)
|
||||||
|
|
||||||
|
TESTS=(
|
||||||
|
"testChatButtonHiddenWithMDMDisableChat"
|
||||||
|
"testConfigUriMDMLandsOnMainPage"
|
||||||
|
)
|
||||||
|
|
||||||
|
CREATED_DEVICE=0
|
||||||
|
DEVICE_UUID="${CLI_DEVICE:-${DEVICE_UUID:-}}"
|
||||||
|
|
||||||
|
if [[ -z "$DEVICE_UUID" ]]; then
|
||||||
|
echo "No DEVICE_UUID provided, creating a throwaway simulator..."
|
||||||
|
DEVICE_UUID=$(xcrun simctl create "LinphoneMDMTest" "iPhone 15")
|
||||||
|
xcrun simctl boot "$DEVICE_UUID"
|
||||||
|
CREATED_DEVICE=1
|
||||||
|
else
|
||||||
|
# Make sure the simulator is booted — simctl uninstall fails on Shutdown.
|
||||||
|
# `simctl boot` is a no-op on an already-booted device except for exit code,
|
||||||
|
# so we ignore that specific error.
|
||||||
|
xcrun simctl boot "$DEVICE_UUID" 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
if [[ "$CREATED_DEVICE" == "1" ]]; then
|
||||||
|
xcrun simctl shutdown "$DEVICE_UUID" || true
|
||||||
|
xcrun simctl delete "$DEVICE_UUID" || true
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
trap cleanup EXIT
|
||||||
|
|
||||||
|
for test in "${TESTS[@]}"; do
|
||||||
|
echo ""
|
||||||
|
echo "=============================================="
|
||||||
|
echo "Running $test on $DEVICE_UUID"
|
||||||
|
echo "=============================================="
|
||||||
|
# Wipe app group containers BEFORE uninstall — get_app_container needs the
|
||||||
|
# app installed to resolve the group path. On the very first iteration the
|
||||||
|
# app isn't installed yet (nothing to leak), so the lookup silently no-ops.
|
||||||
|
for group in "${APP_GROUPS[@]}"; do
|
||||||
|
group_path=$(xcrun simctl get_app_container "$DEVICE_UUID" "$BUNDLE_ID" "$group" 2>/dev/null || true)
|
||||||
|
if [[ -n "$group_path" && -d "$group_path" ]]; then
|
||||||
|
echo "Wiping app group container: $group_path"
|
||||||
|
rm -rf "$group_path"/* "$group_path"/.[!.]* 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
xcrun simctl uninstall "$DEVICE_UUID" "$BUNDLE_ID" || true
|
||||||
|
# Keychain survives simctl uninstall — once the core materializes an account
|
||||||
|
# from MDM it saves auth info to the keychain, which would make the next
|
||||||
|
# fresh install skip the welcome flow. Reset the keychain between tests.
|
||||||
|
xcrun simctl keychain "$DEVICE_UUID" reset || true
|
||||||
|
# Pre-grant privacy-sensitive permissions so no system dialogs interrupt the
|
||||||
|
# flow (Contacts triggers an extra "Share All N Contacts" limited-access
|
||||||
|
# sheet on iOS 18 that UIInterruptionMonitor can only dismiss if another app
|
||||||
|
# interaction follows — not worth juggling). Must happen after uninstall +
|
||||||
|
# before the test launches the app. Ignore failures (not all sims/iOS
|
||||||
|
# versions support every service).
|
||||||
|
for service in contacts notifications location location-always camera microphone photos; do
|
||||||
|
xcrun simctl privacy "$DEVICE_UUID" grant "$service" "$BUNDLE_ID" 2>/dev/null || true
|
||||||
|
done
|
||||||
|
xcodebuild test -project "$PROJECT" -scheme "$SCHEME" -destination "platform=iOS Simulator,id=$DEVICE_UUID" -only-testing:"$TEST_CLASS/$test" -parallel-testing-enabled NO
|
||||||
|
done
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "All MDM UI tests passed."
|
||||||
Loading…
Add table
Reference in a new issue