I am making a Multiplatform SwiftUI app.
After some preliminary struggles, I used to be capable of create a listing of information and add them to my app’s bundle. At launch time, I attempt to use the Bundle operate Bundle.major.paths(forResourcesOfType:) to search out these information and open them.
The Mac model of the app finds the information simply advantageous. After I run the identical code on the iOS model, it returns an empty array of file paths.
I can navigate to the app bundle for the simulator model of the app within the finder, open it with “present package deal contents”, and see my folder within the bundle plain as day, with the information I’ve written to it. Nonetheless, Bundle.major.paths(forResourcesOfType:) returns an empty checklist.
I initially tried getting the bundle sources path appending my folder title to that, and utilizing the file supervisor to fetch the checklist of information, however that failed, so I switched to utilizing the Bundle technique.
Each approaches work on macOS, and each fail on iOS.
Is there some sandboxing challenge I am not conscious of?
Right here is my code:
static var scopeTemplates: [ScopeTemplate] = {
let fileManager = FileManager.default
let folderName = "Kaleidoscope_Templates"
do {
if let bundlePath = Bundle.major.resourcePath {
print("bundlePath = (bundlePath)")
} else {
print("Cannot resolve bundle path")
}
// previous path-based code.
//let kaleidoscopeTemplateFileNames = Bundle.major.paths(forResourcesOfType: "json", inDirectory: folderName)
//let kaleidoscopeTemplateURLs = kaleidoscopeTemplateFileNames.map { URL(filePath: $0) }
guard let kaleidoscopeTemplateURLs = Bundle.major.urls(forResourcesWithExtension: "json", subdirectory: folderName) else {
fatalError("Cannot discover folder (folderName)")
}
let decoder = JSONDecoder()
var scopeTemplates = [ScopeTemplate]()
for aFileURL in kaleidoscopeTemplateURLs {
print("filename = (aFileURL.path)")
let knowledge = strive Knowledge(contentsOf: aFileURL)
let aScopeTemplate = strive decoder.decode(ScopeTemplate.self, from: knowledge)
scopeTemplates.append(aScopeTemplate)
}
return scopeTemplates.sorted() { lhv, rhv in
return lhv.index < rhv.index
}
} catch {
fatalError("Error (error) studying template information")
}
}()
(This model of the code does not crash, and does not log any errors, nevertheless it returns an empty array. The FileManager model threw an exception on iOS after I tried to fetch the information in my listing, however that model additionally labored on macOS.)
Additionally notice that the bundle construction seems to be an identical in iOS and MacOS. I take advantage of the finder “Go to Folder” menu command to open the listing within the bundle within the sim and it seems to be precisely as anticipated.
I simply created a minimal repeatable mission and printed it on Github:
https://github.com/DuncanMC/BundleFiles.git
That code seems to be like this:
static var scopeTemplates: [ScopeTemplate] = {
let fileManager = FileManager.default
let folderName = "Kaleidoscope_Templates"
do {
if let bundlePath = Bundle.major.resourcePath {
print("bundlePath = (bundlePath)")
} else {
print("Cannot resolve bundle path")
}
guard let kaleidoscopeTemplateURLs = Bundle.major.urls(forResourcesWithExtension: "json", subdirectory: folderName) else {
fatalError("Cannot discover folder (folderName)")
}
print("Listing (folderName) in bundle sources accommodates (kaleidoscopeTemplateURLs.depend) information.")
let decoder = JSONDecoder()
var scopeTemplates = [ScopeTemplate]()
for aFileURL in kaleidoscopeTemplateURLs {
print("filename = (aFileURL.path)")
let knowledge = strive Knowledge(contentsOf: aFileURL)
let aScopeTemplate = strive decoder.decode(ScopeTemplate.self, from: knowledge)
scopeTemplates.append(aScopeTemplate)
}
return scopeTemplates.sorted() { lhv, rhv in
return lhv.index < rhv.index
}
} catch {
fatalError("Error (error) studying template information")
}
}()
(The mission on Github has the Xcode mission, the folder-full of information, and many others. It’ is ready up as a SwiftUI Multiplatform mission similar to the true app I am scuffling with.)
When run within the iOS simulator it logs the bundle path as anticipated:
bundlePath = /Customers/duncan/Library/Developer/CoreSimulator/Gadgets/EABDE8A8-0CAC-4D5F-81EF-FB03DC809EE5/knowledge/Containers/Bundle/Utility/8EA76044-8F14-4783-A45B-423A35F1EB4F/BundleFiles.app
After which logs
Listing Kaleidoscope_Templates in bundle sources accommodates 0 information.
The identical code run on my Mac hundreds and decodes the 4 information from the bundle because it ought to.
When run on a Mac, the bundle path ends with Contents/Assets, however on iOS, it’s the top-level app bundle listing. (I consider that’s anticipated conduct.)
