Any information on MCMErrorDomain error 44? - swift

I am running into "MCMErrorDomain error 44" about 50% of the time on app.launch() when loading a container to my app. I have no idea what is the cause and I can't find any information about this error.
This is the code I am using to load container to the app.
extension AppDelegate {
func loadAppData(appDataPath: String) {
let loaderUrl = URL(fileURLWithPath: #file)
let bundleUrl = URL(fileURLWithPath: appDataPath, relativeTo: loaderUrl).appendingPathExtension("xcappdata")
let contentsURL = bundleUrl.appendingPathComponent("AppData")
let fileManager = FileManager.default
let enumerator = fileManager.enumerator(at: contentsURL,
includingPropertiesForKeys: [.isDirectoryKey],
options: [],
//swiftlint:disable:next force_unwrapping
errorHandler: nil)!
//swiftlint:disable:next force_unwrapping
let destinationRoot = fileManager.urls(for: .libraryDirectory, in: .userDomainMask).last!.deletingLastPathComponent()
let test = fileManager.enumerator(at: destinationRoot,
includingPropertiesForKeys: [.isDirectoryKey],
options: [],
//swiftlint:disable:next force_unwrapping
errorHandler: nil)!
while let lol = test.nextObject() as? URL {
do {
try fileManager.removeItem(at: lol)
} catch {
print("✌️ \(error)")
}
}
print("✌️ \(destinationRoot)")
let sourceRoot = contentsURL.standardizedFileURL.path
while let sourceUrl = enumerator.nextObject() as? URL {
guard let resourceValues = try? sourceUrl.resourceValues(forKeys: [.isDirectoryKey]),
let isDirectory = resourceValues.isDirectory,
!isDirectory else {
continue
}
let path = sourceUrl.standardizedFileURL.path.replacingOccurrences(of: sourceRoot, with: "")
let destinationURL = destinationRoot.appendingPathComponent(path)
do {
try fileManager.createDirectory(at: destinationURL.deletingLastPathComponent(),
withIntermediateDirectories: true,
attributes: nil)
try fileManager.copyItem(at: sourceUrl,
to: destinationURL)
} catch {
print("✌️ \(error)")
do {
_ = try fileManager.replaceItemAt(destinationURL, withItemAt: sourceUrl)
} catch {
print("✌️ \(error)")
}
}
}
print("done")
}
}

Yes, MCMErrorDomain is frustrating, as it not documented by Apple.
When I encounter it, the full description reads:
The test runner encountered an error (Failed to install or launch the
test runner. (Underlying error: The operation couldn’t be completed.
(MCMErrorDomain error 44.)))
The workaround I found is to delete the app from simulator and re-run the test.
So far, here is what I am learning about this particular error:
it looks as it is coming from MobileContainerManager.framework
often caused by interrupting a running test on simulator.
once it happens the simulator often in permanently "damaged" state until app is deleted.
only happens for Application tests, that require host app, never for Logic tests.
happens only at the beginning of a test suite
often caused by Xcode Bot trying to use the same simulator that Xcode is already using.
Framework Location:
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/System/Library/PrivateFrameworks/MobileContainerManager.framework
shows entries for MCMErrorDomain in MobileContainerManager binary and in containermanagerd

Related

Listing all files in a directory on macOS Big Sur

In a different question I asked how to save files on a directory of the user's choosing. The reply was the following code, which works great.
func resolveURL(for key: String) throws -> URL {
if let data = UserDefaults.standard.data(forKey: key) {
var isStale = false
let url = try URL(resolvingBookmarkData: data, options:[.withSecurityScope], bookmarkDataIsStale: &isStale)
if isStale {
let newData = try url.bookmarkData(options: [.withSecurityScope])
UserDefaults.standard.set(newData, forKey: key)
}
return url
} else {
let panel = NSOpenPanel()
panel.allowsMultipleSelection = false
panel.canChooseDirectories = true
panel.canCreateDirectories = true
panel.canChooseFiles = false
if panel.runModal() == .OK,
let url = panel.url {
let newData = try url.bookmarkData(options: [.withSecurityScope])
UserDefaults.standard.set(newData, forKey: key)
return url
} else {
throw ResolveError.cancelled
}
}
}
func saveFile(filename: String, contents: String) {
do {
let directoryURL = try resolveURL(for: "savedDirectory")
let documentURL = directoryURL.appendingPathComponent (filename + ".txt")
print("saving " + documentURL.absoluteString)
try directoryURL.accessSecurityScopedResource(at: documentURL) { url in
try contents.write (to: url, atomically: false, encoding: .utf8)
}
} catch let error as ResolveError {
print("Resolve error:", error)
} catch {
print(error)
}
}
Now, the next step is to go to the directory the user chose when the app loads, and if any files are there, ready each one and add the contents of those files to the struct I use to hold the data.
Googling a little bit I found that you can read all files in a directory using FileManager.default.contentsOfDirectory so I wrote:
func loadFiles() {
do {
let directoryURL = try resolveURL(for: "savedDirectory")
let contents = try FileManager.default.contentsOfDirectory(at: directoryURL,
includingPropertiesForKeys: nil,
options: [.skipsHiddenFiles])
for file in contents {
print(file.absoluteString)
}
} catch let error as ResolveError {
print("Resolve error:", error)
return
} catch {
print(error)
return
}
}
But, I get the following error:
Error Domain=NSCocoaErrorDomain Code=257 "The file “myFiles” couldn’t be opened because you don’t have permission to view it." UserInfo={NSURL=file:///Users/aleph/myFiles, NSFilePath=/Users/aleph/myFiles, NSUnderlyingError=0x600000704ba0 {Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted"}}
which looking at my code I would guess it's happening because I'm not using directoryURL.accessSecurityScopedResource. I tried to add that, or find any other way, but I'm running into a block and I don't know how to get to the directory saved in savedDirectory, and go through every file, reading its contents.
Thank you for any help
If I use:
directoryURL.startAccessingSecurityScopedResource()
// load the files
directoryURL.stopAccessingSecurityScopedResource()
Then it works.

How to pre-load Core Data with a SQLite file that have references to images that were saved using "external storage"?

My goal is pre-loading Core Data, at the first app launch. So far I ran a simulation and filled Core Data with data. (I had checked "allow external Storage").
I went into application_support and copied: MyApp.sqlite-wal, MyApp.sqlite-shm, .MyApp_SUPPORT/_EXTERNAL_DATA/ and MyApp.sqlite.
Then I added the MyApp.sqlite file in my app bundle and added this code in my app delegate:
lazy var persistentContainer: NSPersistentContainer = {
let modelName = "MyApp"
var container: NSPersistentContainer!
container = NSPersistentContainer(name: modelName)
// Preloading
let appName: String = "MyApp"
var persistentStoreDescriptions: NSPersistentStoreDescription
let storeUrl = self.getDocumentsDirectory().appendingPathComponent("MyApp.sqlite")
if !FileManager.default.fileExists(atPath: (storeUrl.path)) {
let seededDataUrl = Bundle.main.url(forResource: appName, withExtension: "sqlite")
try! FileManager.default.copyItem(at: seededDataUrl!, to: storeUrl)
}
let description = NSPersistentStoreDescription()
description.shouldInferMappingModelAutomatically = true
description.shouldMigrateStoreAutomatically = true
description.url = storeUrl
container.persistentStoreDescriptions = [description]
//End Preloading
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
return container
}()
It works but It looks like it doesn't find the images that were saved in external storage. They're present in .MyApp_SUPPORT/_EXTERNAL_DATA as references.
Where should I add the references?
Load everything is my goal.
If you have a file named MyApp.sqlite with external binary storage in some directory (here, the app bundle), Core Data puts those files in a sub-directory named .MyApp_SUPPORT/_EXTERNAL_DATA/. You need to recursively copy that directory and everything in its sub-directories.
Using that path is not a good idea, though, because it's undocumented and could change without warning. Also, this will miss MyApp.sqlite-wal and MyApp.sqlite-shm, if they exist.
A better idea is to put the seed store in a custom directory of its own, and copy everything from that directory. Instead of just having MyApp.sqlite, you'd have a directory named MyAppSeedData which would contain MyApp.sqlite. It would also contain all the other stuff Core Data needs like the external binary files. Use the same FileManager function to copy the MyAppSeedData directory (because it will recursively copy every file) and you should be fine.
The code to copy the folder would be something like this:
if let sourceDirURL = Bundle.main.url(forResource: "Source Folder", withExtension: nil) {
let destinationDirURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!.appendingPathComponent("TestFolder")
if !FileManager.default.fileExists(atPath: destinationDirURL.path) {
do {
try FileManager.default.copyItem(at: sourceDirURL, to: destinationDirURL)
} catch {
print("Error copying directory: \(error)")
}
}
}
You could then add the SQLite file name to the end of destinationDirURL and use it for Core Data.
Step 1: Create "MyAppSeedData" dir and paste MyApp.sqlite, the MyApp_SUPPORT, the MyApp.sqilte-smh, MyApp.sqilte-wal files inside.
Step 2: Drag MyAppSeedData to the bundle under AppDelegate and tick the box add target.
Step 3: These functions must be in AppDelegate file:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool
{
//If first launch condition == true {
seedData()
//}
return true
}
func seedData() {
let fm = FileManager.default
//Destination URL: Application Folder
let libURL = fm.urls(for: .libraryDirectory, in: .userDomainMask).first!
let destFolder = libURL.appendingPathComponent("Application Support").path
//Or
//let l1 = NSSearchPathForDirectoriesInDomains(.applicationSupportDirectory, .userDomainMask, true).last!
//
//Starting URL: MyAppSeedData dir
let folderPath = Bundle.main.resourceURL!.appendingPathComponent("MyAppSeedData").path
let fileManager = FileManager.default
let urls = fileManager.urls(for: .applicationSupportDirectory, in: .userDomainMask)
if let applicationSupportURL = urls.last {
do{
try fileManager.createDirectory(at: applicationSupportURL, withIntermediateDirectories: true, attributes: nil)
}
catch{
print(error)
}
}
copyFiles(pathFromBundle: folderPath, pathDestDocs: destFolder)
}
func copyFiles(pathFromBundle : String, pathDestDocs: String) {
let fm = FileManager.default
do {
let filelist = try fm.contentsOfDirectory(atPath: pathFromBundle)
let fileDestList = try fm.contentsOfDirectory(atPath: pathDestDocs)
for filename in fileDestList {
try FileManager.default.removeItem(atPath: "\(pathDestDocs)/\(filename)")
}
for filename in filelist {
try? fm.copyItem(atPath: "\(pathFromBundle)/\(filename)", toPath: "\(pathDestDocs)/\(filename)")
}
} catch {
print("Error info: \(error)")
}
}
// MARK: - Core Data stack
lazy var persistentContainer: NSPersistentContainer = {
let modelName = "MyApp"
var container: NSPersistentContainer!
container = NSPersistentContainer(name: modelName)
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
return container
}()

How to add or delete rule of safari content block list at run time

I am using in my project safari content blocker extension. when i set the rule in blockerList.json file statically and run the project every thing is working fine. Now i want to set my rule dynamically using the technic as it describes in below.
Guys please help me out to set the rule dynamically at run time.
I try this but i am getting an error when
load from viewcontroller class
fileprivate func saveRuleFile() {
let ruleList = [["trigger":["url-filter": ".*"],"action":["type": "block"]]]
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted
if let encoded = try? encoder.encode(ruleList) {
let sharedContainerURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.****.***")
print("sharedContainerURL = \(String(describing: sharedContainerURL))")
if let json = String(data: encoded, encoding: .utf8) {
print(json)
}
if let destinationURL = sharedContainerURL?.appendingPathComponent("Rules.json") {
do {
try encoded.write(to: destinationURL)
} catch {
print (error)
}
}
}
}
And write this in ContentBlockerRequestHandler class
func beginRequest(with context: NSExtensionContext) {
let sharedContainerURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.****.***")
let sourceURL = sharedContainerURL?.appendingPathComponent("Rules.json")
let ruleAttachment = NSItemProvider(contentsOf: sourceURL)
let item = NSExtensionItem()
item.attachments = ([ruleAttachment] as! [NSItemProvider])
context.completeRequest(returningItems: [item], completionHandler: nil)
}
i try to load using
SFContentBlockerManager.reloadContentBlocker(withIdentifier: "com.app.*****", completionHandler: {(error) in
if error != nil{
print("error: \(error.debugDescription)")
}
})
when try to execute 3rd number block at run time i'm getting an error. But i go to the file path and checked the json is absolutely fine, its a valid json there.
Error Domain=WKErrorDomain Code=2 "(null)" UserInfo={NSHelpAnchor=Rule list compilation failed: Failed to parse the JSON String.}
Try to use JSONSerialization. It work great for me :)
fileprivate func saveRuleFile() {
let ruleList = [["trigger":["url-filter": ".*"],"action":["type": "block"]]]
let jsonAsData = try! JSONSerialization.data(withJSONObject: ruleList)
let sharedContainerURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.****.***")
print("sharedContainerURL = \(String(describing: sharedContainerURL))")
if let destinationURL = sharedContainerURL?.appendingPathComponent("Rules.json") {
do {
try jsonAsData.write(to: destinationURL)
} catch {
print (error)
}
}
}

Swift - save video from url

I would like to download a movie from a URL and save to iPhone.
I use this function
func downloadVideo(videoUrl: URL, name: String) {
let sampleURL = videoUrl.absoluteString
DispatchQueue.global(qos: .background).async {
if let url = URL(string: sampleURL), let urlData = NSData(contentsOf: videoUrl) {
let galleryPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0];
let filePath="\(galleryPath)/" + name + ".MOV"
DispatchQueue.main.async {
urlData.write(toFile: filePath, atomically: true)
}
}
}
}
But I got this error message: "Can't end BackgroundTask: no background task exists with identifier 16 (0x10), or it may have already been ended. Break in UIApplicationEndBackgroundTaskError() to debug."
I added a symbolic breakpoint for UIApplicationEndBackgroundTaskError, but I don't understand what is wrong. What should I do to solve this problem?
Screenshot from breakpoint:
But I got this error message: "Can't end BackgroundTask: no background task exists with identifier 16 (0x10), or it may have already been ended. Break in UIApplicationEndBackgroundTaskError() to debug."
This is a new warning only in the Simulator in Xcode 11. It’s unimportant. Ignore it. It happens all the time, nothing to do with your code.

Document file path unreachable in swift

I'm currently working on a small swift application and I'm storing some video records in the documents folder of the app. I would like to retrieve these on a later moment. I already got an array of file locations like this:
file:///private/var/mobile/Containers/Data/Application/6C462C4E-05E2-436F-B2E6-F6D9AAAC9361/Documents/videorecords/196F9A75-28C4-4B65-A06B-6111AEF85F01.mov
Now I want to use such file location to create a thumbnail with the first frame and connect that to my imageview with the following piece of code:
func createVideoStills() {
for video in directoryContents {
print("\(video)")
do {
let asset = AVURLAsset(URL: NSURL(fileURLWithPath: "\(video)"), options: nil)
let imgGenerator = AVAssetImageGenerator(asset: asset)
imgGenerator.appliesPreferredTrackTransform = true
let cgImage = try imgGenerator.copyCGImageAtTime(CMTimeMake(0, 1), actualTime: nil)
let uiImage = UIImage(CGImage: cgImage)
videoCell.imageView = UIImageView(image: uiImage)
//let imageView = UIImageView(image: uiImage)
} catch let error as NSError {
print("Error generating thumbnail: \(error)")
}
}
}
The first print gives me a path like described above. But the AVURLAsset doesn't like this path because it spits out the following error:
Error generating thumbnail: Error Domain=NSURLErrorDomain Code=-1100
"The requested URL was not found on this server."
UserInfo={NSLocalizedDescription=The requested URL was not found on
this server., NSUnderlyingError=0x14ee29170 {Error
Domain=NSPOSIXErrorDomain Code=2 "No such file or directory"}}
Which is weird cause it is right there. Any solutions on how to fix/solve this?
Kind regards,
Wouter
The output of your print("\(video)") is not a file path but a string representation of file URL. You need to use init(string:) than init(fileURLWithPath:) of NSURL.
See what you get with:
let asset = AVURLAsset(URL: NSURL(string: video), options: nil)
(Unnecessary string interpolation would generate some unexpected result without errors -- like getting "Optional(...)", so you should avoid.)
// if You Are Using PHPickerViewController then do this for fetching the url.
// ------
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
picker.dismiss(animated: true, completion: nil)
guard let provider = results.first?.itemProvider else { return }
if provider.hasItemConformingToTypeIdentifier(UTType.movie.identifier) {
provider.loadItem(forTypeIdentifier: UTType.movie.identifier, options: [:]) { [self] (videoURL, error) in
print("resullt:", videoURL, error)
DispatchQueue.main.async {
if let url = videoURL as? URL {
let player = AVPlayer(url: url)
let playerVC = AVPlayerViewController()
playerVC.player = player
present(playerVC, animated: true, completion: nil)
}
}
}
}
}