I am trying to write an iOS document provider (iOS 9), and have used the available Apple documentation and code as a stating point. However, I am running into a strange issue where I cannot write to the location pointed to by the storage URL. I am testing an import operation.
Here is the value I am getting for documentStorageURL:
file:///private/var/mobile/Containers/Shared/AppGroup/4F0A350D-8CD7-4A25-83ED-2C6120CD30FA/File%20Provider%20Storage/
However when I try to write to that location, I get the following error:
Error Domain=NSCocoaErrorDomain Code=4 "The file “test.txt” doesn’t exist." UserInfo={NSFilePath=/private/var/mobile/Containers/Shared/AppGroup/4F0A350D-8CD7-4A25-83ED-2C6120CD30FA/File Provider Storage/test.txt, NSUnderlyingError=0x15f5ba010 {Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory"}}
One thing that is odd is the containerURL returned from containerURLForSecurityApplicationGroupIdentifier is actually different:
file:///private/var/mobile/Containers/Shared/AppGroup/A92110D1-D0B9-4DA7-8048-A4C63FF931D5/
I am actually able to write to this latter path and read it back to verify, but then when I call dismissGrantingAccessToURL I get an error that says the path I returned back is not the documentStorageURL.
Here is the relevant code which is being called after I press a button in the UI of the document provider:
NSURL *container = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:#"group.com.jdw.DocumentProvider"];
NSLog(#"container url = %#", container);
NSLog(#"openDocument: storage uRL = %#", self.documentStorageURL);
NSURL* documentURL;
if (self.documentStorageURL != nil)
documentURL = [self.documentStorageURL URLByAppendingPathComponent:#"test.txt"];
else
documentURL= [container URLByAppendingPathComponent:#"test.txt"];
NSString *fileName = [documentURL path];
NSString *contents = #"this is a dynamically created text file";
NSLog(#"write to file = %#", fileName);
NSError *err;
[contents writeToFile:fileName
atomically:NO
encoding:NSStringEncodingConversionAllowLossy
error:&err];
NSLog(#"write: error = %#", err);
I tried this again today and things magically worked, without any significant code changes that should have fixed the issue. I did reset the iPhone though.
I'm pretty sure this is a iOS or XCode bug. For reference, I'm using XCode 7.2 and iOS 9.2
Related
I want to copy a file from the iOS 11 Files app to my local app sandbox. For testing purposes it is assumed that the file is locally available in the Files app (downloaded from iCloud to the local storage). The file extension is registered with my app and when a file is pressed in the Files app then my app receives the file URL from the Files app:
NSFileCoordinator *fileCoordinator = [[NSFileCoordinator alloc] initWithFilePresenter:nil];
NSURL *nsUrl; // comes from Files app. For instance "file:///private/var/mobile/Library/Mobile%20Documents/com~apple~CloudDocs/test.rar"
NSURL *targetUrl; // file in my app's document directory
NSError *coordinatorError = nil;
[fileCoordinator coordinateReadingItemAtURL:nsUrl options:NSFileCoordinatorReadingWithoutChanges error:&coordinatorError byAccessor:^(NSURL *newURL)
{
NSFileManager *fileManager = [NSFileManager defaultManager];
//if ([fileManager fileExistsAtPath: [nsUrl path]])
{
NSLog(#"Copy from %# to %#", newURL, targetUrl);
NSError *copyError = nil;
[fileManager copyItemAtURL:newURL toURL:targetUrl error:©Error];
if (!copyError)
{
// OK
}
else
{
NSLog(#"Files app error: %#", copyError);
}
}
}];
But the operation fails with this output:
2017-11-22 09:30:28.685127+0100 test[434:40101] Copy from file:///private/var/mobile/Library/Mobile%20Documents/com~apple~CloudDocs/test.rar
to file:///var/mobile/Containers/Data/Application/01BB33E6-2790-0FD0-8270-000/Documents/test.rar
2017-11-22 09:30:28.687174+0100 test[434:40101] Files app error: Error Domain=NSCocoaErrorDomain Code=257 "The file “test.rar” couldn’t be
opened because you don’t have permission to view it."
UserInfo={NSFilePath=/private/var/mobile/Library/Mobile Documents/com~apple~CloudDocs/test.rar,
NSUnderlyingError=0x1c084abf0 {Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted"}}
Is there something special required to get read access to the external file?
Regards,
Here is how you can access the files and stop when are done with it.
//To gain access
[nsUrl startAccessingSecurityScopedResource]
and
//To stop access
[nsUrl stopAccessingSecurityScopedResource]
i have the same issue to Copy file from iOS 11 Files app to sandbox . finally i solved my issue this link
check here
and the sample code .
[fileURL startAccessingSecurityScopedResource];//fileURL ---> Which FileURL you want to copy
NSFileCoordinator *fileCoordinator = [[NSFileCoordinator alloc] initWithFilePresenter:nil];
NSFileAccessIntent *readingIntent = [NSFileAccessIntent readingIntentWithURL:fileURL options:NSFileCoordinatorReadingWithoutChanges];
[fileCoordinator coordinateAccessWithIntents:#[readingIntent] queue:[NSOperationQueue mainQueue] byAccessor:^(NSError *error) {
NSData *filePathData;
if (!error)
{
// Always get URL from access intent. It might have changed.
NSURL *safeURL = readingIntent.URL;
// here your code to do what you want with this
}
[fileURL stopAccessingSecurityScopedResource];
}];
When running the following lines of code, I see this in the log: Error Domain=NSCocoaErrorDomain Code=256 "The file “some_page” couldn’t be opened
Here is the code:
NSError *downloadError = nil;
NSData *theJSONData = [NSData dataWithContentsOfURL:[NSURL URLWithString:s] options:NSDataReadingUncached error:&downloadError];
NSLog(#"error : %#", downloadError);
This happens only 20-30% of the time
What could be the reason?
I found an answer where they say iOS doesn't support http, so I added NS app transport security. But anyway, it happens only sometimes.
Update:
I just found out that this is the cause:
if(! [[fullURL substringFromIndex:fullURL.length-1] isEqualToString:#"/"])
s = [fullURL stringByAppendingString:#"/"];
why does it not work 20% of the time with the same url when I add the "/"?
I'm trying to use the Dropbox iOS sdk to upload a small video file. I've had success with images, but the video upload seems to be failing. My code to upload the video is as follows
NSString *pathToMovie = [[self applicationDocumentsDirectory].path
stringByAppendingPathComponent:#"Movie.m4v"];
NSURL *movieURL = [NSURL fileURLWithPath:pathToMovie];
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:pathToMovie];
if (fileExists) {
NSLog(#"File Exsits");
//open the already downloaded file
}
if (!fileExists) {
NSLog(#"File does not Exsit");
//download and then open
}
[self.restClient
uploadFile:[NSString stringWithFormat:#"%#.m4v", [self randomStringWithLength:6]]
toPath:#"/YourFolder" fromPath:pathToMovie];
I'm checking first just to make sure the file exists and then uploading. I'm getting this error
[WARNING] DropboxSDK: error making request to /1/files_put/sandbox/YourFolder/5iG8y0.m4v -
(-1005) Error Domain=NSURLErrorDomain Code=-1005 "The operation couldn’t be completed. (NSURLErrorDomain error -1005.)"
UserInfo=0x17007c800
{sourcePath=/var/mobile/Containers/Data/Application/CC02A2FC-7B5D-435C-9F81-8A678FF61146/Documents/Movie.m4v, destinationPath=/YourFolder/5iG8y0.m4v}
I'm not really sure where the error is coming from ... again I was able to upload an image, and I tested with a very small video to make sure it was not a file size issue. I'm stumped.
Just as a note, this is not happening on the simulator, it's happening on the device, so resetting the simulator will not solve the problem
one solution is again call the Same Function in which you fot such error. in Device
if (error.code == -1005)
{
//Again Call the Same Function
[Function APICallPostWithName:actionName withRequestParameters:dict block:block];
}
Restarting the simulator fixed the issue for me.
iOS Simulator -> Reset Content and Settings -> Press Reset (on the warning which will come)
-(void)restClient:(DBRestClient*)client uploadFileFailedWithError:(NSError*)error {
NSLog(#"File upload failed with error - %#", error.userInfo);
NSString *myfile=[error.userInfo valueForKey:#"sourcePath"];
[self.restClient uploadFile:#"youfilename" toPath:#"/yourfilepath" withParentRev:nil fromPath:myfile];
}
I'd like to know if the device is locked when I'm loading my Notification/Today widget, so I can show the widget appropriately. (it's financial, and we don't want to show balances on a locked phone)
On devices with TouchID, I can just try to access the Keychain, and if I get
errSecInteractionNotAllowed
back, it's locked. All good. This doesn't work on devices without touchID (but with a PIN). I've found a few things, which recommend using
[[UIApplication sharedApplication] protectedDataAvailable]
However I don't have [UIApplication sharedApplication] in a widget.
Any ideas where and how to do this? I just need a yes/no: is the device locked.
Thanks
[UPDATE: here's the code I have]
Getting the filename:
+ (NSString *)lockedDeviceFilename {
NSURL *directoryUrl = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:USER_DEFAULTS_GROUP_NAME];
return [directoryUrl.path stringByAppendingPathComponent:#"security.dummy"];
}
Writing / creating the file (in the app, not the extension:
NSError *error = nil;
NSString *documentPath = [FOOStorageGatekeeper lockedDeviceFilename];
[[NSFileManager defaultManager] removeItemAtPath:documentPath error:&error];
BOOL created = [[NSFileManager defaultManager] createFileAtPath:documentPath
contents:[#"super secret file contents. we only care about the permissions" dataUsingEncoding:NSUTF8StringEncoding]
attributes:#{NSFileProtectionKey : NSFileProtectionComplete}];
Reading:
BOOL isReadable = [[NSFileManager defaultManager] fileExistsAtPath:[FOOStorageGatekeeper lockedDeviceFilename]];
NSLog(#"isReadable? %#", isReadable ? #"YES" : #"NO");
It's always able to read the file, even on a TouchID device with the screen locked. If I look at the attributes, it shows the NSFileProtectionKey is set to NSFileProtectionComplete... but I can STILL READ IT :(
Update: found it. Marking Ian's answer as correct
Create a file with NSFileProtectionComplete while your app is running and then attempt to access it from your extension. If you can't access it, the screen is locked.
[[NSFileManager defaultManager] createFileAtPath:someFilePath
contents:[#"Lock screen test." dataUsingEncoding:NSUTF8StringEncoding]
attributes:#{NSFileProtectionKey: NSFileProtectionComplete}];
EDIT: Final steps included to complete solution and consolidate answers. (Remaining work provided by Nic Wise.)
NSData *data = [NSData dataWithContentsOfURL:[FOOStorageGatekeeper lockedDeviceUrl] options: NSDataReadingMappedIfSafe error:&error];
if (error != nil && error.code == 257) {
NSLog(#"**** the keychain appears to be locked, using the file method");
return YES;
}
The other method, using errSecInteractionNotAllowed also works, but only for TouchID devices.
I found the answer (indirectly) here (rego with the iOS dev program most likely needed)
Finally, after 3-4 days of looking, found the answer. It was more in how I was reading the result back. Ian is right: I need to create the file using createFileAtPath, but then read it back using
NSData *data = [NSData dataWithContentsOfURL:[FOOStorageGatekeeper lockedDeviceUrl] options: NSDataReadingMappedIfSafe error:&error];
if (error != nil && error.code == 257) {
NSLog(#"**** the keychain appears to be locked, using the file method");
return YES;
}
The other method, using errSecInteractionNotAllowed also works, but only for TouchID devices.
I found the answer (indirectly) here (rego with the iOS dev program most likely needed)
I tried that and my file was always readable (in lock screen or not).
I found this document :
https://www.apple.com/business/docs/iOS_Security_Guide.pdf
It appeared that the files are locked 10 seconds after the device is locked.
Knowing that, you can create the files from the extensions, and it seems to work.
I am Making an Audio recorder(m4a extension files). I am Giving a particular URL for the output of the recorded File(in directory).
I am able to play it, save the path of the file in database and can retrieve it later. EVery thing is going Fine. BUT I am not able to delete the saved/unsaved files. Every time I record an audio , the file is taking a permanent space. Am not able to delete them.
I tried it over internet(stackoverflow ofcourse). I got Links like this: I have video URL and want to delete it from the iPhone using this URl
But they are showing COCOA ERROR 4 when ever i try to delete them using codes like this: [[NSFileManager defaultManager] removeItemAtPath:strPath error:&error];
Please suggest, and reply
You typically accomplish this for resources you've saved in your Apps documents directory like this:
unlink([pathForURL UTF8String]);
where pathForURL is an NSString that describes the path to the resource you're deleting.
This is the path earlier i was getting , at which i was unable to write file
/var/mobile/Applications/8584F54E-75D2-4833-8826-29C125E53DBC/Library/Documentation/291013193758w.png
This morning, I just run my code once again ,. now its showing path
/var/mobile/Applications/DDA14123-6A88-4756-B2E4-C4A3AA39AA5B/Documents/291013081335test.png
on this path am able to write my file
the Difference between two paths is that, first one is of Library/Documentation , where as second one is of Documents
dont know the difference, but it is working now
There may be case that file path which you provide is not correct. If its correct then try following with URL, it might solve your issue
NSString *str= [outputFieldURL absoluteString];
NSError *error;
NSURL *url = [NSURL URLWithString:str];
BOOL success = [[NSFileManager defaultManager] removeItemAtURL:url error:&error];
if (!success) {
NSLog(#"Error removing file at path: %#", error.localizedDescription);
}
else
{
NSLog(#"File removed at path: %#", error.localizedDescription);
}
}
Before deleting the file you have to check file there or not :
NSFileManager* manager = [[NSFileManager alloc] init];
if ([manager fileExistsAtPath:path]) {
[manager removeItemAtPath:path error:&error];
}