New Feature: Native content sharing support for iOS/Android

In commit 36da4cd (followed by 2 minor tweaks later) we added the ability to share content from your app with other apps on your iOS/Android device. On iOS this means that you can for instance share files with your Mac using AirDrop, send an email with files attached, share to DropBox etc. On Android this means that you can for instance send files to Google Drive, send an email, share to Hangouts etc. The number of supported targets depends on installed extensions/apps.

On both OSes you can send text, internal files your app creates (e.g. in a temporary directory), files embedded in your app bundle, images and arbitrary data. For Android, remember to enable Content Sharing in Projucer first:

Let us know if you encounter any issues with sharing, especially on Android where there is no one consistent way each sharing target behaves. JUCE Dialogs Demo has been updated to include the new sharing options.

3 Likes

Will give this a bash over the holidays.

1 Like

Hi @lukasz.h, there’s an issue with layout of the iMessage modal, this is easily reproduced from the DemoRunner app Dialogs demo by choosing Share Text -> iMessage:


I believe this stems from the modal being added to a new JuceUIWindow instead the existing key window and have submitted a patch which fixes it.

What device is this on? I can’t see any issues on an iPhone 6 running iOS 12.3.

Thanks for looking into this @ed95.

Screenshot is from a iPhone 6+ running iOS 12.2.

Sometimes the modal is indeed presented correctly but the layout breaks if you have to rotate the screen and often if the app orientation is different from the device orientation lock, e.g. launch the DemoRunner app with device locked in portrait.

Hi there. I have issues with sharing on iOS. I’m testing iOS 13.1.3 (iPad 5)

  1. First thing is related to layout. Popup fills almost entire screen and there is no cancel button. So there is literally no way to close it. The problem appears for DialogsDemo too.

  2. Is ContentSharer supposed to work for AUv3? The plugin’s UI is getting freezed every time I’m trying to open ContentSharer. Anyone aware of solution?
    Thanks

1 Like

+1 for both points. @ed95, can we please get this addressed?
I think it won’t be a stretch to say native ContentSharer is currently unusable on iOS. I’d also add that besides the obvious issue with the popover filling the entire screen, it doesn’t make sense (from the native UI standpoint) for the popover arrow to point somewhere other than the button that opened it.

I’ve done some work on this in my fork of JUCE.
The first commit fixes a crash due to deallocated memory access. To reproduce: open the sharer, tap ‘Save to Files’, tap ‘Cancel’, close the sharer, boom.
The second makes it workable within AUv3 by allowing to set the parent component (a-la FileChooser) before making a call to shareFiles(), shareText(), etc. and using it to present the UIActivityViewController.
Still need to fix the sharer width and implement a way to get proper popoverController.sourceRect through for arrow placement - not as easy…

2 Likes

Great, I will test it. I got complaints from customers that currently sharing is hard to use (or rather to cancel). I reported also in another thread that printing via ContentSharer is not possible (the sharer is blocked).

1 Like

I guess it’s hard to cancel first and foremost because it occupies the entire screen, so one has to really aim at the edges to dismiss it - I haven’t solved this yet

Yes, exactly! I wanted to look into it but had no time. IIRC in the previous versions of iOS there was at least this close button shown on the sharer but disappeared after some iOS update.

AFAIK, it’s always been that way, but on iPhones (as opposed to iPads) it does have a cancel button, as it’s displayed in a different way, actionsheet-style.

Maybe I’m wrong with iPads but I am sure it worked somehow better (maybe the sharer was not almost full screen?). I should have somewhere an older iPad, will check it tomorrow.

1 Like

Here’s more :smiley:
setParentComponent() can now take an extra component parameter that will be used to calculate the popover sourceRect. I also don’t force custom preferredContentSize, so overall it can now look like a proper iOS popover IMO. Also had to alter PopoverDelegateClass quite a bit to make it support correct repositioning on orientation changes.

Would love to see an official solution though! Can submit a pull request if necessary.

1 Like

I’d also like to point out that the whole singleton ContentSharer and JUCE modal state stuff is in itself an issue in AUv3 context. (Same goes for FileChooser, despite it’s not a singleton.) Perhaps not many users will see this, but if you open the sharer in one AUv3 instance, all others become totally unresponsive until it’s finished. I guess fixing this would take quite a bit of time and more significant API changes, so for us JUCE users it may as well be easier, if necessary, to roll our own wrappers and #if JUCE_IOS them.

Anyway, IMO that’s something for the JUCE team to consider.

1 Like

Good job again! In the meantime I found an iPad with iOS 13 and the sharer is already full screen here.

Turns out UIActivityViewController completionWithItemsHandler is more messed up than I thought.
Initial actions: open the sharer, tap ‘Save to Files’. Then it gets weird…

  • If I tap Cancel in the files dialog, the handler receives this:
    activityType = com.apple.CloudDocsUI.AddToiCloudDrive, completed = NO and, for some weird reason, this error: Error Domain=NSCocoaErrorDomain Code=3072 "The operation was cancelled."
    Then, if I hide the sharer itself, handler gets called again:
    activityType = (null), completed = NO, error = (null).
    (That’s the situation I’ve worked around, see my previous posts)

BUT

  • Imagine I don’t tap the Cancel button, but tap outside the files dialog. Must be the same thing conceptually, right? Guess what, it doesn’t call the handler at all. Then, when I hide the sharer:
    activityType = com.apple.CloudDocsUI.AddToiCloudDrive, completed = NO, error = (null)

I have no idea how to work around this, at least yet.

UPD: Making sure the presentingViewController is nil before exiting modal state seems to do the trick (at least for iOS 13).