WCSession didReceive file not movable "No such file or directory" - ios

After transferring a file from iPhone to Apple Watch I get the Error
Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory"
What do I do wrong? These are the code snippets:
iPhone ViewController
func makeAction () {
let url = NSURL.fileURL(withPath: fileArray[0].object(at: 2) as! String)
var applicationDict = Dictionary<String, Array<AnyObject>>()
applicationDict["fileArray"] = fileArray
WCSession.default().transferFile(url, metadata: applicationDict)
}
Watch InterfaceController
func session(_ session: WCSession, didReceive file: WCSessionFile) {
DispatchQueue.main.async(execute: { () -> Void in
print("RECEIVED")
var applicationDict = Dictionary<String, Array<AnyObject>>()
applicationDict = file.metadata as! Dictionary<String, Array<AnyObject>>
self.fileArray = applicationDict["fileArray"]!
self.fileList = self.fileArray
let dirPaths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
let tempDocsDir = dirPaths[0] as String
let docsDir = tempDocsDir.appending("/")
let filemgr = FileManager.default
do {
let fileName = self.fileArray[0].object(at: 1) as! String
try filemgr.moveItem(atPath: file.fileURL.path, toPath: docsDir + fileName)
} catch let error as NSError {
print("Error moving file: \(error.description)")
}
self.loadTableData()
})
}
Full Error Message
Error moving file: Error Domain=NSCocoaErrorDomain Code=4
"“5d1392cd-acac-4b99-abf5-50062e12dc14_95de54df-69b1-43df-bb90-cfac6fed3677.mp3” couldn’t be moved to “Documents” because either the former doesn't
exist, or the folder containing the latter doesn't exist."
UserInfo={NSSourceFilePathErrorKey=/Users/pknapp/Library/Developer/CoreSimulator/Devices/950FC0DA-C245-4326-8777-80CE765AF655/data/Containers/Data/PluginKitPlugin/73C0D94F-483C-4426-B052-001E8837D83A/Documents/Inbox/com.apple.watchconnectivity/FCE7E6CB-2452-4E0A-9AFF-F5B3A51A0DE8/Files/0B96CCB0-A2E1-418B-9859-97C22238A5F5/5d1392cd-acac-4b99-abf5-50062e12dc14_95de54df-69b1-43df-bb90-cfac6fed3677.mp3, NSUserStringVariant=(
Move ), NSFilePath=/Users/pknapp/Library/Developer/CoreSimulator/Devices/950FC0DA-C245-4326-8777-80CE765AF655/data/Containers/Data/PluginKitPlugin/73C0D94F-483C-4426-B052-001E8837D83A/Documents/Inbox/com.apple.watchconnectivity/FCE7E6CB-2452-4E0A-9AFF-F5B3A51A0DE8/Files/0B96CCB0-A2E1-418B-9859-97C22238A5F5/5d1392cd-acac-4b99-abf5-50062e12dc14_95de54df-69b1-43df-bb90-cfac6fed3677.mp3, NSDestinationFilePath=/Users/pknapp/Library/Developer/CoreSimulator/Devices/950FC0DA-C245-4326-8777-80CE765AF655/data/Containers/Data/PluginKitPlugin/73C0D94F-483C-4426-B052-001E8837D83A/Documents/5d1392cd-acac-4b99-abf5-50062e12dc14_95de54df-69b1-43df-bb90-cfac6fed3677.mp3, NSUnderlyingError=0x7b776110 {Error Domain=NSPOSIXErrorDomain Code=2
"No such file or directory"}}

The documentation for didReceiveFile notes:
File: The object containing the URL of the file and any additional information. If you want to keep the file referenced by this parameter, you must move it synchronously to a new location during your implementation of this method. If you do not move the file, the system deletes it after this method returns.
So make sure to not async in this method before moving the file to a location your app has access to.

Alright, got it. putting this in an async dispatch was wrong. Without ist -> work perfectly. Please go ahead, nothing to see here :)

Related

Agora cannot record call with iOS Swift

I am following the doc here: https://docs.agora.io/en/Voice/rtc_recording_apple?platform=iOS and implementing a basic recording. This is my code:
func startRecording(){
let filename = getDocumentsDirectory().appendingPathComponent("\(APP_NAME)\(now()).WAV")
let str = String(describing: filename)
self.recordingPath = str
agoraKit?.startAudioRecording(str, quality: .high)
}
func stopRecording(){
agoraKit?.stopAudioRecording()
// get audio file
guard let audioUrl = URL(string: self.recordingPath) as? URL else { return }
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0 ) { [weak self] in
// getdata
do {
let myData = try Data(contentsOf: audioUrl)
print(myData.count, myData)
} catch {
print(error)
}
}
}
private func getDocumentsDirectory() -> URL {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
return paths[0]
}
But I am getting error: The file “Whisper1608949569.WAV” couldn’t be opened because there is no such file
Full message:
file:///var/mobile/Containers/Data/Application/1F682ABD-153C-4DFD-BFF4-
02C1CE6F9A4C/Documents/Whisper1608949569.WAV
Error Domain=NSCocoaErrorDomain Code=260 "The file “Whisper1608949569.WAV” couldn’t be opened because there is no such file." UserInfo={NSFilePath=/var/mobile/Containers/Data/Application/1F682ABD-153C-4DFD-BFF4-02C1CE6F9A4C/Documents/Whisper1608949569.WAV, NSUnderlyingError=0x281e33f60 {Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory"}}
Am I not accessing the file correctly?
This is how I have initialized the agora client:
self.agoraKit = AgoraRtcEngineKit.sharedEngine(withAppId: AppID, delegate: self)
agoraKit?.delegate = self
agoraKit?.enableWebSdkInteroperability(true)
// sample loudest speaker every second
agoraKit?.enableAudioVolumeIndication(1000, smooth: 3, report_vad: true)
agoraKit?.enableAudio()
// config for livecast to start
agoraKit?.setChannelProfile(.liveBroadcasting)
// set framrate and HD/SD
agoraKit?.setVideoEncoderConfiguration( CONFIG_PRODUCTION )
//agoraKit?.setDefaultAudioRouteToSpeakerphone(true)
I just checked out the documentation referenced from the doc you're using and it says the method startAudioRecording(filepath, quality: quality) is now deprecated, and you should instead use this method with the additional sampleRate parameter:
https://docs.agora.io/en/Voice/API%20Reference/oc/Classes/AgoraRtcEngineKit.html#//api/name/startAudioRecording:sampleRate:quality:
Also check that the returned value of startAudioRecording and stopAudioRecording returns 0, meaning success.
If your channel name contains special characters (colons, slashes) recording will silently fail and no file will be produced.
It seems Agora uses the channel name when creating the temporary file.

Swift - Open file imported to app

Hi I have an app which uses its own document format (.hvgg). The UTI is declared in the Info.plist (screenshot). Did I do anything wrong there? Because when I use the "Share" menu, it shows "Copy to HvGG" instead of "Import to HvGG" which it says with all the other apps.
Anyways, my actual problem is that I can't find the file that is imported. I tried to find it using the document directory and adding "Inbox" but that didn't work. Is there a new path where the files are saved?
This is my code:
var opened: String?
var path: String?
func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
if String(describing: url)[0..<4] == "file" {
opened = "stundenplan"
let filemanager = FileManager.default
let paths: NSArray = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true) as NSArray
let documentsDirectory: String = paths.object(at: 0) as! String
path = documentsDirectory.appending("/Inbox")
let dirFiles = try! filemanager.contentsOfDirectory(atPath: path!) <-- throws error
print (dirFiles)
}
return true
}
The error it returns:
fatal error: 'try!' expression unexpectedly raised an error: Error Domain=NSCocoaErrorDomain Code=260 "The folder “Inbox” doesn’t exist." UserInfo={NSFilePath=/var/mobile/Containers/Data/Application/9C0586AF-C0B8-440A-9151-13C6A061B3FB/Documents/Inbox, NSUserStringVariant=(
Folder), NSUnderlyingError=0x174050e90 {Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory"}}: file /Library/Caches/com.apple.xbs/Sources/swiftlang/swiftlang-802.0.31.3/src/swift/stdlib/public/core/ErrorType.swift, line 182

Cannot create file or directory in documents folder in iOS sandbox

I'm making a game on iPad (v10.2.1) with Xcode(version 8.2.1) and while I'm trying to save some data in documents folder in the sandbox, I found that all ways I tried failed: createDirectory and createFile(using file manager), and writeToUrl(using NSData). I ran the program on 2 iPads and 1 iPhone and no success.
I was able to read from a plist I created, and convert it to a dictionary, using the function convertDataFrom().
I'm new to data persistence or file manipulation and my game stuck here. would appreciate any help!
func loadData()->NSDictionary{
let fm = FileManager()
let sourceUrl = Bundle.main.url(forResource: "Data", withExtension: "plist")!
var appSupportDir = fm.urls(for: .documentDirectory, in: .userDomainMask).first! as? NSURL
appSupportDir = appSupportDir!.appendingPathComponent("UserData", isDirectory: true) as NSURL?
let urlForSave = (appSupportDir!.appendingPathComponent("Data.plist"))!
//load data, or if file doesn't exist yet, create one
var isDirectory: ObjCBool = false
if fm.fileExists(atPath: urlForSave.absoluteString, isDirectory: &isDirectory) {
let data = convertDataFrom(url: urlForSave)
print("data file exists")
print(isDirectory)
return data as NSDictionary
} else {
do { try fm.createDirectory(atPath: appSupportDir!.absoluteString!, withIntermediateDirectories: true, attributes: nil) }catch let Error {
print("create directory failed")
print(Error)
}
let originalData = NSData.init(contentsOf: sourceUrl)
print("\(urlForSave)")
do { try originalData?.write(toFile: urlForSave.absoluteString, options: .atomic) } catch let Error {
print(Error)
}
if (!fm.createFile(atPath: urlForSave.absoluteString, contents: originalData as Data?, attributes: nil)) {
fatalError("file creation failed")
}
let data = convertDataFrom(url: urlForSave)
print("\(data)")
print(isDirectory)
return data as NSDictionary
}
}
func convertDataFrom(url: URL)->Dictionary<String, Any> {
let dictionary = NSDictionary.init(contentsOf: url) as! Dictionary<String, Any>
return dictionary
}
Error messages for "createDirectory": Error Domain=NSCocoaErrorDomain
Code=513 "You don’t have permission to save the file “UserData” in the
folder “Documents”."
UserInfo={NSFilePath=file:///var/mobile/Containers/Data/Application/F7F41E0D-D3F6-489B-A59E-B7AC401EC402/Documents/UserData/,
NSUnderlyingError=0x174053f50 {Error Domain=NSPOSIXErrorDomain Code=1
"Operation not permitted"}}
file:///var/mobile/Containers/Data/Application/F7F41E0D-D3F6-489B-A59E-B7AC401EC402/Documents/UserData/Data.plist
and for "createFile" (fatalError if createFile fails) Error
Domain=NSCocoaErrorDomain Code=4 "The file “Data.plist” doesn’t
exist."
UserInfo={NSFilePath=file:///var/mobile/Containers/Data/Application/F7F41E0D-D3F6-489B-A59E-B7AC401EC402/Documents/UserData/Data.plist,
NSUnderlyingError=0x174055bd0 {Error Domain=NSPOSIXErrorDomain Code=2
"No such file or directory"}} fatal error: file creation failed: file
/Users/chanwu/Desktop/Math_DownStairs/Math_DownStairs/
Your code checks to see if urlForSave (the final file) exists, and if it doesn't, you then try to create the UserData directory.
If the final file doesn't exist, but the UserData directory does, I would expect the exact outcome you describe.
You should probably change your test to see if the UserData directory exists instead of testing for the final file. That way if the directory doesn't exist you'll create it, and then call write(toFile:), which will create the file if it doesn't exist.

Download fails when on first use or app goes in background

Alamofire 3.5.0, Swift2.2
I'm downloading ZIP files with the Alamofire download method, I've noticed that when I'm starting download process and apps goes background than the download fails with following error:
----------------------
error Optional(Error Domain=NSCocoaErrorDomain Code=4
"“CFNetworkDownload_pZ56nc.tmp” couldn’t be moved to “courses”
because either the former doesn't exist, or the folder containing
the latter doesn't exist." UserInfo=
{NSSourceFilePathErrorKey=
/private/var/mobile/Containers/Data/Application/[UUID]/tmp/CFNetworkDownload_pZ56nc.tmp,
NSUserStringVariant=(
Move
),
NSDestinationFilePath=
/var/mobile/Containers/Data/Application/[UUID]/Library/courses/course_302.zip,
NSFilePath=
/private/var/mobile/Containers/Data/Application/[UUID]/tmp/CFNetworkDownload_pZ56nc.tmp,
NSUnderlyingError=0x13f52f990 {Error Domain=NSPOSIXErrorDomain
Code=2 "No such file or directory"}})
----------------------
this is the code to download a file:
//...
var userLibraryPath:String = {
return NSSearchPathForDirectoriesInDomains(.LibraryDirectory, .UserDomainMask, true)[0]
}()
//...
let _coursePath:NSURL = NSURL(string: "file://\(userLibraryPath)/)")!
//...
let zipURL = _coursePath.URLByAppendingPathComponent("course_\(courseId).zip")
//if file exists destroy it
if let zipPath = zipURL?.path where NSFileManager.defaultManager().fileExistsAtPath(zipPath) {
do {
try NSFileManager.defaultManager().removeItemAtPath(zipPath)
} catch let error as NSError {
print(error)
}
}
//
let downloadRequest = Alamofire.download(Router.download(courseId), destination: { (url:NSURL, urlResponse:NSHTTPURLResponse) -> NSURL in
//
return zipURL!
//
}).progress({ (bytesWritten, totalBytesWritten, totalBytesExpectedToWrite) in
//
let progress = Double(totalBytesWritten) / Double(totalBytesExpectedToWrite)
dispatch_async(GlobalMainQueue, {
self.notifyDownloadProgress(courseId, progress: progress)
})
}).response(completionHandler: { (request:NSURLRequest?, response:NSHTTPURLResponse?, data:NSData?, error:NSError?) in
self.removeFromQueue(courseId)
print("response")
print("----------------------")
print("error \(error)")
print("----------------------")
//here I would try to extract it
})
UPDATE I've just tested on iPhone 5 fresh install of the app and it doesn't have to go to background (e.g. via home button) to fail, it fails on the very first load (and any subsequent) untill after the app is killed and reopened.
Why is the "/private" bit added to the path? What am I doing wrong here?
And indeed it was a "No such file or directory" error.
When I've added:
//
let downloadRequest = Alamofire.download(Router.download(courseId), destination: { (url:NSURL, urlResponse:NSHTTPURLResponse) -> NSURL in
let course = zipURL!.URLByDeletingLastPathComponent!.path!
let fm = NSFileManager.defaultManager()
var isDir:ObjCBool = false
if(fm.fileExistsAtPath(path, isDirectory: &isDir) == false){
//doesnt exist
do {
try fm.createDirectoryAtPath(path, withIntermediateDirectories: true, attributes: nil)
} catch let error as NSError {
//
print(error)
}
}
return zipURL!
//
})

Get Document Directory Inbox file and move

I have an incoming PDF attachment coming into my app. It's coming in as NSURL assigned in the AppDelegate:
func application(app: UIApplication, openURL url: NSURL, options: [String : AnyObject]) -> Bool {
The file prints to the print log as:
Incoming File:
file:///private/var/mobile/Containers/Data/Application/65E4F19F-98DD-4A4E-8A49-E1C564D135D8/Documents/Inbox/Burrito.pdf
How can I get the file out of the DocumentDirectory Inbox folder where it is put by default for an incoming file? I tried to create a new folder called "Recipes" and then move it to this folder, but it won't I get the error:
Unable to create directory Error Domain=NSCocoaErrorDomain Code=516
"“Burrito-2.pdf” couldn’t be moved to “Documents” because an item with
the same name already exists."
UserInfo={NSSourceFilePathErrorKey=/private/var/mobile/Containers/Data/Application/D5C9B472-B880-4D68-BA0D-31BA545E2150/Documents/Inbox/Burrito.pdf,
NSUserStringVariant=(
Move ), NSDestinationFilePath=/var/mobile/Containers/Data/Application/D5C9B472-B880-4D68-BA0D-31BA545E2150/Documents/Recipes,
NSFilePath=/private/var/mobile/Containers/Data/Application/D5C9B472-B880-4D68-BA0D-31BA545E2150/Documents/Inbox/Burrito.pdf,
NSUnderlyingError=0x13912e0e0 {Error Domain=NSPOSIXErrorDomain Code=17
"File exists"}}
My code to move the file is:
// Incoming file
print("Incoming File: \(incomingFileTransfer)")
// File Manager
let filemgr = NSFileManager.defaultManager()
// Document Directory
var dirPaths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
// Documents Location
let docsDir = dirPaths[0] //as! String
print("Documents Folder: \(docsDir)")
print("------------------------")
// Create a new folder in the directory named "Recipes"
print("Creating new folder...")
let documentsPath = NSURL(fileURLWithPath: NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0])
let newPath = documentsPath.URLByAppendingPathComponent("Recipes")
do {
try NSFileManager.defaultManager().createDirectoryAtPath(newPath.path!, withIntermediateDirectories: true, attributes: nil)
} catch let error as NSError {
NSLog("Unable to create directory \(error.debugDescription)")
}
print("New Path: \(newPath)")
print("------------------------")
// Moving item in folder
print("Moving PDf file to new folder...")
let startingPath = incomingFileTransfer
let endingPath = newPath
do {
try filemgr.moveItemAtURL(startingPath, toURL: endingPath)
} catch let error as NSError {
NSLog("Unable to create directory \(error.debugDescription)")
}
I'm new to Swift and have been research online and documentation on file management, but can't figure this out. I looked here but it is different and also in Objective-C; converting to Swift is hard for me. I'm using Xcode7 and Swift2, Thank you.
You get the errors when you run the application the second time and the directory is already created and the file has already been moved.
Apple highly recommends to use the URL related API of NSFileManager
First get the documents directory
// File Manager
let filemgr = NSFileManager.defaultManager()
// Document Directory
let docsDirURL = try! filemgr.URLForDirectory(.DocumentDirectory, inDomain: .UserDomainMask, appropriateForURL: nil, create: true)
The try! statement is safe because the documents directory always exists.
Then check if the Recipes directory exists. If not, create it
let recipesURL = docsDirURL.URLByAppendingPathComponent("Recipes")
if !filemgr.fileExistsAtPath(recipesURL.path!) {
do {
try filemgr.createDirectoryAtURL(recipesURL, withIntermediateDirectories: false, attributes: nil)
print("Directory created at: \(recipesURL)")
} catch let error as NSError {
NSLog("Unable to create directory \(error.debugDescription)")
return
}
}
You can also check if the destination file exists
let incomingFileName = incomingFileTransfer.lastPathComponent!
let startingURL = incomingFileTransfer
let endingURL = recipesURL.URLByAppendingPathComponent(incomingFileName)
if !filemgr.fileExistsAtPath(endingURL.path!) {
do {
try filemgr.moveItemAtURL(startingURL, toURL: endingURL)
} catch let error as NSError {
NSLog("Unable to move file \(error.debugDescription)")
}
}

Resources