fluttercommunity / plus_plugins

Flutter Community Plus Plugins
BSD 3-Clause "New" or "Revised" License
1.55k stars 924 forks source link

share_plus - Give back result of user action #386

Closed kristijorgji closed 2 years ago

kristijorgji commented 3 years ago

I will propose below a feature for the plugin https://pub.dev/packages/share_plus

Request is: Give back some enum of user action after share screen is shown. Currently we have this signature, which returns void

  static Future<void> share(
    String text, {
    String? subject,
    Rect? sharePositionOrigin,
  })

In many use cases as I will describe in the other section, will be very useful to know what user did in the share screen.

Use case

  1. Tracking. We need to know if user shared the text/file/etc =, or just closed the dialog(view) without doing nothing. This enabled a lot of opportunities, like A/B testing, trying to improve ui (explanation text) for what user is about to share and so on.
  2. Follow up logic. Based on whether user shared or not, app might want to follow up with different code paths. Example: thank you for sharing, you received 10 super app points.

Proposal

The functions will return instead of Future Future

  static Future<Result> share(
    String text, {
    String? subject,
    Rect? sharePositionOrigin,
  })

//where Result can be something like

enum ShareResult {
  shared,
  closed,
  // maybe something else here no idea currently i see big need for binary did share or not  
}
mhadaily commented 3 years ago

While this is great idea and I do agree we should enhance this, this might not be as easy as it looks.

I suggest, you take the lead on this suggestion and send US a PR so then we can discuss on your PR what can be establish as a public api and how to move feather.

Thanks for the proposal btw, this looks very promising.

Chinmay-KB commented 3 years ago

@kristijorgji I think IntentSender can be used for this on the android side.

alexrainman commented 3 years ago

In iOS, it can be done like this:

activityViewController.CompletionWithItemsHandler = (activityType, completed, returnedItems, error) => {
    if (completed)
    {
        // do something with the result
    }
};
alexrainman commented 3 years ago

In Android, implement PluginRegistry.ActivityResultListener in MethodCallHandler.java:

Then override onActivityResult:

override fun onActivityResult(code: Int, resultCode: Int, data: Intent?): Boolean {
    if (resultCode == Activity.RESULT_OK) {
        // do something with the result
    }
}

I guess this line https://github.com/fluttercommunity/plus_plugins/blob/6b464ca687ec9d38e435bc6c04fddf391a04a6d7/packages/share_plus/share_plus/android/src/main/java/dev/fluttercommunity/plus/share/Share.java#L63 need to be changed to startActivityForResult

mustafa-707 commented 3 years ago

here is needed

champ96k commented 2 years ago

@mhadaily can you please assign me this issue I would love to take it.

Thanks

The-Redhat commented 2 years ago

Hey @champ96k are you currently working on this? If not can somebody maybe share her/his thoughts about how this should be integrated with the current methods.

One solution would be to add a parameter to the share method: waitForCompletion and return the results to make it a non-breaking change.

alexrainman commented 2 years ago

Any news on this?

tobatha commented 2 years ago

I thought it was just me but seems like everyone is yearning for the success/fail/cancel callback support, that's reassuring! LOL

alexrainman commented 2 years ago

How i am going to increase a share count without knowing if the user actually share or hit cancel?

appinteractive commented 2 years ago

Plus one on that! Any plans for that one??

joaovirgilicw commented 2 years ago

any update of this?

andynvt commented 2 years ago

any updates?

mhadaily commented 2 years ago

@champ96k or @elias8 did you make any progress don't his issue?

appinteractive commented 2 years ago

@mhadaily any update on that? Who can we point to? @alexrainman @champ96k, @miquelbeltran, @Coronon, @jpnurmi, anyone for a PR???

Is there still hope? 🥺

giphy

Coronon commented 2 years ago

I could have a look into this - no guarantees though. As it looks this should be fairly simple for IOS, Android will be a little bit more tricky...

We probably want to avoid breaking the current API, so maybe we can use an extra method and let the old one simply filter out the result.

Ill have a look!

Edit: I will only look at IOS and Android for now

Coronon commented 2 years ago

Update

This feature can only be implemented from Android API level 21+, we are currently supporting level 16+... The only way around this would be to completly re-implement all sharing logic (the share sheet -> what android does atm -> not really a good idea) :(

So there are two options:

1: Drop support for API version 16 (2012) and move to API version 21 (2014) 2: Leave this feature alone

Why?

Some apps may return something, but they are not forced to... So we can't distinguish between success and cancelation :/

To avoid this we need public static Intent createChooser(Intent, CharSequence, IntentSender) which comes in API version 21 - addid benefit: we would know what app was launched

efraimbart commented 2 years ago

@Coronon Is there a branch this attempt was worked on in?

Coronon commented 2 years ago

@Coronon Is there a branch this work was done in?

I have forked the repo and am testing out my implementation locally, just looked for a solution for ~3hours until I now know that we need public static Intent createChooser(Intent, CharSequence, IntentSender)

IOS seems to be pretty straight foreword though xD

efraimbart commented 2 years ago

Would you mind pushing the branch so I can have a look? Curious to see what it entails...

Coronon commented 2 years ago

There are basically ~10 more lines atm but sure ^^ Here you go: https://github.com/Coronon/plus_plugins/tree/playground/packages/share_plus/share_plus/android/src/main/kotlin/dev/fluttercommunity/plus/share

I did not wire up anything though, as said - just playing around trying to get a result

efraimbart commented 2 years ago

Thanks!

Coronon commented 2 years ago

I will try implementing this with API version 21 now!

efraimbart commented 2 years ago

Using your code I got it to work with android_intent_plus (see https://github.com/fluttercommunity/plus_plugins/issues/344). Perhaps consider creating a pull request for that as well.

efraimbart commented 2 years ago

And perhaps instead of replacing the current method, add another one for the result, and that way the api version doesn't have to be updated

Coronon commented 2 years ago

Im very close to a working implementation that can figure out if you actually called another app or dismissed the share sheet. The problem is mainly that we need to use two different "async" ways of being informed about success and dismissal -> BroadcastReceiver and onActivityResult. I am currently building a manager class that will handle these. I will then have to implement the dart bindings.

Coronon commented 2 years ago

And perhaps instead of replacing the current method, add another one for the result, and that way the api version doesn't have to be updated

That was the plan ;)

Coronon commented 2 years ago

UPDATE: The android side is now implemented, you can have a look here

The await will already work if the method names are suffixed with "withResult" -> awaiting the new methods will wait for a result and return it :)

Coronon commented 2 years ago

UPDATE: Dart bindings are now available, while it states that they are available for both 'IOS' and 'Android', only 'Android' is supported atm. Link

I will work on IOS tomorrow (German time)

Coronon commented 2 years ago

Ok, so the IOS side basically works now, the only problem is that we get more information on IOS than on Android: On Android we only know if the user selected an option on the share-sheet, but not if he actually went through with it. On IOS we get both what he selected and if he actually completed the option.

The question is how consistent we should be: Should we count a started action but then dismissed one on IOS as a success, or rather always return the best information we have -> For this case dismissed on IOS but success on Android?

Personally, I prefer the "best we got" approach.

Coronon commented 2 years ago

Update: This feature is now fully implemented for IOS and Android

It even handles if the share-sheet is closed for an action (like create IOS photo album) and then reappears after canceling that action :P (At least on IOS, as Android does not provide a way to find out to the best of my knowledge)

You can have a look on my fork. The pull request is #765

If you have any comments, I would love to hear from you. This has been my first time writing Kotlin, Objective C and Swift, so any feedback is greatly appreciated ;)

Coronon commented 2 years ago

Just added tests, should be pretty much ready to merge if the maintainers agree with the changes 🥳

fullflash commented 2 years ago

waiting such a must feature for a "plus" plugin )

miquelbeltran commented 2 years ago

Hey, maintainer here. I would like to ask the people in the thread to try to give it a go to the PR and reply with their experiences. It is a big change and needs to be well tested, and as well try to test it on Desktop and Web just to verify that nothing is broken.

andynvt commented 2 years ago

Update: This feature is now fully implemented for IOS and Android

It even handles if the share-sheet is closed for an action (like create IOS photo album) and then reappears after canceling that action :P (At least on IOS, as Android does not provide a way to find out to the best of my knowledge)

You can have a look on my fork. The pull request is #765

If you have any comments, I would love to hear from you. This has been my first time writing Kotlin and Objective C, so any feedback is greatly appreciated ;)

How can I use your fork in pubspec.yaml file? Currently, I use:

share_plus:
    git:
      url: https://github.com/Coronon/plus_plugins.git
      path: packages/share_plus/share_plus/

But I got this error

Launching lib[/main.dart]() on iPhone 12 in debug mode...
lib/main.dart:1
Xcode build done.                                           31.7s
Failed to build iOS app
Error output from Xcode build:
↳
    ** BUILD FAILED **
Xcode's output:
↳
    Writing result bundle at path:
        [/var/folders/q5/qm7y6dqn3mjfj7g3zrwgwcz00000gn/T/flutter_tools.RQ906a/flutter_ios_build_temp_dirnWUgks/temporary_xcresult_bundle]()
[/Users/andy/.pub-cache/hosted/pub.dartlang.org/flutter_inappwebview-5.3.2/ios/Classes/InAppBrowser/InAppBrowserWebViewController.swift:557:13](): warning: setter for 'statusBarStyle' was deprecated in iOS 9.0: Use -[UIViewController preferredStatusBarStyle]
                UIApplication.shared.statusBarStyle = UIStatusBarStyle(rawValue: previousStatusBarStyle)!
                ^
[/Users/andy/.pub-cache/hosted/pub.dartlang.org/flutter_inappwebview-5.3.2/ios/Classes/InAppWebView/InAppWebView.swift:517:31](): warning: 'mediaPlaybackRequiresUserAction' was deprecated in iOS 9.0
                    configuration.mediaPlaybackRequiresUserAction = options.mediaPlaybackRequiresUserGesture
                                  ^
[/Users/andy/.pub-cache/hosted/pub.dartlang.org/flutter_inappwebview-5.3.2/ios/Classes/InAppWebView/InAppWebView.swift:928:31](): warning: 'mediaPlaybackRequiresUserAction' was deprecated in iOS 9.0
                    configuration.mediaPlaybackRequiresUserAction = newOptions.mediaPlaybackRequiresUserGesture
                                  ^
[/Users/andy/.pub-cache/hosted/pub.dartlang.org/flutter_inappwebview-5.3.2/ios/Classes/InAppWebView/InAppWebViewOptions.swift:102:81](): warning: 'mediaPlaybackRequiresUserAction' was deprecated in iOS 9.0
                    realOptions["mediaPlaybackRequiresUserGesture"] = configuration.mediaPlaybackRequiresUserAction
                                                                                    ^
[/Users/andy/.pub-cache/hosted/pub.dartlang.org/flutter_inappwebview-5.3.2/ios/Classes/InAppBrowser/InAppBrowserWebViewController.swift:557:13](): warning: setter for 'statusBarStyle' was deprecated in iOS 9.0: Use -[UIViewController preferredStatusBarStyle]
                UIApplication.shared.statusBarStyle = UIStatusBarStyle(rawValue: previousStatusBarStyle)!
                ^
[/Users/andy/.pub-cache/hosted/pub.dartlang.org/flutter_inappwebview-5.3.2/ios/Classes/InAppWebView/InAppWebView.swift:517:31](): warning: 'mediaPlaybackRequiresUserAction' was deprecated in iOS 9.0
                    configuration.mediaPlaybackRequiresUserAction = options.mediaPlaybackRequiresUserGesture
                                  ^
[/Users/andy/.pub-cache/hosted/pub.dartlang.org/flutter_inappwebview-5.3.2/ios/Classes/InAppWebView/InAppWebView.swift:928:31](): warning: 'mediaPlaybackRequiresUserAction' was deprecated in iOS 9.0
                    configuration.mediaPlaybackRequiresUserAction = newOptions.mediaPlaybackRequiresUserGesture
                                  ^
[/Users/andy/.pub-cache/hosted/pub.dartlang.org/flutter_inappwebview-5.3.2/ios/Classes/InAppWebView/InAppWebViewOptions.swift:102:81](): warning: 'mediaPlaybackRequiresUserAction' was deprecated in iOS 9.0
[Users/andy/.pub-cache/hosted/pub.dartlang.org/flutter_inappwebview-5.3.2/ios/Storyboards/WebView.storyboard]():global: warning: This file is set to build for a version older than the deployment target. Functionality may be limited. [9]
: Error: Type 'ShareResult' not found.
../…/lib/share_plus.dart:96
      static Future<ShareResult> shareWithResult(
                    ^^^^^^^^^^^
: Error: Type 'ShareResult' not found.
../…/lib/share_plus.dart:120
      static Future<ShareResult> shareFilesWithResult(
                    ^^^^^^^^^^^
: Error: The method 'shareWithResult' isn't defined for the class 'SharePlatform'.
../…/lib/share_plus.dart:102
- 'SharePlatform' is from 'package:share_plus_platform_interface[/share_plus_platform_interface.dart]()' ('.[./../../.pub-cache/hosted/pub.dartlang.org/share_plus_platform_interface-2.0.1/lib/share_plus_platform_interface.dart]()').
package:share_plus_platform_interface[/share_plus_platform_interface.dart]():1
    Try correcting the name to the name of an existing method, or defining a method named 'shareWithResult'.
        return _platform.shareWithResult(
                         ^^^^^^^^^^^^^^^
: Error: The method 'shareFilesWithResult' isn't defined for the class 'SharePlatform'.
../…/lib/share_plus.dart:129
- 'SharePlatform' is from 'package:share_plus_platform_interface/share_plus_platform_interface.dart' ('.[./../../.pub-cache/hosted/pub.dartlang.org/share_plus_platform_interface-2.0.1/lib/share_plus_platform_interface.dart]()').
package:share_plus_platform_interface/share_plus_platform_interface.dart:1
    Try correcting the name to the name of an existing method, or defining a method named 'shareFilesWithResult'.
        return _platform.shareFilesWithResult(
                         ^^^^^^^^^^^^^^^^^^^^
    Failed to package [/Users/andy/Desktop/QK/....]()
    Command PhaseScriptExecution failed with a nonzero exit code
    note: Using new build system
    note: Building targets in parallel
    note: Planning build
    note: Constructing build description
    warning: The iOS Simulator deployment target 'IPHONEOS_DEPLOYMENT_TARGET' is set to 8.0, but the range of supported deployment target versions is 9.0 to 14.4.99. (in target 'OrderedSet' from project 'Pods')
    warning: The iOS Simulator deployment target 'IPHONEOS_DEPLOYMENT_TARGET' is set to 8.0, but the range of supported deployment target versions is 9.0 to 14.4.99. (in target 'FMDB' from project 'Pods')
    Result bundle written to path:
        [/var/folders/q5/qm7y6dqn3mjfj7g3zrwgwcz00000gn/T/flutter_tools.RQ906a/flutter_ios_build_temp_dirnWUgks/temporary_xcresult_bundle]()
Could not build the application for the simulator.
Error launching application on iPhone 12.
Exited (sigterm)
leidig54 commented 2 years ago

Update: This feature is now fully implemented for IOS and Android

It even handles if the share-sheet is closed for an action (like create IOS photo album) and then reappears after But I got this error

also getting this issue. tried clearing/deleting/updating the pub cache but to no avail.

I don't know much about package development, but is the share_plus plugin referencing the original share_plus_platform_interface instead of the fork somehow?

miquelbeltran commented 2 years ago

is the share_plus plugin referencing the original share_plus_platform_interface instead of the fork somehow?

Yes, that's going to be an issue.

I think it may work this way:

Coronon commented 2 years ago

@miquelbeltran is right. My share_plus forks version requires my share_plus_interface forks version, which when you only include share_plus in your pubspec.yml will fetch the one from pub -> error!

@leidig54 - thats pretty much exactly the issue :P You might also manually change the pubspec.yml in each share_plus subpackage to something with path: (you will also need to add publish_to: none) if you dont want to use melos.

Coronon commented 2 years ago

Just added macOS support too

andynvt commented 2 years ago

@miquelbeltran is right. My share_plus forks version requires my share_plus_interface forks version, which when you only include share_plus in your pubspec.yml will fetch the one from pub -> error!

@leidig54 - thats pretty much exactly the issue :P You might also manually change the pubspec.yml in each share_plus subpackage to something with path: (you will also need to add publish_to: none) if you dont want to use melos.

Could you make a repo as a pubspec.yml useable before merging the PR? I'd like to use it in my project. Thank you

Coronon commented 2 years ago

is the share_plus plugin referencing the original share_plus_platform_interface instead of the fork somehow?

Yes, that's going to be an issue.

I think it may work this way:

  • Clone @Coronon repo in a folder
  • Run the melos bootstrap in the root, this setups the repository to use local dependencies and not pub.dev, see intrucctions to instlal melos in repo
  • Use the plugin as a path reference, not as a git reference

@andynvt You can just follow these instructions to get it to work :)

appinteractive commented 2 years ago

WOW @Coronon! Thanks a million 💯 times for your implementation 🤩

Sadly, I'm also not able to get the fork working with my app. Did the melos bootstrap inside your fork and added it to my pubspec.yaml like that:

share_plus: 
    path: ../share_plus_fork/packages/share_plus/share_plus

But I get the same issue as @andynvt. Also tried to add share_plus_platform_interface in dependencies and in dependency_overrides but with no luck.

Any suggestions how to get it working to test that?

Coronon commented 2 years ago

WOW @Coronon! Thanks a million 💯 times for your implementation 🤩

Sadly, I'm also not able to get the fork working with my app. Did the melos bootstrap inside your fork and added it to my pubspec.yaml like that:

share_plus: 
    path: ../share_plus_fork/packages/share_plus/share_plus

But I get the same issue as @andynvt. Also tried to add share_plus_platform_interface in dependencies and in dependency_overrides but with no luck.

Any suggestions how to get it working to test that?

Thanks for raising the issue, I will try to put together a test project (to show how to integrate my changes) tomorrow (CET) 👍🏻

Coronon commented 2 years ago

Here you go everyone, a flutter project that you should be able to run without any modifications: share_plus_result_example

appinteractive commented 2 years ago

@Coronon on iOS it does work like expected, but I get following messages, I guess they are debug messages by you?

[LayoutConstraints] Changing the translatesAutoresizingMaskIntoConstraints property of a UICollectionReusableView that is managed by a UICollectionView is not supported, and will result in incorrect self-sizing. View: <_UIActivityContentFooterView: 0x1060d2480; baseClass = UICollectionReusableView; frame = (16 638.333; 343 52); layer = <CALayer: 0x280e9cd00>>
[Process] 0x105969018 - [pageProxyID=448, webPageID=449, PID=49127] WebPageProxy::didFailProvisionalLoadForFrame: frameID=6, domain=WebKitErrorDomain, code=102
[assertion] Error acquiring assertion: <Error Domain=RBSServiceErrorDomain Code=1 "target is not running or doesn't have entitlement com.apple.runningboard.assertions.webkit" UserInfo={NSLocalizedFailureReason=target is not running or doesn't have entitlement com.apple.runningboard.assertions.webkit}>
[ProcessSuspension] 0x1158f9aa0 - ProcessAssertion: Failed to acquire RBS assertion 'ConnectionTerminationWatchdog' for process with PID=49127, error: Error Domain=RBSServiceErrorDomain Code=1 "target is not running or doesn't have entitlement com.apple.runningboard.assertions.webkit" UserInfo={NSLocalizedFailureReason=target is not running or doesn't have entitlement com.apple.runningboard.assertions.webkit}
[assertion] Error acquiring assertion: <Error Domain=RBSAssertionErrorDomain Code=2 "Specified target process does not exist" UserInfo={NSLocalizedFailureReason=Specified target process does not exist}>
[ProcessSuspension] 0x1158f9b00 - ProcessAssertion: Failed to acquire RBS assertion 'WebProcess Background Assertion' for process with PID=49127, error: Error Domain=RBSAssertionErrorDomain Code=2 "Specified target process does not exist" UserInfo={NSLocalizedFailureReason=Specified target process does not exist}
[assertion] Error acquiring assertion: <Error Domain=RBSAssertionErrorDomain Code=2 "Specified target process does not exist" UserInfo={NSLocalizedFailureReason=Specified target process does not exist}>
[ProcessSuspension] 0x1158f9b60 - ProcessAssertion: Failed to acquire RBS assertion 'WebProcess Suspended Assertion' for process with PID=49127, error: Error Domain=RBSAssertionErrorDomain Code=2 "Specified target process does not exist" UserInfo={NSLocalizedFailureReason=Specified target process does not exist}

On Android I had to add implementation 'androidx.work:work-runtime-ktx:2.7.1' to the dependencies section in build.gradle but I still dont get the dialog in the simulator:

D[/EGL_emulation]()( 7817): app_time_stats: avg=180.38ms min=13.32ms max=4607.33ms count=28
E[/flutter]() ( 7817): [ERROR:flutter[/lib/ui/ui_dart_state.cc]()(209)] Unhandled Exception: PlatformException(prior share-sheet did not call back, did you await it? Maybe use non-result variant, null, null, null)
E[/flutter]() ( 7817): #0      StandardMethodCodec.decodeEnvelope
package:flutter/…/services/message_codecs.dart:607
E[/flutter]() ( 7817): #1      MethodChannel._invokeMethod
package:flutter/…/services/platform_channel.dart:177
E[/flutter]() ( 7817): <asynchronous suspension>
E[/flutter]() ( 7817): #2      MethodChannelShare.shareWithResult
package:share_plus_platform_interface/method_channel/method_channel_share.dart:95
E[/flutter]() ( 7817): <asynchronous suspension>
E[/flutter]() ( 7817): #3      _HomePageState.build.<anonymous closure>
package:example/main.dart:54
E[/flutter]() ( 7817): <asynchronous suspension>
E[/flutter]() ( 7817):
appinteractive commented 2 years ago

for Reference, I use Flutter 2.10

Coronon commented 2 years ago

@Coronon on iOS it does work like expected, but I get following messages, I guess they are debug messages by you?


[LayoutConstraints] Changing the translatesAutoresizingMaskIntoConstraints property of a UICollectionReusableView that is managed by a UICollectionView is not supported, and will result in incorrect self-sizing. View: <_UIActivityContentFooterView: 0x1060d2480; baseClass = UICollectionReusableView; frame = (16 638.333; 343 52); layer = <CALayer: 0x280e9cd00>>

[Process] 0x105969018 - [pageProxyID=448, webPageID=449, PID=49127] WebPageProxy::didFailProvisionalLoadForFrame: frameID=6, domain=WebKitErrorDomain, code=102

[assertion] Error acquiring assertion: <Error Domain=RBSServiceErrorDomain Code=1 "target is not running or doesn't have entitlement com.apple.runningboard.assertions.webkit" UserInfo={NSLocalizedFailureReason=target is not running or doesn't have entitlement com.apple.runningboard.assertions.webkit}>

[ProcessSuspension] 0x1158f9aa0 - ProcessAssertion: Failed to acquire RBS assertion 'ConnectionTerminationWatchdog' for process with PID=49127, error: Error Domain=RBSServiceErrorDomain Code=1 "target is not running or doesn't have entitlement com.apple.runningboard.assertions.webkit" UserInfo={NSLocalizedFailureReason=target is not running or doesn't have entitlement com.apple.runningboard.assertions.webkit}

[assertion] Error acquiring assertion: <Error Domain=RBSAssertionErrorDomain Code=2 "Specified target process does not exist" UserInfo={NSLocalizedFailureReason=Specified target process does not exist}>

[ProcessSuspension] 0x1158f9b00 - ProcessAssertion: Failed to acquire RBS assertion 'WebProcess Background Assertion' for process with PID=49127, error: Error Domain=RBSAssertionErrorDomain Code=2 "Specified target process does not exist" UserInfo={NSLocalizedFailureReason=Specified target process does not exist}

[assertion] Error acquiring assertion: <Error Domain=RBSAssertionErrorDomain Code=2 "Specified target process does not exist" UserInfo={NSLocalizedFailureReason=Specified target process does not exist}>

[ProcessSuspension] 0x1158f9b60 - ProcessAssertion: Failed to acquire RBS assertion 'WebProcess Suspended Assertion' for process with PID=49127, error: Error Domain=RBSAssertionErrorDomain Code=2 "Specified target process does not exist" UserInfo={NSLocalizedFailureReason=Specified target process does not exist}

On Android I had to add implementation 'androidx.work:work-runtime-ktx:2.7.1' to the dependencies section in build.gradle but I still dont get the dialog in the simulator:


D[/EGL_emulation]()( 7817): app_time_stats: avg=180.38ms min=13.32ms max=4607.33ms count=28

E[/flutter]() ( 7817): [ERROR:flutter[/lib/ui/ui_dart_state.cc]()(209)] Unhandled Exception: PlatformException(prior share-sheet did not call back, did you await it? Maybe use non-result variant, null, null, null)

E[/flutter]() ( 7817): #0      StandardMethodCodec.decodeEnvelope

package:flutter/…/services/message_codecs.dart:607

E[/flutter]() ( 7817): #1      MethodChannel._invokeMethod

package:flutter/…/services/platform_channel.dart:177

E[/flutter]() ( 7817): <asynchronous suspension>

E[/flutter]() ( 7817): #2      MethodChannelShare.shareWithResult

package:share_plus_platform_interface/method_channel/method_channel_share.dart:95

E[/flutter]() ( 7817): <asynchronous suspension>

E[/flutter]() ( 7817): #3      _HomePageState.build.<anonymous closure>

package:example/main.dart:54

E[/flutter]() ( 7817): <asynchronous suspension>

E[/flutter]() ( 7817):

Nope, thats not debug but rather outputs from the share_plus ios implementation mistreating some components that it uses (which seem to be mostly deprecated since IOS 9). That was there before, that will stay there until a full rewrite probably.

For Android: That is funny, I am running a simulator with API Version 30 and don't get any messages... The message you get can only be produced if you use ?WithResult without awaiting it, so if you did that then AtomicBool in the Java std is broken? This seems totally weird to me... Did you make any modifications to my code? What is the error if you dont add that androidx line?

Flutter version I tested with: 2.10.3 - but that should not be a constraint...

appinteractive commented 2 years ago

For Android: That is funny, I am running a simulator with API Version 30 and don't get any messages... The message you get can only be produced if you use ?WithResult without awaiting it, so if you did that then AtomicBool in the Java std is broken? This seems totally weird to me... Did you make any modifications to my code? What is the error if you dont add that androidx line?

When tapping the button I get:

E[/flutter]() ( 2369): Strongly consider using FLAG_IMMUTABLE, only use FLAG_MUTABLE if some functionality depends on the PendingIntent being mutable, e.g. if it needs to be used with inline replies or bubbles., null, java.lang.IllegalArgumentException: com.example.example: Targeting S+ (version 31 and above) requires that one of FLAG_IMMUTABLE or FLAG_MUTABLE be specified when creating a PendingIntent.
E[/flutter]() ( 2369): Strongly consider using FLAG_IMMUTABLE, only use FLAG_MUTABLE if some functionality depends on the PendingIntent being mutable, e.g. if it needs to be used with inline replies or bubbles.
E[/flutter]() ( 2369):  at android.app.PendingIntent.checkFlags(PendingIntent.java:375)
E[/flutter]() ( 2369):  at android.app.PendingIntent.getBroadcastAsUser(PendingIntent.java:645)
E[/flutter]() ( 2369):  at android.app.PendingIntent.getBroadcast(PendingIntent.java:632)
E[/flutter]() ( 2369):  at dev.fluttercommunity.plus.share.Share.share(Share.kt:57)
E[/flutter]() ( 2369):  at dev.fluttercommunity.plus.share.MethodCallHandler.onMethodCall(MethodCallHandler.kt:44)
E[/flutter]() ( 2369):  at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler.onMessage(MethodChannel.java:262)
E[/flutter]() ( 2369):  at io.flutter.embedding.engine.dart.DartMessenger.invokeHandler(DartMessenger.java:296)
E[/flutter]() ( 2369):  at io.flutter.embedding.engine.dart.DartMessenger.lambda$dispatchMessageToQueue$0$DartMessenger(DartMessenger.java:320)
E[/flutter]() ( 2369):  at io.flutter.embedding.engine.dart.-$$Lambda$DartMessenger$TsixYUB5E6FpKhMtCSQVHKE89gQ.run(Unknown Source:12)
E[/flutter]() ( 2369):  at android.os.Handler.handleCallback(Handler.java:938)
E[/flutter]() ( 2369):  at android.os.Handler.dispatchMessage(Handler.java:99)
E[/flutter]() ( 2369):  at android.os.Looper.loopOnce(Looper.java:201)
E[/flutter]() ( 2369):  at android.os.Looper.loop(Looper.java:288)
E[/flutter]() ( 2369):  at android.app.ActivityThread.main(ActivityThread.java:7839)
E[/flutter]() ( 2369):  at java.lang.reflect.Method.invoke(Native Method)
E[/flutter]() ( 2369):  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
E[/flutter]() ( 2369):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)
E[/flutter]() ( 2369): )
E[/flutter]() ( 2369): #0      StandardMethodCodec.decodeEnvelope
package:flutter/…/services/message_codecs.dart:607
E[/flutter]() ( 2369): #1      MethodChannel._invokeMethod
package:flutter/…/services/platform_channel.dart:177
E[/flutter]() ( 2369): <asynchronous suspension>
E[/flutter]() ( 2369): #2      MethodChannelShare.shareWithResult
package:share_plus_platform_interface/method_channel/method_channel_share.dart:95
E[/flutter]() ( 2369): <asynchronous suspension>
E[/flutter]() ( 2369): #3      _HomePageState.build.<anonymous closure>
package:example/main.dart:54
E[/flutter]() ( 2369): <asynchronous suspension>
E[/flutter]() ( 2369):

Then I found: https://stackoverflow.com/questions/69783824/targeting-s-version-31-and-above-requires-that-one-of-flag-immutable-or-flag

I`m also using SDK 31 in the Sim

Coronon commented 2 years ago

You are totally right, that was added in 31 and I did not catch that! Thank you! Will boot up my PC now and fix it very quickly - thanks for uncovering this! 👍🏻

While this was available before, 31 made setting a specific flag mandatory

appinteractive commented 2 years ago

@Coronon and yes I did alter the code a bit to better test my use case of sharing a link but I`m also using async/await:

                onPressed: () async {
                  final result = await Share.shareWithResult(
                    'https://github.com',
                  );
                  setState(() {
                    status = result.status.name;
                    raw = result.raw;
                  });
                },

And using a Stateful widget to display the result directly to not bother the chaotic console outputs