Unable to import pages and numbers documents with UIDocumentPicker - objective-c

I'm developing an app that provides the ability to store cloud documents.
This app will have the option to import data from other apps using the new UIDocumentPickerViewController.
Everything works fine and I'm able to show the picker view controller.
This is the code that I'm using to import the file:
- (void)documentPicker:(UIDocumentPickerViewController *)controller didPickDocumentAtURL:(NSURL *)url {
if (controller.documentPickerMode == UIDocumentPickerModeImport) {
dispatch_async(dispatch_get_main_queue(), ^{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0]; // Get documents folder
NSString* path=[NSString stringWithFormat:#"%#/MyHandyTap/%#/%#",documentsDirectory,self.cartella,[url lastPathComponent]];
BOOL startAccessingWorked = [url startAccessingSecurityScopedResource];
NSURL *ubiquityURL = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil];
__block NSData *data;
NSFileCoordinator *fileCoordinator = [[NSFileCoordinator alloc] init];
NSError *error;
[fileCoordinator coordinateReadingItemAtURL:url options:0 error:&error byAccessor:^(NSURL *newURL) {
data = [NSData dataWithContentsOfURL:newURL];
[data writeToFile:path atomically:YES];
}];
[url stopAccessingSecurityScopedResource];
}
}
With this code I'm able to import a lot of different file formats (.pdf, .txt, .rtf, .doc etc) however if I try to import files .pages or .numbers files from iCloud the call to [NSData dataWithContentsOfURL:newURL] returns null.
Is it possibile to let users import these kinds of files?
I've red the documentation listed here https://developer.apple.com/library/prerelease/ios/documentation/General/Conceptual/ExtensibilityPG/FileProvider.html#//apple_ref/doc/uid/TP40014214-CH18-SW2
and I've downloaded the example listed here : https://developer.apple.com/devcenter/download.action?path=/wwdc_2014/wwdc_2014_sample_code/newboxanintroductiontoiclouddocumentenhancementsinios8.0.zip
however I'm not able to figure out how to solve this issue.
Thank you in advance for your help
Andrea

Even I did not test it, but likely you get the problems, because documents of type .pages or .numbers are no single files, but bundles. So you cannot read them with -dataWithContentsOfURL:.
Did you check copying with -copyItemAtURL:toURL:error: (NSFileManager)?

Related

How to save mixed file with AVAudioUnit without playing?

At now I save file by recording it from AVAudioUnitEQ.
[mainEQ installTapOnBus:0 bufferSize:0 format:[mainEQ outputFormatForBus:0] block:^(AVAudioPCMBuffer *buf, AVAudioTime *when){
if(!recordIsGoing){
[mainEQ removeTapOnBus:0];
}
else{
[writeAudioFile writeFromBuffer:buf error:nil];
// NSLog(#"%lld", writeAudioFile.length);
}
}];
But this method requires a prior file playback . Is there a way to save the mixed file without playing ?
UPD: I can get AUAudioUnit.outputBusses[0] to mainEQ.
The challenge now is to take out the data and hope that they will be such what I need.
RESOLVED: Issue been resolved by this answer Can I use AVAudioEngine to read from a file, process with an audio unit and write to a file, faster than real-time?
I think you can do this by first converting your data into NSData and storing it. When you retrieve it back, you can convert it back.
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:buf];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *dataPath = [documentsDirectory stringByAppendingPathComponent:#"yourfilename.dat"];
// Save it into file system
[data writeToFile:dataPath atomically:YES];

Objective c - picker to get video path

In my app, I allow the user to record videos and I save them in this path:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *path = [paths[0] stringByAppendingPathComponent:DestFileName];
I want to implement a video picker in my app, but the objective is to get the path of the video. I started with the basic method like this:
UIImagePickerController *videoPicker = [[UIImagePickerController alloc] init];
videoPicker.delegate = self;
videoPicker.modalPresentationStyle = UIModalPresentationCurrentContext;
videoPicker.mediaTypes =[UIImagePickerController availableMediaTypesForSourceType:UIImagePickerControllerSourceTypePhotoLibrary];‌​
videoPicker.mediaTypes = #[(NSString*)kUTTypeMovie, (NSString*)kUTTypeAVIMovie, (NSString*)kUTTypeVideo, (NSString*)kUTTypeMPEG4];
videoPicker.videoQuality = UIImagePickerControllerQualityTypeHigh;
[self presentViewController:videoPicker animated:YES completion:nil];
The first problem is that I can not access to my recorded videos, why?
Then, this picker allows the user to play video, and when I choose one video I think that a compressed video is created and sent to our delegate method (the URL goes to a tmp repository).
I don't want to allow the user to play video and I just want the video path, is it possible with this method?
I can also get the list of files in
NSSearchPathForDirectoriesInDomains
with this:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *rootPath = path[0];
[[NSFileManager defaultManager] createDirectoryAtPath:rooPath withIntermediateDirectories:YES attributes:nil error:nil];
NSArray* mPaths = [[NSFileManager defaultManager] contentOfDirectoryAtPath:rootPath error:nil];
With this method I can found my recorded videos, but then I have to implement my own custom picker, but it can be difficult and long to implement (need to get the thumbnail for example, possible?).
To summarize:
With the UIImagePickerController, is it possible to prevent the play, to just get the path and to show our recorded videos?
With the NSFileManager, is it possible to easily create a custom video picker with thumbnail, duration etc.)
Thanks for your help
UIImagePickerController is an instance of the iOS Photos App by which you can access all of the Photos/Videos in the Device Gallery and not exclusively those belonging to your App. There is no way to have the UIImagePickerController show only the videos recorded by your App. It is also not possible to have the UIImagePickerController skip the Play/Choose step while picking a File.
Like you mentioned you can definitely write the Video file into the Apps documents directory by means of NSFileManager and hold a reference to the path which you can use for later use. I think you would probably end up creating a Model Class say "Video" with the following attributes;
a) savedPath
b) duration
c) thumbnail etc
You can then use something like a NSKeyedArchiver to encode these objects and store into a File so that you can retrieve this information later.
I finally found the solution using a custom picker, :
To get the list of local videos:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString* rootPath = paths[0];
[[NSFileManager defaultManager] createDirectoryAtPath:rootPath withIntermediateDirectories:YES attributes:nil error:nil];
NSArray* mPaths = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:rootPath error:nil];
To get the duration and the thumbnail:
NSURL *videoURl = [NSURL fileURLWithPath:mPath];
AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:videoURl options:nil];
AVAssetImageGenerator *generate = [[AVAssetImageGenerator alloc] initWithAsset:asset];
generate.appliesPreferredTrackTransform = YES;
NSError *err = NULL;
CMTime time = CMTimeMake(1, 60);
CGImageRef imgRef = [generate copyCGImageAtTime:time actualTime:NULL error:&err];
UIImage *img = [[UIImage alloc] initWithCGImage:imgRef];
[m_videoFrames addObject:img];
CMTime duration = [asset duration];
int seconds = ceil(duration.value/duration.timescale);
Thanks!

Objective C can't read text file when running on iPhone

I've made an app that is relying on reading and writing a plist-file. This works well when I'm running the app in the iPhone simulator, but doesn't work at all when I'm testing it on my iPhone. I've also made a pre made text file in .txt format with demo data. The app works when I'm running this file.
All the reading and writing is done in a class that looks like this:
-(void)saveArray:(NSMutableArray *)inputArray
{
albumArray = inputArray;
NSArray *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentFolder = [path objectAtIndex:0];
NSString *filePath = [documentFolder stringByAppendingFormat:#"albums.plist"];
[albumArray writeToFile:filePath atomically:YES];
}
Update: Changed the string from "stringByAppendingFormat" to "stringByAppendingPathComponent" and it seems to work now. Thanks a lot! You guys made my day made.
Are you sure, that the folders already exist?
Here is a function i'm using to get the path to my file:
- (NSString*) pathToSavedAlbums
{
NSURL *applicationSupportURL = [self applicationDataDirectory];
if (! [[NSFileManager defaultManager] fileExistsAtPath:[applicationSupportURL path]])
{
NSError *error = nil;
[[NSFileManager defaultManager] createDirectoryAtPath:[applicationSupportURL path]
withIntermediateDirectories:YES
attributes:nil
error:&error];
if (error)
{
NSLog(#"error creating app support dir: %#", error);
}
}
NSString *path = [[applicationSupportURL path] stringByAppendingPathComponent:#"albums.plist"];
return path;
}
Check the spelling of the plist name as well as the case, device is case sensitive for docs but simulator isn't. Also try deleting the app from the device and reinstalling it ?
writeToFile:atomically: returns a bool, so check that to see if it fails to even write to the path. Check the file path string and ensure this is where you want it to go.

move/copy a file to iCloud

I am a beginner using Objective-C. I used the following code to move a file to iCloud but it gives an error that The operation could not be completed. The file exists.
//store the file locally in document folder
NSArray *docPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *filePath = [docPaths objectAtIndex:0];
filePath = [filePath stringByAppendingString:#"/"];
filePath = [filePath stringByAppendingString:fileName];
NSString *writeError = nil;
NSData * fileData = [NSPropertyListSerialization dataFromPropertyList:dataDic format:NSPropertyListXMLFormat_v1_0 errorDescription:&writeError];
if ([fileData writeToFile:filePath atomically:YES]) {
NSLog(#"Server file is stored locally");
}else {
NSLog(#"%#", writeError);
}
// store the file in iCloud folder
NSURL *ubiquitousURL = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil];
NSString *tmpubiquitousURL = ubiquitousURL.absoluteString;
tmpubiquitousURL = [tmpubiquitousURL stringByAppendingString:fileName];
NSURL *ubi2 = [[NSURL alloc] initWithString:tmpubiquitousURL];
[[NSFileManager defaultManager] setUbiquitous:YES itemAtURL:filePathURL destinationURL:ubi2 error:&error];
I used the following to remove the file from iCloud but it gives an error that Cannot disable syncing on an un-synced file.
[[NSFileManager defaultManager] setUbiquitous:NO itemAtURL:filePathURL destinationURL:ubi2 error:&error];
I checked the availability of iCloud in my app delegate and it's available. The file is an XML file (.plist) and I have a local copy stored in NSDocumentDirectory.
Overall, I want to sync that file in iCloud so it will be accessible on all devices using my app. I have been struggling with this for 2 days, so if you could help me to resolve the problem I would appreciate it.
Note: I would rather not to use UIDocument, however, if that is the only option please let me know.
I also have the same problem while using the code
[[NSFileManager defaultManager] setUbiquitous:NO itemAtURL:filePathURL destinationURL:ubi2 error:&error];
you have to change the code like below for this to work correctly
[[[NSFileManager alloc]init]setUbiquitous:YES itemAtURL:filePathURL destinationURL:ubi2 error:nil];
this code is for moving a file to icloud, also you should change the name of the file you are moving. It should not be same.

MPMoviePlayerViewController not working

I have been roaming the internet for a solution I really don't know what am I doing wrong. I have been with this problem a few days now. I save the video at the following path that should be accessible to the application (Right?)
//NSDocumentDirectory doesn't work either.
NSArray *newPath = NSSearchPathForDirectoriesInDomains(NSMoviesDirectory,
NSUserDomainMask, YES);
NSString *moviesDirectory = [NSString stringWithFormat:#"%#/WebSurg",
[newPath objectAtIndex:0]];
// Check if the directory already exists
if (![[NSFileManager defaultManager] fileExistsAtPath:moviesDirectory]) {
// Directory does not exist so create it
[[NSFileManager defaultManager] createDirectoryAtPath:moviesDirectory
withIntermediateDirectories:YES attributes:nil error:nil];
}
I show the contents of this directory in a tableView in the application. When a row is tapped it should play the video. But it doesn't. It shows me the MPMoviePlayerViewController modal view and then hides it after probably what is 1 second. This is the code I use to play it:
I tried two ways of getting the path to no avail.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSArray *moviesPath = NSSearchPathForDirectoriesInDomains(NSMoviesDirectory,
NSUserDomainMask, YES);
NSString *moviesDirectory = [NSString stringWithFormat:#"%#/WebSurg",
[moviesPath objectAtIndex:0]];
NSString *movie = [self.tableData objectAtIndex:indexPath.row];
NSString *moviePath = [NSString stringWithFormat:#"%#/%#",
moviesDirectory, movie];
NSURL *movieURL = [NSURL fileURLWithPath:moviePath];
NSLog(#"MOVIEPATH: %#", moviePath);
NSString *alternatePath = [NSString stringWithFormat:#"%#/%#",
[[NSBundle mainBundle] resourcePath], movie];
NSURL *alternateMoviePath = [NSURL fileURLWithPath:moviePath];
movieViewController = [[MPMoviePlayerViewController alloc] initWithContentURL:alternateMoviePath];
movieViewController.moviePlayer.movieSourceType= MPMovieSourceTypeFile;
NSLog(#"Movie Load State: %d", [[movieViewController moviePlayer] loadState]);
NSLog(#"Alternate movie Path: %#", alternatePath);
[self presentMoviePlayerViewControllerAnimated:movieViewController];
[movieViewController.moviePlayer play];
[self checkAndPlay];
}
- (void) checkAndPlay {
if ([[self.movieViewController moviePlayer] loadState] == MPMovieLoadStateUnknown) {
[NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:
#selector(checkAndPlay) userInfo:nil repeats:NO];
} else {
[self.movieViewController setModalTransitionStyle:
UIModalTransitionStyleCrossDissolve];
[self presentModalViewController:movieViewController animated:YES];
}
}
And these are the results of the console:
2012-10-08 10:14:52.392 WebsurgTemplates[3722:17903] MOVIEPATH: /Users/THISISME/Library/Application Support/iPhone Simulator/5.0/Applications/E075DBE3-BFEA-4F6A-9DFA-2CC912E14863/Movies/WebSurg/FirstVideo.mp4
2012-10-08 10:14:52.459 WebsurgTemplates[3722:17903] Movie Load State: 0
2012-10-08 10:14:52.460 WebsurgTemplates[3722:17903] Alternate movie Path: /Users/THISISME/Library/Application Support/iPhone Simulator/5.0/Applications/E075DBE3-BFEA-4F6A-9DFA-2CC912E14863/WebsurgTemplates.app/FirstVideo.mp4
I would greatly appreciate any suggestions and help!!
UPDATE
I made no progress so far. I managed to log some other data to the console, some info that may help more at solving this problem. I tried to make a blank project taking the direct download of the video as link to play the video but it didn't work. What happens is exactly the same thing. jaydee3 said that maybe it was due because I had probably no access to NSMoviesDirectory. So I changed to NSDocumentDirectory but that didn't solve the problem. I checked that the file exists and the format in which it is saved so it can be readable by the player. Still it doesn't work. I don't know what am I doing wrong. Thanks again for the suggestions/help.
Here the results of the debug. more complete:
if ([[NSFileManager defaultManager] fileExistsAtPath:moviePath]) {
NSLog(#"FILE EXISTS");
CFStringRef fileExtension = (__bridge CFStringRef) [moviePath pathExtension];
CFStringRef fileUTI = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, fileExtension, NULL);
if (UTTypeConformsTo(fileUTI, kUTTypeImage)) NSLog(#"It's an image");
else if (UTTypeConformsTo(fileUTI, kUTTypeMovie)) NSLog(#"It's a movie");
else if (UTTypeConformsTo(fileUTI, kUTTypeText)) NSLog(#"It's text");
}
RESULTS
[6343:17903] MOVIEPATH: /Users/myname/Library/Application Support/iPhone Simulator/5.0/Applications/E075DBE3-BFEA-4F6A-9DFA-2CC912E14863/Documents/FirstVideo.mp4
[6343:17903] FILE EXISTS
[6343:17903] It's a movie
Okay so I managed to solve the problem and find the culprit.
In a brief note it was because the downloaded movie wasn't being saved properly (I am currently investigating the possible reasons why). And because of this the player was trying to play a file that existed, was in the correct format and the correct name but that was empty. I found this out by logging all the file sizes after download and transfer and play.
Now being more descriptive the issue was that I was downloading the movie to the NSCachesDirectory and then saving it to the NSDocumentDirectory. I found this because I started to wonder if it really found the file and if the file was "edible". It now plays the movie fine as I download it directly to the NSDocumentDirectory. Now I have to solve just in case the connection goes down. As saving in the NSCachesDirectory solved that automatically. I am open to suggestions on that. here is the code that didn't work to transfer the data from the NSCachesDirectory to NSDocumentDirectory:
NSArray *paths = NSSearchPathForDirectoriesInDomains
// HERE I changed NSCachesDirectory to NSDocumentDirectory fixed it
(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *cachesDirectory = [paths objectAtIndex:0];
NSString *downloadPath = [cachesDirectory stringByAppendingPathComponent:
#"DownloadedVideo.mp4"];
NSArray *newPath = NSSearchPathForDirectoriesInDomains
(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *moviesDirectory = [NSString stringWithFormat:#"%#",
[newPath objectAtIndex:0]];
self.downloadOperation = [ApplicationDelegate.mainDownloader downloadVideoFrom:
#"http://www.blablabla.web/iphone/download.php"
toFile:downloadPath];