5
votes

Our iPad app can show Documents and save them offline when needed. I've got a QLPreviewController subclass named DocumentViewController (named DVC from now on) for showing them.

Workflow of the app: - The user clicks a name of a document and the DVC is pushed on to show the document. - The DVC downloads the file offline and shows it when done. (So the HTTP URL is downloaded, stored offline, and an offline URL is returned)

The weird thing is, is that only PDF files are working with the offline URL, and the rest crashes.. (it works with online links though)

I did some tests and when I put file:// before the offline link the app does not crash but the DVC is ging me some information about the file (like that it is a excel 97-2004 document).

So some info is transferred, but I can't figure out what the problem is.

Here are some screenshots and after that some code.

enter image description here

code: Note that Document is a model class with document properties like id, name, file type and url.

//DVC QLPreviewController dataSource method for returning url
- (id <QLPreviewItem>) previewController: (QLPreviewController *) controller previewItemAtIndex: (NSInteger)index
{
    [SaveHelper saveDocumentFileAndPropertyWithDocument:document];

    //[SaveHelper getDocumentFileWithDocument:document]; without file://
    //if I return document.documentUrl it is working with all files except iworks files)
    return [SaveHelper getDocumentFileAsPathWithDocument:document]; //with file://
}

//SaveHelper methods
+ (NSString *)documentFilePathWithDocument:(Document *)document
{
    return [[self documentFilePath] stringByAppendingPathComponent:[NSString stringWithFormat:@"%@%d.%@", DOCUMENT_FILE_PREFIX, document.documentId, document.documentType]];
}

+ (NSURL *)saveDocumentFileAndPropertyWithDocument:(Document *)document
{
    if([self saveDocumentPropertyWithDocument:document])
    {
        return [self saveDocumentFileWithDocument:document];
    }

    return nil;
}

+ (NSURL *)saveDocumentFileWithDocument:(Document *)document
{
    NSData *data = [NSData dataWithContentsOfURL:document.documentURL];

    NSString *fullPath = [self documentFilePathWithDocument:document];

   if([[NSKeyedArchiver archivedDataWithRootObject:data] writeToFile:fullPath atomically:YES])
   {
       return [NSURL fileURLWithPath:fullPath];
   }

    return nil;
}

+ (NSURL *)getDocumentFileWithDocument:(Document *)document
{
    return [NSURL fileURLWithPath:[self documentFilePathWithDocument:document]];
}

+ (NSURL *)getDocumentFileAsPathWithDocument:(Document *)document
{
    return [NSURL fileURLWithPath:[@"file://" stringByAppendingPathComponent:[[self getDocumentFileWithDocument:document] absoluteString]]];
}

If more code needed, just say.

EDIT:

When logging the URL passed trough the 'getDocumentFileAsPathWithDocument' method:

url: file:/var/mobile/Applications/xx-xx/Documents/documentFiles/file_20.pdf
url: file:/var/mobile/Applications/xx-xx/Documents/documentFiles/file_80.docx

Where the PDF file is working and the docx not

When I try to load an image(jpg) from local storage I get a black screen with this error message:

warning: Unable to read symbols for /Developer/Platforms/iPhoneOS.platform/DeviceSupport/4.3.5 (8L1)/Symbols/System/Library/Frameworks/QuickLook.framework/DisplayBundles/Image.qldisplay/Image (file not found).
warning: No copy of Image.qldisplay/Image found locally, reading from memory on remote device.  This may slow down the debug session.

EDIT:

The webview does not work either with the local urls. PDF is fine but the office files gives an message "Unable to read Document, the file format is invalid". The iWorks documents give the same error as the quicklook. I think its somewhere at the save and load of the format, I savve them as a NSDATA but after that there is no hint for the iPad to see if it is for example a word document (only the extension).

5
Have you tried using [NSURL fileURLWithPath:...]? The way your are handling file URLs is very fragile.rbrown
I have changed it to "return [NSURL fileURLWithPath:fullPath];" (I update the code above to), but I still got the same problem.Justin

5 Answers

3
votes

You haven't posted your download code, but I believe that the problem is there. Files from Pages (.pages extension) aren't actual files, they are bundles, i.e. directories that contain files and show as a single item in Finder (look up a .pages file in Finder, right-click it and select 'Show contents'). Downloading a .pages file is actually like downloading a directory: it depends on the web server what kind of result you get but it's most likely an error page.

You could detect that it's a .pages file and try to download all of its contents manually, but you'd have to study the structure of the files to see if that's possible because it's unlikely that you can request the contents of the directory from a web server.

The results for the .ppt and .xls files look normal to me; I think it unlikely that the iPad can preview MS Office documents at all.

Edit: apologies, I just read that iOS can preview MS Office documents. Perhaps the documents get somehow corrupted during download? Have you tried to set your download location to the app's documents folder and enable iTunes file sharing? That way you can download some documents, pull them off your device and then try to open it on your PC to see if that works.

3
votes

We finally found the solution!

I was right that the problem was with saving the document.

I needed to change the save method in:

+ (NSURL *)saveDocumentFileWithDocument:(Document *)document
{
    NSData *data = [NSData dataWithContentsOfURL:document.documentURL options:NSDataReadingUncached error:nil];

    NSString *fullPath = [self documentFilePathWithDocument:document];

    if([[NSFileManager defaultManager] createFileAtPath:fullPath contents:data attributes:nil])
    {
        return [NSURL fileURLWithPath:fullPath];
    }
//OLD CODE
//   if([[NSKeyedArchiver archivedDataWithRootObject:data] writeToFile:fullPath atomically:YES])
//   {
//       return [NSURL fileURLWithPath:fullPath];
//   }

    return nil;
}

SO saving it with the filemanager and not with a keyedarchiver.

0
votes
  1. Did you check if the size of the files is the same both online and offline? It is possible that the file download wasn't complete

  2. Try using the URL of the MS Office documents with a normal NSURL object and opening in a UIWebView. Does it work then (so we know if its the document or your class)?

  3. Try using NSURL's fileURLWithPath: method in the getDocumentFileAsPathWithDocument: It is possible that the URL being returned is incorrect (though doesn't look like it from the logs but doesn't hurt to try)

0
votes

first of all, use this code to make sure your documents are there,because i think the error cause by your documents path.

NSFileManager *fileManager=[NSFileManager defaultManager];


        if([fileManager fileExistsAtPath:fullPath]){
            NSLog(@"%@  exsit! ",fullPath);
        }else{
            NSLog(@"%@  not exsit! ",fullPath);

        }
0
votes

If any of one have same problem even though you did everything suggestions above. (I had same problem, when I downloaded some files from google drive.)

Try this!

Put 'x' end of your file extension to be recognized as a new version of format. (it's working only for 'doc' and 'ppt' files, not for 'xls' files) Yes, I know this is not a appropriate way to solve this problem, but it's worth to try it.

Believe me I tried everything!

Hope you help.