“Open With” in iOS PhoneGap Apps

Let’s say that you have a PhoneGap app that has access to documents, but you want to open those documents in a different application outside of your PhoneGap application.   For example, let’s say you have a DRM-protected PDF document that gets authenticated by an Adobe LiveCycle server.   On iOS devices, the DRM can only be authenticated if you are using Adobe Reader.  So, you need to delegate handling of that file to Adobe Reader.

You have two ways of handling this type of scenario: Either the target app opens the document via a custom URL scheme, or your app delegates to another application that is registered to handle a specific file format.   If the target app has a custom URL scheme, you just make a request following that scheme’s conventions… Simple, right?   If the target app does not have a custom URL scheme, then what do you do?

iOS supports the ability to use an “open with” menu through the UIDocumentInteractionController class, but by default this is not available to PhoneGap applications.  Luckily for us, PhoneGap is extensible, and we can create native plugins for whatever we want.

Since Adobe Reader does not yet support a custom URL scheme, you could use the UIDocumentInteractionController to suggest that the user opens the document with Adobe Reader, and this is exactly what I did…

I created a PhoneGap native plugin that allows you to specify a file URL and UTI, and it will use the UIDocumentInteractionController class to ask the user to select another program to use for handling the file.  Check out the video below to see it in action:

Using this within your PhoneGap app is dirt simple:

ExternalFileUtil.openWith(
     "http://www.tricedesigns.com/temp/drm.pdf",
     "com.adobe.pdf" );

The plugin workflow is as follows:

  1. PhoneGap app requests ExternalFileUtil.openWith action, specifying a file URL and UTI.
  2. Plugin downloads the file and saves as a local temp file
  3. Plugin uses UIDocumentInteractionController to launch an “open with” dialog
  4. User selects appropriate app to “preview” the content
  5. The appropriate reader app is opened and UI/input is handed over to the target app
  6. Plugin deletes the temp file

Even though I’ve demonstrated this with a PDF and Adobe Reader, this is not limited to just PDF handling.  This plugin should work with any file type that has registered handlers (although I’ve only tested with PDFs & Adobe Reader).  You just need to specify the UTI that is supported by the target application(s).  You can view a list of predefined UTI values from Apple, or create your own applications that support custom UTIs.

If you’re interested, YES, you can use this today.  I’ve already committed it to GitHub and sent a pull request to the master phonegap-plugins repo.  Go download it now!

Enjoy!

  • http://none Mahendra

    Hi,

    This seems to be a great work in direction of opening documents especially PDFs. Although, I haven’t yet tried it – but any insights on whether the plugin will work with PDFs within the ‘www’ folder itself or it needs to be an online document?

    Regards

    Mahendra

    • http://www.tricedesigns.com Andrew

      You could definitely use this technique. You would have to change the native plugin some, b/c it expects remote files. However, this technique would definitely work. As long as you can access the raw file, you can send it to “preview” in other apps.

    • Rich

      Mahendra, Did you ever figure this out??? I am trying to change the plugin to work with local files. Thanks!

  • http://n/a Mahendra

    Hi,

    I just tried the plugin – It doesn’t work with v1.4; so I upgraded to v2.0.

    I added ‘ExternalFileUtil’ as the key & value to Cordova.plist and used the code:

    ExternalFileUtil.openWith(
    “http://www.tricedesigns.com/temp/drm.pdf”,
    “com.adobe.pdf” );

    However, it gives me the plugin error:

    2012-10-15 23:44:30.222 TestApp[2923:13403] ERROR: Plugin ‘ExternalFileUtil’ not found, or is not a CDVPlugin. Check your plugin mapping in Cordova.plist.
    2012-10-15 23:44:30.223 TestApp[2923:13403] FAILED pluginJSON = {“className”:”ExternalFileUtil”,”methodName”:”openWith”,”arguments”:["INVALID","http://www.tricedesigns.com/temp/drm.pdf","com.adobe.pdf"]}

    May the plugin mapping is wrong.. Can you post what is the key/value pair to be used in Cordova.plist.

    It would be great if you can upload a working sample project using which anybody can understand what needs to be done and how it is implement.

    Regards,

    Mahendra

    • http://www.tricedesigns.com Andrew

      The key “ExternalFileUtil” maps to the CDVExternalFileUtil class. Make sure that the class (both .h and .m files) has been added to your Xcode project, and that you can see it in the sidebar on the left in Xcode.

  • Paul

    Hi,

    I tried your plugin.

    It stops after downloading the file to the temp-dir (log-outputs).

    Is your plugin compatible with cordova 2.1.0?

    br,
    Paul

    • http://www.tricedesigns.com Andrew

      Yes, it should work. I wrote it with 2.0, but I see no glaring reason that it wouldn’t work in 2.1, although PhoneGap 2.1 supports ARC – did you (or Xcode) make changes to support ARC? If so, that actually changes your Objective-C code. If you un-comment my log statements in CDVExternalFileUtil.m, you can get more insight into what is happening at runtime. The PDF download is a blocking operation, so if the UI just hangs, it’s still working, but downloading. This is especially apparent if it’s a big PDF file. If this is the case, you may want to make the download non-blocking, and make the download/open-with sequence asynchronus.

  • Paul

    Thanks for your answer.

    I found a solution by changing the view argument from “cont.view” to “cont.webView” for iPad Development.

    br,
    Paul

  • manish

    Hello sir, I am using externalutil plugin to open pdf and doc file, but plugin is not calling in cordova2.2.0 …I have added the .h and .m files , with plugin name in Cordova plist file .also added the js file in www folder and calling from index .html on click button..
    Please I want to know how to use this plugin in application .help me
    If you provide proper document to add and use this plugin it will be very helpful for us ..
    Thanks and regards
    Manish

  • laziel

    Hi.
    I’ve tried and failed to use your awesome plugin, for png(public.png) image.
    It doesn’t appears external handler list. File has written in local and presentOpenInMenuRect, successCallback(writeJavascript) processed also in log outputs. ARC doesn’t matter on this problem.

    I need you help.
    laziel.

  • Helmut

    Hi,I tried your example on github,copying the whole content of “sample/www” folder on my “www” folder,but it doesn’t work.
    Have I also to include the obj-c file?
    If yes, in which folder have I to include them?
    Thank you (sorry for my english)

  • kinszhang

    Hi, thanks for the brilliant plugins. However, I tried this plugin but it didn’t work. The debugger shows PluginResult toSuccessCallbackString:cordova.callbackSuccess(‘INVALID’,{“status”:1,”message”:”",”keepCallback”:false}); and the Openwith dialogue didn’t pop up.

    I have copy the .h and .m file into the project plugins folder, in Cordova.plist, I add the mapping, key is ExternalFileUtil, value is CDVExternalFileUtil. and I use your example file but it still didn’t work. Any ideas for that? Thanks

    • http://www.tricedesigns.com Andrew

      Is this happening on an iPad? For some reason, people have been telling me that this line doesn’t work on the iPad:

      CGRect rect = CGRectMake(0, 0, cont.view.bounds.size.width, cont.view.bounds.size.height);

      Instead, change it to a static size, and it should work:

      CGRect rect = CGRectMake(0, 0, 1024, 768);

      • kinszhang

        Thanks, I was figured out later I post my comment, I think it might be relate to the difference between ipad and iphone handle the Open With dialogue. In iphone the Open With menu is displayed like a toast, in iPad it doesn’t.

  • utsu

    thanks for the great plugin. in iOS6.1 iPhone5 works great well.
    but unfortunately iOS6.1 iPad (3rd generation retina display) didn’t work well with:
    CGRect rect = CGRectMake(0, 0, 1024, 768); or changing “cont.view” to “cont.webView”.
    in Cordove(Phonegap)2.2.

    does anyone have solution?

    • Bill

      This does not work for me either. I am getting an error ‘Unable to get data for URL: The operation couldn’t be completed. (Cocoa error 260.)’ with the above solutions for iPad 2 running iOS 6.1. When tested on iphone simulator I was able to get the dialog to open using Laziel’s above comment (changing it to presentOpenInMenuFromRect), but the results were not expected, only options to print, copy or email. It is a shame the latest software will not allow this plugin to work properly :(

      • http://www.tricedesigns.com Andrew

        You will only get options like “Open With Reader” for apps that you actually have installed. If you don’t have reader installed on your device, you will not get the option to open the file with it. If you are able to see the prompt with “print”, “copy” and “email”, then it is working properly.

  • KL

    does it work with data uri? like this:

    ExternalFileUtil.openWith( “data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUA
    … 9TXL0Y4OHwAAAABJRU5ErkJggg==”, “com.adobe.pdf” );

    • http://www.tricedesigns.com Andrew

      You could probably modify the plugin to work with a data uri like that, but in its current form, no I do not think it will work. It expects a remote URL, then attempts to download the contents locally. Once downloaded, it attempts too preview the file/content using the OS’s preview capability.

      • KL

        I added the plugin and it worked, but after it opened another viewer, the phone gap app crashed, do you have any idea?

        • http://www.tricedesigns.com Andrew

          Do you have any console output, error messages, or additional detail? Without some additional information, it’s pretty much impossible to say.

          • KL

            no error message, but when I switched back to the phonegap, instead of stayed on the same page, the phonegap app restarted. I looked into the code in your plugin and played with it, and it worked when I replaced presentOpenInMenuFromRect with presentOptionsMenuFromRect.

  • Kas

    Hi Andrew, thanks for the great plugin. can you update to cordova2.4 ?
    Thanks.

    • http://www.tricedesigns.com Andrew

      The deprecated API signature should still work. I have plans to update all my plugins, but unfortunately just haven’t had the time to update all of them.

  • jarek

    how do i insert the plugin?

  • kapil kumawat

    Hi Andrew,

    I want to use your plugin in my project, is you plugin is assciated with any LICENSE.

    Regards,
    -Kapil Kumawat

  • Danial

    Hi, thanks for this, but so far I cannot get it to work on my iPad?

    I have the project setup and all appears to be working well but I do not get any popup to choose a reader from?

    I have tried this:
    CGRect rect = CGRectMake(0, 0, cont.view.bounds.size.width, cont.view.bounds.size.height);
    [controller presentOpenInMenuFromRect:rect inView:cont.view animated:YES];

    ans this:
    CGRect rect = CGRectMake(0, 0, 1024, 768);
    [controller presentOptionsMenuFromRect:rect inView:cont.webView animated:YES];

    and test for the result of the presenting of the documentinteractioncontroller that returns true but neither appears or calls the event to signal did pass file to reader

    ???

    • http://www.tricedesigns.com Andrew

      Do you have any additional detail, OS version, device type, or error messages? I’ve heard other people have issues, all of which are discussed in the blog comments on this post.

  • Marc

    Hi Andrew, thank you for your plugin, it is exactly what I want for my application.

    Unfortunately, it doesn’t seem to work on my project. Even your simple PDF example doesn’t bring up any “Open with” menu. I have installed your plugin and I know it’s called because I uncommented some NSLog lines from your code.

    It downloads the file (I can open the downloaded file by commenting your cleanup code) but the menu doesn’t open. The log does not show any error at all. Even I set two callbacks (success, failure) and the success callback is ALWAYS executed (but it does not receive any argument).

    With this information, do you have a clue on what’s wrong in my app?

    Thank you.

    • http://www.tricedesigns.com Andrew

      Check the previous comments on this blog. People have had issues in certain cases, on certain devices. Otherwise, do you have any additional information that could be used to debug the issue?

  • Stefan

    Hi,

    I’m using Codova 2.5, Xcode 4.6.1 and can’t get this running.

    In iPAd Simulator I get a Success callback but the the app seems to hang ,meaning no opening of the menu as in your video.

    On my physical Ipad I get following error:
    2013-04-04 13:25:14.684 eidApp[4074:907] The file name is a_file_com_adobe.pdf
    2013-04-04 13:25:16.301 eidApp[4074:907] Resource file ‘a_file_com_adobe.pdf’ has been written to the Documents directory from online
    2013-04-04 13:25:18.493 eidApp[4074:907] *** Terminating app due to uncaught exception ‘NSGenericException’, reason: ‘-[UIPopoverController dealloc] reached while popover is still visible.’
    *** First throw call stack:
    (0x31a452a3 0x398ae97f 0x31a451c5 0x33c35a91 0x33b87e3d 0x398ab489 0×31988441 0x3235c185 0x31a1a683 0x31a19ee9 0x31a18cb7 0x3198bebd 0x3198bd49 0x355402eb 0x338a1301 0x662e7 0x662a8)
    libc++abi.dylib: terminate called throwing an exception

    I tried with cont.view. and cont.Webview as mentioned in anoher mail but no success.

    Regards,

    Stefan

    • http://www.tricedesigns.com Andrew

      Hi Stefan,
      Do you have any sample code that you can share? It’s hard to say exactly what the error might be.

  • kapil

    Can you provide me the license information to use this plugin.

  • http://www.jcesarmobile.com jcesarmobile

    Hi,
    Do you know if adobe reader support url schemes now? or if adobe is going to support it soon?

    • http://www.tricedesigns.com Andrew

      To my knowledge, it does not support URL schemes. Unfortunately, I do not know whether that is in the roadmap.

  • ben

    Any suggestions on how to change the plugin to work with a data URI ? I’m attempting to use this with another great library jsPDF. Just trying to figure out how I can use this to open the document in something other than inappbrowser, so the user can print/email the pdf file that gets generated.

    • http://www.tricedesigns.com Andrew

      You can’t use a data URL in the preview implementation. Instead, you can save the generated pdf file to your local file system, then use the preview to open the local file. I have done this in the past… I’ll post code to the blog later if I have time to dig it up.

  • Mahendra Liya

    For all those of you having problems with this plugin working for iPad, please replace the code for ‘CGRect rect’ with ‘CGRect rect = CGRectMake(0, 0, 1500.0f, 50.0f);’ and it will show you the pop-up.

    Hope that helps.

    • Ralf Richtsteiger

      Thanks a lot, it works.

  • Rich

    Could you please submit this plugin to PhoneGap Build? I’d very much like to use this functionality in my application. Thanks!

  • Prassi Poonacha

    Hi Andrew

    I am trying to open an HTML page in a different application rather than in a chrome browser or safari browser. When I use this ExternalUtil plugin, it doesn’t work as expected. I mean it doesn’t give out open with options. What I would like to see in open with options is my xyz application, chrome and safari browser. Could you please help here? I am trying to do this in an ipad simulator.

  • Prassi Poonacha

    Hi Andrew

    I am trying to open an HTML page in a different application rather than in a chrome browser or safari browser. When I use this ExternalUtil plugin, it doesn’t work as expected. I mean it doesn’t give out open with options. What I would like to see in open with options is my xyz application, chrome and safari browser. Could you please help here? I am trying to do this in an ipad simulator.

  • Cristian Cascante

    Yes please! :)
    Great job!

  • Cristian Cascante

    Anybody know if this plugin works with Phonegap 2.9?

    I have installed it on xcode 4.6.3 but it didn’t work for me …

    The javascript and classes are working, but nothing happen

    Any idea?

    Best regards ;)

    • http://www.bluestudios.co.uk/blog/ John

      I’m having the same issue in 2.9 havent started looking into the problem yet.

      • Cristian Cascante

        Hello,

        But does it works on iPhone?

        En my case it never works, I think the problem is with the new plugin signature, so that this plugin is not working for Phonegap 2.1 and higher versions…

        Is that correct?

        Ho to fix the problem with taht line:

        NSString* callbackID = [arguments pop];

        Any idea?
        Best regards

        • Cristian Cascante

          Great!
          It works on Phonegap 2.9 ;)
          You have to try it on a real device, not simulator ;)

          Best regards,

          • John Sim

            Great! I only tried on simulator – I will give it a go did you do anything else specific to the code and did you use the feature or plugin tag on the config?

            Thanks

          • Cristian Cascante

            No. Plugin works with Old signature plugin.
            You don’t have to modify anything.

  • Cristian Cascante

    Hello!

    So whats happening with new plugin signature,
    Is necessary to replace it?

    Thanks,
    best regards ;)

  • Cristian Cascante

    Hi,

    is necessary to modify CDVExternalFileUtil.m with new plugin signature in order to make the plugin work?

    Thanks,
    Best regards

  • Josef Norlin

    Thank you for a great work Andrew! How would I go about doing the opposite, to make my app visible in others “Open with…”-suggestions and then receive the file still using PhoneGap?

    • supermegapollo

      Hi there Josef.
      Little old thread, but I’ll give it a shot.
      Did you found the way –to make your app visible in others “Open with…”– ??

      Regards =)

  • Greg Hudy

    I am having an issue with the plugin – the error from xcode is Method openWith: not defined in Plugin ExternalFileUtil – I am using PG 3 Then it gives failed pluginJSON=["INVALID","ExternalFileUtil","openWith",[ "URL of file","com.adobe.pdf"]

    Any suggestions?

    • njtman

      This plugin is old and doesn’t support PhoneGap 3.0.

      I updated the plugin to support Cordova/Phonegap 3.0 and ARC.

      Check out my github page for the new files

      https://github.com/njtman/phonegap-plugins/tree/master/iOS/ExternalFileUtil/plugin/obj-c

      • Greg Hudy

        Thanks, I will check it out and let you know how it goes!

      • Greg Hudy

        looks like it is wanting to work, but when ran on the ipad the open with icon appears in the upper left corner and when selecting the app from that list, it doesn’t open – any suggestions?

        • njtman

          I tested on my iPhone 5 w/ iOS 7 and iPad 4 w/ iOS 6 and it worked just fine. That being said, on my colleagues iPad 2 w/ iOS 7, he had the same issue as you. I haven’t been able to look any further into this issue, but I definitely think we are headed in the right direction.

          • Greg Hudy

            Yeah, unfortunately, I just upgraded to iOS 7 today too! Thanks for checking into it and let me know what you find, thanks again!

          • njtman

            My colleague that was having the issues on his iPad 2 w/ iOS7 wiped and restored his device. Since then, he is no longer experiencing this issue. The open with box pops right up, and the book loads perfectly into the iBookStore app. I have been unable to replicate this issue personally.

          • Greg Hudy

            I will have to see if that works for me as well. Did he do a backup and then restore or did he do fresh installs of everything?

          • njtman

            I believe he did fresh installs

        • http://www.neobaum.de/ Elderov Ali

          PhoneGap v3.0 + iPod v.6.3.1 doesn’t open pdf, without emotions on this function… how can i fix this?

      • walid taraf

        Hey Greg, were u able to install the original one thru PG build, or Cordova build or even plugman? I am on 3.1 and none of them worked…they all have a missing plugin.xml. I can take your code but it just wont build without a proper CLI-mandated plugin.xml. Thx!

        • Marcel Mrowetz

          Same here!! I’m on PG 3.1.0 on MAC OS 10.9 and I’m getting this:

          phonegap local plugin add https://github.com/phonegap/phonegap-plugins.git

          [phonegap] adding the plugin: https://github.com/phonegap/phonegap-plugins.git

          fs.js:427

          return binding.open(pathModule._makeLong(path), stringToFlags(flags), mode);
          ^
          Error: ENOENT, no such file or directory ‘/var/folders/dj/5xhtk5yx1xs0z4hx_44g_74w0000gn/T/plugman-tmp1382633341863/plugin.xml’

          Maybe I’m doing something wrong??

          • Marcel Mrowetz

            Now I can see the popup-menue for the pdf-File, but if I click on a app like “open in iBooks”, nothing happens?!

            PG 3.0, Mac OS 10.9, iOS7, XCODE 5.0.1

            Is there another option for the util instead of “com.adobe.pdf”? What if I would like to open a doc or ppt file?

          • Sean Rodda

            I can also see the Open With pop up menu however clicking on the relevant app does nothing. It does seem that the pdf file is downloaded into temp as I do see the loading symbol before hand. I am using PG 3.1 iOS 7. Any help would be greatly appreciated.

  • Franzkappa

    Thanks for the plugin. But i have some issues: when i try to open the file the app crash with a bad_exc access. How can I resolve this? I use cordova 2.6, mountain lion and xcode 4.6

    • njtman

      This issue is due to the fact that this plugin is not arc compatible and there is a weird issue where the method cleanupTempFile is called twice. The second time it is called, it crashes because the resources were already released. I have updated the plugin to support phonegap 3.0 and arc, but it will also work with phonegap 2.x. Try using my plugin files that I updated.

      https://github.com/njtman/phonegap-plugins/tree/master/iOS/ExternalFileUtil/plugin/obj-c

      Your project must have ARC turned on for this to work.

      If arc isn’t enabled in your project and you can’t enable it, just wrap the logic in the cleanupTempFile method with an if statement using a flag value that will ensure the method only executes the code once.

      • Franzkappa

        Thanks for replying. I changed the plugin and have the arc turned on but i can’t build because of the following errors: autorelease is unavaible: not avaible in arc mode. The file that returns these errors is appDelegate.m.

        • njtman

          If you are using it with arc turned off, you cannot use my updated code. You would need to use Andrew Trice’s code, and wrap the logic inside the cleanupTempFile method as I mentioned. Maybe its best to set a breakpoint and step thru that method as it executes so you can see it for yourself.

          • Franzkappa

            Thanks very much, I finally got it work! I turned on ARC and clean all the errors hidden in phonegap files.
            I am curious if there’s a way to display the download percentage like in the phonegap API FileTransfer onprogress, that would be a good feature!
            If I’ll find an iPad with iOS7, I’ll let you know if the issue comes out to me too.

          • njtman

            I’m not sure if there is a way to do this or not, but I did update my code on the github page to show a native spinner while the file is being downloaded.

  • Cristian Cascante

    Hello!
    It works for me :D

    The problem was with temp file, that is deleted by the original code so you have to delete the code that deletes the temporal file. And it works loading a file stored on device. ;)

  • Cornelius Parkin

    Hello

    What is the command on PhoneGap 3.0.0 to install this plugin i.e.

    sudo phonegap local plugin add https://git-wip-us.apache.org/repos/asf/cordova-plugin-dialogs.git

    Thanks in advance…

  • walid taraf

    Dont think the gitHub repo shows it as 3.0+ compliant yet. It’s missing plugin.xml which is needed for the CLI interface. Anyone tried to run this with CLI yet? Thanks guys.

  • fmgasparino

    Excellent! Thanks Andrew!

  • Justin Wark

    FYI – I have updated this plugin to work with iOS7/cordova 3.3 and I have merged in a similar Android-only plugin, so that there is now one plugin with similar functionality over both iOS and Android: https://github.com/jwark/FileOpener/tree/cordova-3.0
    I hope this helps!

    • François

      Great! Exactly what I was looking for!

  • Michael Ellis

    Awesome job!

    I am having a problem though, it does not seem to work on files with spaces in their name. For example I can open “myfile.pdf” but not “myfile 1.pdf”.

    I am using Phonegap and the following code: theFile.toURI()

    Any suggestions ?

    • Michael Ellis

      I was kind of able to fix by using

      theFile.toURI().replace(/s/g,”%20″)

      Now other apps can open the file, but %20 is part of the filename.

    • Michael Ellis

      I believe I fixed it, pull request submitted on github.

  • Hicham Taoufikallah

    Hello,
    Did u post the code anywhere ?
    Thanks in advance !

  • scottdc

    Works great but I’m having an issue with the open with dialog position on iPad appearing at the bottom of my app when the iPad is horizontal and offscreen if in portrait. Any ideas?

  • Abo

    Can someone tell me how to install this plugin inside my project?
    I’am new in it,sorry…