FR: iOS custom file type open handler

@lukasz.k, @tpoole

Hi,

It would be great, if JUCE would include the ability to handle opening of custom file types from another app on iOS. Here’s a setup guide.

Attached is a slapped together patch that achieves that - kindly provided under the WTFPL.

iOS-custom-file-tyoe-handler.cpp (3.4 KB)

Thanks.

Hi, you can use the custom plist entry in Projucer for this.

e.g, the following allows prs extensions to be used:

image

Yes, I know. But if a user clicks a file in the iOS file browser (I don’t mean the JUCE native file chooser, but the separate app), there’s currently no way find get access to this file in JUCE (AFAIK).

This patch is useful if you get a file via e-mail and want to open it in your app via a simple click.

Just a status update, as you mentioned this thread from another conversation: Looking at this patch has gone into our backlog, but it’s not particularly high priority so no promises when we’ll get round to it.

2 Likes

I found this topic when I’m looking for a solution to open file from other apps on iOS.

I really like the suggested solution. Opening file sent from other apps is very fundamental thing on iOS, can you prioritize this?

Note that application:openURL has been deprecated so need to use application:openURL:options:.

https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1623112-application?language=objc

1 Like

bump! this is crucial for my IOS application that i’m building at the moment

1 Like

i just got this working locally (thanks @PixelPacker) and i wanted to share a few findings.

first, to get around the deprecated method warning that shows up you can change the openURL declaration from the patch to this:

- (BOOL) application:(UIApplication *)application openURL:(NSURL *)
       url options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options

second, because of how reading private files works in ios (and how this patch is implemented) this approach will not work:

 void urlOpened(const juce::URL &url) override {
  // get a File from the URL
  juce::File file = url.getLocalFile();
  // this will be false!
  file.existsAsFile(); 
  // this will fail too because the file is inaccessible 
  doSomething(file); 

but this will work:

 void urlOpened(const juce::URL &url) override {
  // create an InputStream
  auto input = url.createInputStream(juce::URL::InputStreamOptions(juce::URL::ParameterHandling::inAddress));
  // now read from the InputStream 
  auto data = input.readEntireStreamAsString(); 
  // this will be false
  data.isEmpty(); 
  // now you can do something with the data

hopefully this helps save someone else some time.

1 Like

It seems like this patch (or something implementing a similar solution) still hasn’t been applied. Is there any pointer on how to handle opening files from within iOS’ file browser?

the current version of the patch i’m using is here:

and then i have this code in StandaloneApp.cpp:

#if JucePlugin_Build_Standalone && JUCE_IOS

  void urlOpened(const juce::URL &url) override {
    // we have to read our url as an InputStream, otherwise
    // we won't have access to the underlying bookmark data.
    auto is = url.createInputStream(
        juce::URL::InputStreamOptions(juce::URL::ParameterHandling::inAddress));

    // so we read from the url and write to a temp file
    // with the same extension.
    auto tmp = juce::TemporaryFile(url.getLocalFile().getFileExtension());
    auto tmpFile = tmp.getFile();
    auto os = juce::FileOutputStream(tmpFile);
    os.writeFromInputStream(*is, -1);

    // call flush so the file is readable!
    os.flush();

    // and now we can do something with our tmpFile
    doSomething(tmpFile);
    // note that our tmpFile will be cleaned up by going out
    // of scope.
  }

#endif

i also had to setup CFBundleDocumentTypes and UTExportedTypeDeclarations for the new filetypes/extensions i was adding - the setup guide from the OP does a good job of explaining this iirc.

4 Likes

It’s amazing to me that this still hasn’t been added to JUCE. It’s pretty much essential if you want your standalone plugin to be able to interact with the iOS Files app.

1 Like

@modosc I’ve made a PR for this here, fwiw: Support for custom file formats in ios files app by dhilowitz · Pull Request #1036 · juce-framework/JUCE · GitHub

9 Likes

Great! Thanks a lot for sharing.

Since we are on the topic of iOS and files: there’s also no JUCE method to open audio files from the user’s music collection.

Has anybody here put something together to access the user’s music library?

That would also be very useful!

Thank you so much! It did save me a ton of time.

1 Like

Hey @modosc @dhilowitz @PixelPacker and @leehu
Many thanks to everyone for sharing this info. With a combination of the above I managed to get this working nicely at my end too. :slight_smile: So cool!

However, I’m a little puzzled as to why this hasn’t been rolled into JUCE proper. Is there somewhere I can vote towards getting the pull request rolled in?

2 Likes

Hey there

Hmm, I can’t seem to see any furtherance of this.

Looks like it’s not been merged in the 3 years hence. Is that because there’s an alternative that is more official than the example shown here?

It might be worthwhile to extend the FR to Android for a more balanced, cross-platform solution.

This could involve a couple parts:

  1. The AndroidManifest.xml would need to have intent-filters:
    • See https://stackoverflow.com/a/55976817 for how that part could be done.
    • An approach to this could be extending the Projucer to allow populating intent-filters via some CSV or whatever textbox option in the Android exporter.
    • I would say Cmake might need some TLC in this regard but I don’t think JUCE officially supports Android/Cmake right now… (correct me if I’m wrong!)
  2. The app would then need to have a JNI interface to accept the related intents, and would then need pipe those events into the app similar to how that was done in the PR for iOS.

This is starting to resemble deep-linking in spirit, so the following links might offer helpful context:

  1. Create Deep Links to App Content  |  App architecture  |  Android Developers
  2. Allowing apps and websites to link to your content | Apple Developer Documentation
2 Likes

I agree in that there’s definitely a strong argument to have a cross-platform solution for this.

In the right here right now, how are iOS devs are handling this urlOpened situation? I’m repeatedly re-applying a patch to whatever JUCE commit I’m using via a git stash. This seems super hacky and naive. Surely there’s a better approach, right?

To avoid that I keep my own JUCE fork. I apply patches and changes to my fork and these changes persist even after syncing my fork with the current develop tip, which I do regularly. Very rarely there can be a conflict when syncing (an update to the JUCE codebase which directly overwrites one of my changes) which I need to resolve manually, but that’s it.

1 Like