mirror of
https://gitlab.linphone.org/BC/public/linphone-iphone.git
synced 2026-04-17 11:48:27 +00:00
MDM configuration & Unit/UI tests
This commit is contained in:
parent
e6b1b632d4
commit
0feac76611
18 changed files with 1549 additions and 21 deletions
|
|
@ -65,7 +65,60 @@ class CoreContext: ObservableObject {
|
|||
do {
|
||||
try initialiseCore()
|
||||
} 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")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
|
||||
MDMManager.shared.applyMdmConfigToCore(core: self.mCore)
|
||||
self.startObservingMDMConfigurationUpdates()
|
||||
|
||||
|
||||
self.mCore.callkitEnabled = true
|
||||
self.mCore.pushNotificationEnabled = true
|
||||
|
|
@ -348,19 +407,7 @@ class CoreContext: ObservableObject {
|
|||
}
|
||||
}, onConfiguringStatus: { (_: Core, status: ConfiguringState, message: String) in
|
||||
Log.info("New configuration state is \(status) = \(message)\n")
|
||||
let themeMainColor = AppServices.corePreferences.themeMainColor
|
||||
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()
|
||||
}
|
||||
}
|
||||
self.handleConfigurationChanged(status: status)
|
||||
}, onLogCollectionUploadStateChanged: { (_: Core, _: Core.LogCollectionUploadState, info: String) in
|
||||
if info.starts(with: "https") {
|
||||
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 {
|
||||
|
|
@ -589,8 +654,30 @@ enum AppServices {
|
|||
}
|
||||
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
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDele
|
|||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
||||
// Set up notifications
|
||||
UNUserNotificationCenter.current().delegate = self
|
||||
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
|
|
@ -159,6 +159,9 @@ struct LinphoneApp: App {
|
|||
private let voipRegistry = PKPushRegistry(queue: coreQueue)
|
||||
|
||||
init() {
|
||||
#if DEBUG
|
||||
LinphoneApp.applyUITestMDMConfigIfNeeded()
|
||||
#endif
|
||||
if !configAvailable {
|
||||
voipRegistry.delegate = earlyPushDelegate
|
||||
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 {
|
||||
WindowGroup {
|
||||
if configAvailable {
|
||||
|
|
|
|||
|
|
@ -35,7 +35,8 @@ struct SplashScreen: View {
|
|||
.foregroundColor(ThemeManager.shared.currentTheme.main500)
|
||||
|
||||
if showSpinner {
|
||||
ProgressView()
|
||||
PopupLoadingView()
|
||||
.background(.black.opacity(0.65))
|
||||
}
|
||||
}
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||
|
|
|
|||
|
|
@ -180,6 +180,7 @@ struct PermissionsFragment: View {
|
|||
)
|
||||
.frame(maxWidth: SharedMainViewModel.shared.maxWidth)
|
||||
.padding(.horizontal)
|
||||
.accessibilityIdentifier("permissions_skip_button")
|
||||
|
||||
Button {
|
||||
permissionManager.getPermissions()
|
||||
|
|
|
|||
|
|
@ -370,7 +370,7 @@ struct ContentView: View {
|
|||
|
||||
Button(action: {
|
||||
resetFilter()
|
||||
|
||||
|
||||
sharedMainViewModel.changeIndexView(indexViewInt: 1)
|
||||
sharedMainViewModel.displayedFriend = nil
|
||||
sharedMainViewModel.displayedConversation = nil
|
||||
|
|
@ -395,6 +395,7 @@ struct ContentView: View {
|
|||
}
|
||||
})
|
||||
.padding(.top)
|
||||
.accessibilityIdentifier("bottom_bar_calls_button")
|
||||
}
|
||||
|
||||
Spacer()
|
||||
|
|
@ -435,7 +436,7 @@ struct ContentView: View {
|
|||
.resizable()
|
||||
.foregroundStyle(sharedMainViewModel.indexView == 2 ? Color.orangeMain500 : Color.grayMain2c600)
|
||||
.frame(width: 25, height: 25)
|
||||
|
||||
|
||||
if sharedMainViewModel.indexView == 2 {
|
||||
Text("bottom_navigation_conversations_label")
|
||||
.default_text_style_700(styleSize: 10)
|
||||
|
|
@ -446,6 +447,7 @@ struct ContentView: View {
|
|||
}
|
||||
})
|
||||
.padding(.top)
|
||||
.accessibilityIdentifier("bottom_bar_chat_button")
|
||||
}
|
||||
|
||||
Spacer()
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ struct WelcomeView: View {
|
|||
Text("welcome_carousel_skip")
|
||||
.underline()
|
||||
.default_text_style_600(styleSize: 15)
|
||||
|
||||
|
||||
})
|
||||
.padding(.top, -35)
|
||||
.padding(.trailing, 20)
|
||||
|
|
@ -64,6 +64,7 @@ struct WelcomeView: View {
|
|||
self.index = 2
|
||||
}
|
||||
)
|
||||
.accessibilityIdentifier("welcome_skip_button")
|
||||
Text("welcome_page_title")
|
||||
.default_text_style_800(styleSize: 35)
|
||||
.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 */; };
|
||||
C642277D2E8E4E2B0094FEDC /* ColorExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D717071D2AC5922E0037746F /* ColorExtension.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 */; };
|
||||
C67586B02C09F247002E77BF /* URIHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = C67586AF2C09F247002E77BF /* URIHandler.swift */; };
|
||||
C67586B52C09F617002E77BF /* SingleSignOnManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C67586B22C09F617002E77BF /* SingleSignOnManager.swift */; };
|
||||
|
|
@ -240,6 +241,20 @@
|
|||
remoteGlobalIDString = 660AAF7A2B839271004C0FA6;
|
||||
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 */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = D719ABAB2ABC67BF00B41C10 /* Project object */;
|
||||
|
|
@ -309,6 +324,8 @@
|
|||
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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
|
|
@ -318,6 +335,7 @@
|
|||
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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
|
|
@ -537,6 +555,8 @@
|
|||
/* End PBXFileSystemSynchronizedBuildFileExceptionSet 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>"; };
|
||||
D792F15B2F02BCC2002E3225 /* intentsExtension */ = {isa = PBXFileSystemSynchronizedRootGroup; exceptions = (D792F1642F02BCC2002E3225 /* PBXFileSystemSynchronizedBuildFileExceptionSet */, ); explicitFileTypes = {}; explicitFolders = (); path = intentsExtension; sourceTree = "<group>"; };
|
||||
/* End PBXFileSystemSynchronizedRootGroup section */
|
||||
|
|
@ -552,6 +572,20 @@
|
|||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
C65271092F88D1CA00FF248C /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
C6E408AC2F8E1A33003E0F8C /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
D719ABB02ABC67BF00B41C10 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
|
|
@ -698,6 +732,7 @@
|
|||
D717071C2AC591EF0037746F /* Utils */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
C65271052F87D3E600FF248C /* MDMManager.swift */,
|
||||
D7BC10D82F4EF64E00F09BDA /* AudioMode.swift */,
|
||||
D7BC10D32F4EF18100F09BDA /* SoundPlayer.swift */,
|
||||
C642277A2E8E4AC50094FEDC /* ThemeManager.swift */,
|
||||
|
|
@ -732,6 +767,8 @@
|
|||
660AAF7C2B839272004C0FA6 /* msgNotificationService */,
|
||||
D7458F302E0BDCF4000C957A /* linphoneExtension */,
|
||||
D792F15B2F02BCC2002E3225 /* intentsExtension */,
|
||||
C652710D2F88D1CA00FF248C /* LinphoneAppUITests */,
|
||||
C6E408B02F8E1A33003E0F8C /* LinphoneAppTests */,
|
||||
D7DF8BE52E2104DC003A3BC7 /* Frameworks */,
|
||||
D719ABB42ABC67BF00B41C10 /* Products */,
|
||||
D7AEB9462F29128500298546 /* Shared.xcconfig */,
|
||||
|
|
@ -745,6 +782,8 @@
|
|||
660AAF7B2B839271004C0FA6 /* msgNotificationService.appex */,
|
||||
D7458F2F2E0BDCF4000C957A /* linphoneExtension.appex */,
|
||||
D792F1582F02BCC2002E3225 /* intentsExtension.appex */,
|
||||
C652710C2F88D1CA00FF248C /* LinphoneAppUITests.xctest */,
|
||||
C6E408AF2F8E1A33003E0F8C /* LinphoneAppTests.xctest */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -1261,6 +1300,52 @@
|
|||
productReference = 660AAF7B2B839271004C0FA6 /* msgNotificationService.appex */;
|
||||
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 */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = D719ABC22ABC67BF00B41C10 /* Build configuration list for PBXNativeTarget "LinphoneApp" */;
|
||||
|
|
@ -1342,6 +1427,14 @@
|
|||
CreatedOnToolsVersion = 15.0.1;
|
||||
LastSwiftMigration = 1500;
|
||||
};
|
||||
C652710B2F88D1CA00FF248C = {
|
||||
CreatedOnToolsVersion = 26.2;
|
||||
TestTargetID = D719ABB22ABC67BF00B41C10;
|
||||
};
|
||||
C6E408AE2F8E1A33003E0F8C = {
|
||||
CreatedOnToolsVersion = 26.2;
|
||||
TestTargetID = D719ABB22ABC67BF00B41C10;
|
||||
};
|
||||
D719ABB22ABC67BF00B41C10 = {
|
||||
CreatedOnToolsVersion = 14.3.1;
|
||||
};
|
||||
|
|
@ -1392,6 +1485,8 @@
|
|||
660AAF7A2B839271004C0FA6 /* msgNotificationService */,
|
||||
D7458F2E2E0BDCF4000C957A /* linphoneExtension */,
|
||||
D792F1572F02BCC2002E3225 /* intentsExtension */,
|
||||
C652710B2F88D1CA00FF248C /* LinphoneAppUITests */,
|
||||
C6E408AE2F8E1A33003E0F8C /* LinphoneAppTests */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
|
@ -1407,6 +1502,20 @@
|
|||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
C652710A2F88D1CA00FF248C /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
C6E408AD2F8E1A33003E0F8C /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
D719ABB12ABC67BF00B41C10 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
|
|
@ -1500,6 +1609,20 @@
|
|||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
C65271082F88D1CA00FF248C /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
C6E408AB2F8E1A33003E0F8C /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
D719ABAF2ABC67BF00B41C10 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
|
|
@ -1571,6 +1694,7 @@
|
|||
D7E2E69F2CE356C90080DA0D /* PopupViewWithTextField.swift in Sources */,
|
||||
C67586B52C09F617002E77BF /* SingleSignOnManager.swift in Sources */,
|
||||
D7F4D9CB2B5FD27200CDCD76 /* CallsListFragment.swift in Sources */,
|
||||
C65271062F87D3E600FF248C /* MDMManager.swift in Sources */,
|
||||
C6A5A9482C10B6A30070FEA4 /* AuthState.swift in Sources */,
|
||||
D72992392ADD7F68003AF125 /* HistoryContactFragment.swift in Sources */,
|
||||
D711B1342E93F18700DF8C71 /* LdapServerConfigurationFragment.swift in Sources */,
|
||||
|
|
@ -1712,6 +1836,16 @@
|
|||
target = 660AAF7A2B839271004C0FA6 /* msgNotificationService */;
|
||||
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 */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = D7458F2E2E0BDCF4000C957A /* linphoneExtension */;
|
||||
|
|
@ -1863,6 +1997,120 @@
|
|||
};
|
||||
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 */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = D7AEB9462F29128500298546 /* Shared.xcconfig */;
|
||||
|
|
@ -2260,6 +2508,24 @@
|
|||
defaultConfigurationIsVisible = 0;
|
||||
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" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
|
|
|
|||
|
|
@ -28,6 +28,30 @@
|
|||
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>
|
||||
<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"
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||

|
||||
|
||||
# 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