Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using UIDocumentInteractionController to display presentPreviewAnimated: via UIWebView

I'd like to intercept the clicks from any of the supported file types of the UIDocumentInteractionController and display them in a modal view (provided by presentPreviewAnimated: method of UIDocumentInteractionController). This modal view also provides the "Open In..." functionality to open any of these documents in other compatible applications on the device. The code below will intercept these clicks, detect if the URL string has any of the appropriate suffixes, load this data, write it to the directory, read it again and finally use the data with the presentPreviewAnimated: method. I have to write the data to the file system first because the UIDocumentInteractionController requires local data and cannot use the data directly from the URL (as far as I've read).

- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType {  if (navigationType == UIWebViewNavigationTypeLinkClicked) {   ILog(@"URL loading for NavigationTypeLinkClicked: %@", request.URL.absoluteString);    if ([request.URL.absoluteString hasSuffix:@"pdf"] || [request.URL.absoluteString hasSuffix:@"doc"] || [request.URL.absoluteString hasSuffix:@"xls"] || [request.URL.absoluteString hasSuffix:@"ppt"] || [request.URL.absoluteString hasSuffix:@"rtf"] || [request.URL.absoluteString hasSuffix:@"key"] || [request.URL.absoluteString hasSuffix:@"numbers"] || [request.URL.absoluteString hasSuffix:@"pages"]) {    if (NSClassFromString(@"UIDocumentInteractionController")) {                 NSArray *parts = [request.URL.absoluteString componentsSeparatedByString:@"/"];                 self.previewDocumentFileName = [parts lastObject];                 NSLog(@"The file name is %@", previewDocumentFileName);      // Get file online                 NSData *fileOnline = [[NSData alloc] initWithContentsOfURL:request.URL];      // Write file to the Documents directory                 NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);                 NSString *documentsDirectory = [paths objectAtIndex:0];                 if (!documentsDirectory) {NSLog(@"Documents directory not found!");}                 NSString *appFile = [documentsDirectory stringByAppendingPathComponent:previewDocumentFileName];                 [fileOnline writeToFile:appFile atomically:YES];     NSLog(@"Resource file '%@' has been written to the Documents directory from online", previewDocumentFileName);     [fileOnline release];      // Get file again from Documents directory                 NSURL *fileURL = [NSURL fileURLWithPath:appFile];      UIDocumentInteractionController* docController = [UIDocumentInteractionController interactionControllerWithURL:fileURL];      docController.delegate = self;     [docController retain];      BOOL result = [docController presentPreviewAnimated:YES];      if (!result) {      [docController release];     }     return NO;    }   }  }   // Do lots of other URL-detecting stuff here } 

I also implement the following delegate methods to use the appropriate view and to delete the file after the view has been dismissed (previewDocumentFileName is a class variable):

#pragma mark - #pragma mark Document Interaction Controller Delegate Methods  - (UIViewController *)documentInteractionControllerViewControllerForPreview:(UIDocumentInteractionController *)controller {  return self; }  - (void)documentInteractionControllerDidEndPreview:(UIDocumentInteractionController *)controller {  NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);     NSString *documentsDirectory = [paths objectAtIndex:0];     NSString *appFile = [documentsDirectory stringByAppendingPathComponent:previewDocumentFileName];  NSFileManager *fileManager = [NSFileManager defaultManager];  [fileManager removeItemAtPath:appFile error:NULL];  //[controller release]; // Release here was causing crashes } 

Please note that the Apple Documentation made specific mention of the fact that the document controller needed to be retained manually, so I did that. I also needs to be released, so I do that if the controller wasn't used (top method) and attempted to release it after it was used (delegate method), but that release was causing crashes, so I removed it and things seem to be working fine from that standpoint.

With the background out of the way, my question has to do with the fact that while this code seems to work in the iPhone simulator (the online document is displayed correctly in the presentPreviewAnimated: view, although without the 'Open In...' dialogue that can't be used in the sim), it is not showing the presentPreviewMethod: on the iPad sim or my actual iPhone or iPad devices. I believe the method is being called correctly, but the presentPreviewAnimated: method is returning NO, which means it was not able to display the document preview.

Why would this be? Am I not saving the file properly (and thus it is not being detected as a *pdf or *doc, etc)? What else could I be doing wrong? There is very little documentation or example code out there besides the Apple Documentation, so I hope that at the very least this code will be helpful to someone, although I would like to get it working 100% first. Thanks in advance.

like image 541
Ricky Avatar asked Jul 24 '10 12:07

Ricky


1 Answers

Ignoring the fact that you [docController retain] and [controller release] - I recommend you try [docController autorelease]. There's a chance it's trying to do something immediately after you return, but not later during execution. If that's the case, you want to release the controller a bit later, which is what autorelease is for. If it still crashes, you do not own the object. Though, if you are retaining it, you are responsible for releaseing it. Once you've autoreleased it, set it to nil so you don't try to touch it again.

like image 129
Daniel Avatar answered Sep 21 '22 09:09

Daniel