jhass / insporation

Flutter based client for diaspora*
BSD 3-Clause "New" or "Revised" License
30 stars 3 forks source link

Implement share receiver for iOS #38

Closed jhass closed 3 years ago

jhass commented 3 years ago

34 Adds a stub to silence the errors, but we should follow up with a proper implementation that allows to share text, links and images to the app.

Android already has this implemented, so this is "just" the bridge interface missing for iOS.

tclaus commented 3 years ago

Does this work in Android? Sharing a image to insporation seems to start the app - but not a new Post?

jhass commented 3 years ago

It used to work at some point at least 😅

jhass commented 3 years ago

It seems to work with a warm start (app active in the background) but not with a cold start. But that's a separate bug to this anyways.

jhass commented 3 years ago

It seems to work with a warm start (app active in the background) but not with a cold start. But that's a separate bug to this anyways.

FWIW that should be fixed now https://github.com/jhass/insporation/commit/7b4eca094606d3ea76fd7752040d072a29627120 :)

tclaus commented 3 years ago

I did not get this to work. I followed the official App Extensions share guide on iOS - the I get a target App in the simulator, but a warning message after using it. I added the 'receive_sharing_intent' in the flutters pubscpec and followed its guide (along with adding a new App group capability which invalidates the provisioning profiles). On a device during sharing (from the images app) the App Icon won't appear.

One more problem seems too appear: the Share App Extension uses an own info.plist file with synced CFBundleVersion keys - this should the $(FLUTTER_BUILD_NUMBER) - but this will not parse during build. I ended up with hardcoded a "1" here, which builds on development machine, but surely not on a CI environment.

Resources I used: iOS Share Extension: https://developer.apple.com/library/archive/documentation/General/Conceptual/ExtensibilityPG/Share.html

Flutter's receive_sharing_intent https://pub.dev/packages/receive_sharing_intent

I pushed a share_handler branch: https://github.com/jhass/insporation/tree/share_handler

jhass commented 3 years ago

I don't quite remember why, but given I implemented a custom event channel and platform native code to pass it the share events, I guess the situation in the ecosystem wasn't much better on the Android side of things too, at least when I implemented this.

So given the trouble you got with the flutter package, and also to not have two ways to receive shares on the flutter side, how about looking into doing a custom platform native implementation for iOS too, reusing the Flutter side of things? The protocol is really simple, just push a small map to the event channel: https://github.com/jhass/insporation/blob/main/android/app/src/main/kotlin/jhass/eu/insporation/ShareEventStream.kt#L34-L53

I'm not familiar with how sharing works on iOS, but judging from https://medium.com/@dinesh.kachhot/different-ways-to-share-data-between-apps-de75a0a46d4a there's more than one pattern for sharing, and maybe share extensions is not the best fit for our usecase?

tclaus commented 3 years ago

On iOS it seems to work in this way: App needs an "AppExtension" of type "Share Extension" User can now use the System-Wide share - Action. A Dialog appears and user can enter Text and sees the image. (Dialog can be customized, but default is good enough)

Bildschirmfoto 2020-12-02 um 08 46 20

App Extension now 'collects' this text and Image, and starts the App itself. Before app is started, under iOS the Extension and App 'shares' Image and Text in a shared Setting. (which should be readable also in DART part)

The missing link: App starts in iOS, Shared Settings now holds text and image (media file), but it should be forwarded to the publisher.

So what we need is a way to open the publisher and 'send' data to it from iOS. All needed Data is now in the System-Setting ("UserDefaults"). I can also pack the Data in a structure so send it to the dart-part. (text and image - in a URL form, or in a serialized form)

Is there a Flutter-Method?

This is the iOS line with the missing link: https://github.com/jhass/insporation/blob/c66cde3e7dae7d21812f9476d2ed4a54f2ad0215/ios/Runner/AppDelegate.swift#L71

Need here a call to open publisher with a set of data, or publisher should read from 'UserDefaults', which contains the shared data.

jhass commented 3 years ago

This is what https://github.com/jhass/insporation/blob/c66cde3e7dae7d21812f9476d2ed4a54f2ad0215/ios/Runner/AppDelegate.swift#L62-L63 is for :)

It's listened to here: https://github.com/jhass/insporation/blob/eceba66793ec06822a5d4c3c708f4ce87de35ffb/lib/main.dart#L106

I linked the Android implementation of that bridge above.

tclaus commented 3 years ago

Hm - in AppDelegate is a consumer for this. (Called on start with null-values) Sure, that this would not start a loop and will call iOS again? I'll try this. But don't hold your breath..

tclaus commented 3 years ago

A real device needed a reboot. Some strange techniques are involved to implement this.