Titanium JIRA Archive
Titanium SDK/CLI (TIMOB)

[TIMOB-25680] iOS 11.2: DocumentViewer not displaying PDF files (Apple regression)

GitHub Issuen/a
TypeBug
PriorityHigh
StatusClosed
ResolutionFixed
Resolution Date2018-01-23T16:44:58.000+0000
Affected Version/sRelease 7.0.1
Fix Version/sRelease 7.0.2
ComponentsiOS
Labelsapplebug, documentViewer, ios
ReporterMotiur Rahman
AssigneeHans Knöchel
Created2018-01-17T02:01:12.000+0000
Updated2018-01-24T16:22:40.000+0000

Description

Issue Using DocumentViewer on iOS 11.2.X is not rendering PDF files. Steps to repro 1. Just run the following test code 2. At first, place a pdf file in the resource directory. Expected result: .pdf file should show in the DocumentViewer. Actual result: .pdf file is not being shown by the DocumentViewer.
var win = Ti.UI.createWindow();

// Create a document viewer to preview a PDF file
docViewer = Ti.UI.iOS.createDocumentViewer({
  url : 'example.pdf'
});

docViewer.show();
win.open();

Attachments

FileDateSize
example.pdf2018-01-17T09:45:54.000+0000433994

Comments

  1. Hans Knöchel 2018-01-17

    *EDIT*: There seems to be a breaking change in 11.2 that developers came across (known iOS issue). Basically, iOS 11.2 required developers to copy the PDF to the temporary- or application-support directory before using. Read more about it [here](https://forums.developer.apple.com/thread/91835). We will:

    File a radar at Apple to provide a fix

    Provide a workaround (eventually in both JS and the SDK, so an SDK-update won't necessarily required to workaround this issue)

    Tested with all possible combinations (main-thread, kroll-thread, jscore, ticore) and it works fine. My example code:
       var win = Ti.UI.createWindow({
         backgroundColor: '#fff'
       });
       
       var btn = Ti.UI.createButton({
         title: 'Open PDF'
       });
       
       btn.addEventListener('click', function(e) {
         var docViewer = Ti.UI.iOS.createDocumentViewer({
           url : 'example.pdf'
         });
        
         docViewer.show();
       });
       
       win.add(btn);
       win.open();
       
    I've also attached my sample PDF file that worked fine. As a side-note: We haven't touched the DocumentViewer API for years, since it's a simple interface which we completely expose already.
  2. Hans Knöchel 2018-01-17

    Update

    Here is the workaround for the iOS issue, together with detailed documentation about what is happening:
       var win = Ti.UI.createWindow({
         backgroundColor: '#fff'
       });
       
       var btn = Ti.UI.createButton({
         title: 'Open PDF'
       });
       
       btn.addEventListener('click', openPDF);
       
       win.add(btn);
       win.open();
       
       // Open the PDF file
       function openPDF() {
         var fileName = 'example.pdf';
         
         // For iOS 11.2, workaround the Apple issue by creating a temporary file and
         // reference it. It will be removed from filesystem once the app closes.
         // Read more here: http://nshipster.com/nstemporarydirectory/
         if (isiOS11_2()) {
           fileName = fileInTemporaryDirectory(fileName);
         }
         
         var docViewer = Ti.UI.iOS.createDocumentViewer({
           url: fileName
         });
        
         docViewer.show();
       }
       
       // Check if the current device runs iOS 11.2+
       function isiOS11_2() {
       	var version = Ti.Platform.version.split(".");	
       	return (parseInt(version[0]) >= 11 && parseInt(version[1]) >= 2);
       }
       
       // Create a temporary file with the contents of the old file
       // Expects the file to be in the resources directory. If you receive the file 
       // from an API-call, receive pass the Ti.Blob/Ti.File/text to "write" directly.
       function fileInTemporaryDirectory(fileName) {
         var file = Ti.Filesystem.getFile(Ti.Filesystem.resourcesDirectory, fileName);
         
         if (!file.exists()) {
           alert('File does not exist in resources!');
           return;
         }
         
         var newFile = Titanium.Filesystem.getFile(Ti.Filesystem.tempDirectory, fileName);
         newFile.createFile();
         
         if (!newFile.exists()) {
           alert('New file could not be created in temporary directory!');
           return;
         }
         
         newFile.write(file);
         
         return newFile.nativePath;
       }
       
    Basically, we create a temporary file in /tmp that will be flushed once the app is closed, so it doesn't effect the device's storage. Keeping this issue open to also provide an SDK workaround that detects the type of path provided and fixes it internally. Hopefully iOS fixes this issue in iOS 11.2.x, but let's try to keep as flexible as possible.
  3. Hans Knöchel 2018-01-17

    PR (master): https://github.com/appcelerator/titanium_mobile/pull/9741 PR (7_0_X): https://github.com/appcelerator/titanium_mobile/pull/9742 Test-Case:

    Run the above test-case and remove the comment out the isiOS11_2() check. Without this line, the PDF will not be displayed

    Comment it in the line if-statement again. It should now work, even with the old SDK (master/7.0.1)

    Now uninstall the app, use the PR and repeat steps 1 und 2. They should still display the file without issues

  4. Eric Wieber 2018-01-23

    FR Passed. Workaround is working as designed. Document viewer is able to display PDF files in iOS 11.X
  5. Eric Wieber 2018-01-24

    Verified in SDK builds 7.0.2.v20180123170142 & 7.1.0.v20180124063413

JSON Source