ios: file provider service

This commit is contained in:
Evgeny Poberezkin 2022-06-01 17:26:15 +01:00
parent fa844c48e9
commit 1b972bc7cc
6 changed files with 431 additions and 3 deletions

View File

@ -0,0 +1,51 @@
//
// FileProviderEnumerator.swift
// SimpleX Service
//
// Created by Evgeny on 01/06/2022.
// Copyright © 2022 SimpleX Chat. All rights reserved.
//
import FileProvider
class FileProviderEnumerator: NSObject, NSFileProviderEnumerator {
var enumeratedItemIdentifier: NSFileProviderItemIdentifier
init(enumeratedItemIdentifier: NSFileProviderItemIdentifier) {
self.enumeratedItemIdentifier = enumeratedItemIdentifier
super.init()
}
func invalidate() {
// TODO: perform invalidation of server connection if necessary
}
func enumerateItems(for observer: NSFileProviderEnumerationObserver, startingAt page: NSFileProviderPage) {
/* TODO:
- inspect the page to determine whether this is an initial or a follow-up request
If this is an enumerator for a directory, the root container or all directories:
- perform a server request to fetch directory contents
If this is an enumerator for the active set:
- perform a server request to update your local database
- fetch the active set from your local database
- inform the observer about the items returned by the server (possibly multiple times)
- inform the observer that you are finished with this page
*/
}
func enumerateChanges(for observer: NSFileProviderChangeObserver, from anchor: NSFileProviderSyncAnchor) {
/* TODO:
- query the server for updates since the passed-in sync anchor
If this is an enumerator for the active set:
- note the changes in your local database
- inform the observer about item deletions and updates (modifications + insertions)
- inform the observer when you have finished enumerating up to a subsequent sync anchor
*/
}
}

View File

@ -0,0 +1,160 @@
//
// FileProviderExtension.swift
// SimpleX Service
//
// Created by Evgeny on 01/06/2022.
// Copyright © 2022 SimpleX Chat. All rights reserved.
//
import FileProvider
class FileProviderExtension: NSFileProviderExtension {
var fileManager = FileManager()
override init() {
super.init()
}
override func item(for identifier: NSFileProviderItemIdentifier) throws -> NSFileProviderItem {
// resolve the given identifier to a record in the model
// TODO: implement the actual lookup
return FileProviderItem()
}
override func urlForItem(withPersistentIdentifier identifier: NSFileProviderItemIdentifier) -> URL? {
// resolve the given identifier to a file on disk
guard let item = try? item(for: identifier) else {
return nil
}
// in this implementation, all paths are structured as <base storage directory>/<item identifier>/<item file name>
let manager = NSFileProviderManager.default
let perItemDirectory = manager.documentStorageURL.appendingPathComponent(identifier.rawValue, isDirectory: true)
return perItemDirectory.appendingPathComponent(item.filename, isDirectory:false)
}
override func persistentIdentifierForItem(at url: URL) -> NSFileProviderItemIdentifier? {
// resolve the given URL to a persistent identifier using a database
let pathComponents = url.pathComponents
// exploit the fact that the path structure has been defined as
// <base storage directory>/<item identifier>/<item file name> above
assert(pathComponents.count > 2)
return NSFileProviderItemIdentifier(pathComponents[pathComponents.count - 2])
}
override func providePlaceholder(at url: URL, completionHandler: @escaping (Error?) -> Void) {
guard let identifier = persistentIdentifierForItem(at: url) else {
completionHandler(NSFileProviderError(.noSuchItem))
return
}
do {
let fileProviderItem = try item(for: identifier)
let placeholderURL = NSFileProviderManager.placeholderURL(for: url)
try NSFileProviderManager.writePlaceholder(at: placeholderURL,withMetadata: fileProviderItem)
completionHandler(nil)
} catch let error {
completionHandler(error)
}
}
override func startProvidingItem(at url: URL, completionHandler: @escaping ((_ error: Error?) -> Void)) {
// Should ensure that the actual file is in the position returned by URLForItemWithIdentifier:, then call the completion handler
/* TODO:
This is one of the main entry points of the file provider. We need to check whether the file already exists on disk,
whether we know of a more recent version of the file, and implement a policy for these cases. Pseudocode:
if !fileOnDisk {
downloadRemoteFile()
callCompletion(downloadErrorOrNil)
} else if fileIsCurrent {
callCompletion(nil)
} else {
if localFileHasChanges {
// in this case, a version of the file is on disk, but we know of a more recent version
// we need to implement a strategy to resolve this conflict
moveLocalFileAside()
scheduleUploadOfLocalFile()
downloadRemoteFile()
callCompletion(downloadErrorOrNil)
} else {
downloadRemoteFile()
callCompletion(downloadErrorOrNil)
}
}
*/
completionHandler(NSError(domain: NSCocoaErrorDomain, code: NSFeatureUnsupportedError, userInfo:[:]))
}
override func itemChanged(at url: URL) {
// Called at some point after the file has changed; the provider may then trigger an upload
/* TODO:
- mark file at <url> as needing an update in the model
- if there are existing NSURLSessionTasks uploading this file, cancel them
- create a fresh background NSURLSessionTask and schedule it to upload the current modifications
- register the NSURLSessionTask with NSFileProviderManager to provide progress updates
*/
}
override func stopProvidingItem(at url: URL) {
// Called after the last claim to the file has been released. At this point, it is safe for the file provider to remove the content file.
// Care should be taken that the corresponding placeholder file stays behind after the content file has been deleted.
// Called after the last claim to the file has been released. At this point, it is safe for the file provider to remove the content file.
// TODO: look up whether the file has local changes
let fileHasLocalChanges = false
if !fileHasLocalChanges {
// remove the existing file to free up space
do {
_ = try FileManager.default.removeItem(at: url)
} catch {
// Handle error
}
// write out a placeholder to facilitate future property lookups
self.providePlaceholder(at: url, completionHandler: { error in
// TODO: handle any error, do any necessary cleanup
})
}
}
// MARK: - Actions
/* TODO: implement the actions for items here
each of the actions follows the same pattern:
- make a note of the change in the local model
- schedule a server request as a background task to inform the server of the change
- call the completion block with the modified item in its post-modification state
*/
// MARK: - Enumeration
override func enumerator(for containerItemIdentifier: NSFileProviderItemIdentifier) throws -> NSFileProviderEnumerator {
let maybeEnumerator: NSFileProviderEnumerator? = nil
if (containerItemIdentifier == NSFileProviderItemIdentifier.rootContainer) {
// TODO: instantiate an enumerator for the container root
} else if (containerItemIdentifier == NSFileProviderItemIdentifier.workingSet) {
// TODO: instantiate an enumerator for the working set
} else {
// TODO: determine if the item is a directory or a file
// - for a directory, instantiate an enumerator of its subitems
// - for a file, instantiate an enumerator that observes changes to the file
}
guard let enumerator = maybeEnumerator else {
throw NSError(domain: NSCocoaErrorDomain, code: NSFeatureUnsupportedError, userInfo:[:])
}
return enumerator
}
}

View File

@ -0,0 +1,37 @@
//
// FileProviderItem.swift
// SimpleX Service
//
// Created by Evgeny on 01/06/2022.
// Copyright © 2022 SimpleX Chat. All rights reserved.
//
import FileProvider
import UniformTypeIdentifiers
class FileProviderItem: NSObject, NSFileProviderItem {
// TODO: implement an initializer to create an item from your extension's backing model
// TODO: implement the accessors to return the values from your extension's backing model
var itemIdentifier: NSFileProviderItemIdentifier {
return NSFileProviderItemIdentifier("")
}
var parentItemIdentifier: NSFileProviderItemIdentifier {
return NSFileProviderItemIdentifier("")
}
var capabilities: NSFileProviderItemCapabilities {
return [.allowsReading, .allowsWriting, .allowsRenaming, .allowsReparenting, .allowsTrashing, .allowsDeleting]
}
var filename: String {
return ""
}
var contentType: UTType {
return itemIdentifier == NSFileProviderItemIdentifier.rootContainer ? .folder : .plainText
}
}

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSExtension</key>
<dict>
<key>NSExtensionFileProviderDocumentGroup</key>
<string>group.chat.simplex.app</string>
<key>NSExtensionFileProviderSupportsEnumeration</key>
<true/>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.fileprovider-nonui</string>
<key>NSExtensionPrincipalClass</key>
<string>$(PRODUCT_MODULE_NAME).FileProviderExtension</string>
</dict>
</dict>
</plist>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.application-groups</key>
<array>
<string>group.chat.simplex.app</string>
</array>
</dict>
</plist>

View File

@ -19,6 +19,11 @@
5C116CDC27AABE0400E66D01 /* ContactRequestView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C116CDB27AABE0400E66D01 /* ContactRequestView.swift */; };
5C13730B28156D2700F43030 /* ContactConnectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C13730A28156D2700F43030 /* ContactConnectionView.swift */; };
5C1A4C1E27A715B700EAD5AD /* ChatItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C1A4C1D27A715B700EAD5AD /* ChatItemView.swift */; };
5C1CAA172847C5C8009E5C72 /* UniformTypeIdentifiers.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C1CAA162847C5C8009E5C72 /* UniformTypeIdentifiers.framework */; };
5C1CAA1A2847C5C8009E5C72 /* FileProviderExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C1CAA192847C5C8009E5C72 /* FileProviderExtension.swift */; };
5C1CAA1C2847C5C8009E5C72 /* FileProviderItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C1CAA1B2847C5C8009E5C72 /* FileProviderItem.swift */; };
5C1CAA1E2847C5C8009E5C72 /* FileProviderEnumerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C1CAA1D2847C5C8009E5C72 /* FileProviderEnumerator.swift */; };
5C1CAA232847C5C8009E5C72 /* SimpleX Service.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 5C1CAA152847C5C8009E5C72 /* SimpleX Service.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
5C2E260727A2941F00F70299 /* SimpleXAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C2E260627A2941F00F70299 /* SimpleXAPI.swift */; };
5C2E260B27A30CFA00F70299 /* ChatListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C2E260A27A30CFA00F70299 /* ChatListView.swift */; };
5C2E260F27A30FDC00F70299 /* ChatView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C2E260E27A30FDC00F70299 /* ChatView.swift */; };
@ -116,6 +121,13 @@
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
5C1CAA212847C5C8009E5C72 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 5CA059BE279559F40002BEB4 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 5C1CAA142847C5C8009E5C72;
remoteInfo = "SimpleX Service";
};
5CA059D8279559F40002BEB4 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 5CA059BE279559F40002BEB4 /* Project object */;
@ -164,6 +176,7 @@
dstPath = "";
dstSubfolderSpec = 13;
files = (
5C1CAA232847C5C8009E5C72 /* SimpleX Service.appex in Embed App Extensions */,
5CE2BA9D284555F500EC33A6 /* SimpleX NSE.appex in Embed App Extensions */,
);
name = "Embed App Extensions";
@ -185,6 +198,13 @@
5C13730A28156D2700F43030 /* ContactConnectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactConnectionView.swift; sourceTree = "<group>"; };
5C13730C2815740A00F43030 /* DebugJSON.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = DebugJSON.playground; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
5C1A4C1D27A715B700EAD5AD /* ChatItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatItemView.swift; sourceTree = "<group>"; };
5C1CAA152847C5C8009E5C72 /* SimpleX Service.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "SimpleX Service.appex"; sourceTree = BUILT_PRODUCTS_DIR; };
5C1CAA162847C5C8009E5C72 /* UniformTypeIdentifiers.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UniformTypeIdentifiers.framework; path = System/Library/Frameworks/UniformTypeIdentifiers.framework; sourceTree = SDKROOT; };
5C1CAA192847C5C8009E5C72 /* FileProviderExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileProviderExtension.swift; sourceTree = "<group>"; };
5C1CAA1B2847C5C8009E5C72 /* FileProviderItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileProviderItem.swift; sourceTree = "<group>"; };
5C1CAA1D2847C5C8009E5C72 /* FileProviderEnumerator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileProviderEnumerator.swift; sourceTree = "<group>"; };
5C1CAA1F2847C5C8009E5C72 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
5C1CAA202847C5C8009E5C72 /* SimpleX_Service.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = SimpleX_Service.entitlements; sourceTree = "<group>"; };
5C2E260627A2941F00F70299 /* SimpleXAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimpleXAPI.swift; sourceTree = "<group>"; };
5C2E260A27A30CFA00F70299 /* ChatListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatListView.swift; sourceTree = "<group>"; };
5C2E260E27A30FDC00F70299 /* ChatView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatView.swift; sourceTree = "<group>"; };
@ -286,6 +306,14 @@
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
5C1CAA122847C5C8009E5C72 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
5C1CAA172847C5C8009E5C72 /* UniformTypeIdentifiers.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
5CA059C7279559F40002BEB4 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
@ -342,6 +370,18 @@
path = Call;
sourceTree = "<group>";
};
5C1CAA182847C5C8009E5C72 /* SimpleX Service */ = {
isa = PBXGroup;
children = (
5C1CAA192847C5C8009E5C72 /* FileProviderExtension.swift */,
5C1CAA1B2847C5C8009E5C72 /* FileProviderItem.swift */,
5C1CAA1D2847C5C8009E5C72 /* FileProviderEnumerator.swift */,
5C1CAA1F2847C5C8009E5C72 /* Info.plist */,
5C1CAA202847C5C8009E5C72 /* SimpleX_Service.entitlements */,
);
path = "SimpleX Service";
sourceTree = "<group>";
};
5C2E260D27A30E2400F70299 /* Views */ = {
isa = PBXGroup;
children = (
@ -391,6 +431,7 @@
5CDCAD5E28187D4A00503DA2 /* libiconv.tbd */,
5C764E7C279C71DB000C6508 /* libz.tbd */,
5C764E7B279C71D4000C6508 /* libiconv.tbd */,
5C1CAA162847C5C8009E5C72 /* UniformTypeIdentifiers.framework */,
);
name = Frameworks;
sourceTree = "<group>";
@ -432,9 +473,10 @@
5C422A7C27A9A6FA0097A1E1 /* SimpleX (iOS).entitlements */,
5C764E5C279C70B7000C6508 /* Libraries */,
5CA059C2279559F40002BEB4 /* Shared */,
5CDCAD462818589900503DA2 /* SimpleX NSE */,
5CA059DA279559F40002BEB4 /* Tests iOS */,
5CE2BA692845308900EC33A6 /* SimpleXChat */,
5CDCAD462818589900503DA2 /* SimpleX NSE */,
5C1CAA182847C5C8009E5C72 /* SimpleX Service */,
5CA059DA279559F40002BEB4 /* Tests iOS */,
5CA059CB279559F40002BEB4 /* Products */,
5C764E7A279C71D4000C6508 /* Frameworks */,
);
@ -461,6 +503,7 @@
5CA059D7279559F40002BEB4 /* Tests iOS.xctest */,
5CDCAD452818589900503DA2 /* SimpleX NSE.appex */,
5CE2BA682845308900EC33A6 /* SimpleXChat.framework */,
5C1CAA152847C5C8009E5C72 /* SimpleX Service.appex */,
);
name = Products;
sourceTree = "<group>";
@ -611,6 +654,23 @@
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
5C1CAA142847C5C8009E5C72 /* SimpleX Service */ = {
isa = PBXNativeTarget;
buildConfigurationList = 5C1CAA262847C5C8009E5C72 /* Build configuration list for PBXNativeTarget "SimpleX Service" */;
buildPhases = (
5C1CAA112847C5C8009E5C72 /* Sources */,
5C1CAA122847C5C8009E5C72 /* Frameworks */,
5C1CAA132847C5C8009E5C72 /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = "SimpleX Service";
productName = "SimpleX Service";
productReference = 5C1CAA152847C5C8009E5C72 /* SimpleX Service.appex */;
productType = "com.apple.product-type.app-extension";
};
5CA059C9279559F40002BEB4 /* SimpleX (iOS) */ = {
isa = PBXNativeTarget;
buildConfigurationList = 5CA059F3279559F40002BEB4 /* Build configuration list for PBXNativeTarget "SimpleX (iOS)" */;
@ -626,6 +686,7 @@
dependencies = (
5CE2BA6F2845308900EC33A6 /* PBXTargetDependency */,
5CE2BA9F284555F500EC33A6 /* PBXTargetDependency */,
5C1CAA222847C5C8009E5C72 /* PBXTargetDependency */,
);
name = "SimpleX (iOS)";
packageProductDependencies = (
@ -700,6 +761,9 @@
LastUpgradeCheck = 1330;
ORGANIZATIONNAME = "SimpleX Chat";
TargetAttributes = {
5C1CAA142847C5C8009E5C72 = {
CreatedOnToolsVersion = 13.3;
};
5CA059C9279559F40002BEB4 = {
CreatedOnToolsVersion = 13.2.1;
LastSwiftMigration = 1320;
@ -736,13 +800,21 @@
targets = (
5CA059C9279559F40002BEB4 /* SimpleX (iOS) */,
5CA059D6279559F40002BEB4 /* Tests iOS */,
5CDCAD442818589900503DA2 /* SimpleX NSE */,
5CE2BA672845308900EC33A6 /* SimpleXChat */,
5CDCAD442818589900503DA2 /* SimpleX NSE */,
5C1CAA142847C5C8009E5C72 /* SimpleX Service */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
5C1CAA132847C5C8009E5C72 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
5CA059C8279559F40002BEB4 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
@ -781,6 +853,16 @@
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
5C1CAA112847C5C8009E5C72 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
5C1CAA1A2847C5C8009E5C72 /* FileProviderExtension.swift in Sources */,
5C1CAA1C2847C5C8009E5C72 /* FileProviderItem.swift in Sources */,
5C1CAA1E2847C5C8009E5C72 /* FileProviderEnumerator.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
5CA059C6279559F40002BEB4 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
@ -896,6 +978,11 @@
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
5C1CAA222847C5C8009E5C72 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 5C1CAA142847C5C8009E5C72 /* SimpleX Service */;
targetProxy = 5C1CAA212847C5C8009E5C72 /* PBXContainerItemProxy */;
};
5CA059D9279559F40002BEB4 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 5CA059C9279559F40002BEB4 /* SimpleX (iOS) */;
@ -956,6 +1043,63 @@
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
5C1CAA242847C5C8009E5C72 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_ENTITLEMENTS = "SimpleX Service/SimpleX_Service.entitlements";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = "SimpleX Service/Info.plist";
INFOPLIST_KEY_CFBundleDisplayName = "SimpleX Service";
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2022 SimpleX Chat. All rights reserved.";
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.app.SimpleX-Service";
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
5C1CAA252847C5C8009E5C72 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_ENTITLEMENTS = "SimpleX Service/SimpleX_Service.entitlements";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = "SimpleX Service/Info.plist";
INFOPLIST_KEY_CFBundleDisplayName = "SimpleX Service";
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2022 SimpleX Chat. All rights reserved.";
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.app.SimpleX-Service";
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
5CA059F1279559F40002BEB4 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
@ -1371,6 +1515,15 @@
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
5C1CAA262847C5C8009E5C72 /* Build configuration list for PBXNativeTarget "SimpleX Service" */ = {
isa = XCConfigurationList;
buildConfigurations = (
5C1CAA242847C5C8009E5C72 /* Debug */,
5C1CAA252847C5C8009E5C72 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
5CA059C1279559F40002BEB4 /* Build configuration list for PBXProject "SimpleX" */ = {
isa = XCConfigurationList;
buildConfigurations = (