Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions docs/share_plus/usage.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,21 @@ To share one or multiple files invoke the static `shareFiles` method anywhere in
Share.shareFiles(['${directory.path}/image.jpg'], text: 'Great picture');
Share.shareFiles(['${directory.path}/image1.jpg', '${directory.path}/image2.jpg']);
```

If you are interested in the action your user performed with the share sheet, you can instead use the `shareWithResult` and `shareFilesWithResult` methods.

```dart
final result = await Share.shareWithResult('check out my website https://example.com');

if (result.status != ShareResultStatus.success) {
print('thank you for sharing my website!');
}
```

```dart
final result = await Share.shareFilesWithResult(['${directory.path}/image.jpg'], text: 'Great picture');

if (result.status == ShareResultStatus.dismissed) {
print('did you not like the picture?');
}
```
6 changes: 6 additions & 0 deletions packages/share_plus/share_plus/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## 4.0.3

- Android: Revert increased minSdkVersion back to 16
- Gracefully fall back from `shareWithResult` to regular `share` methods on unsupported platforms
- Improve documentation for `shareWithResult` methods

## 4.0.2

- Fix type mismatch on Android for some users
Expand Down
2 changes: 1 addition & 1 deletion packages/share_plus/share_plus/android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ android {
compileSdkVersion 31

defaultConfig {
minSdkVersion 22
minSdkVersion 16
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
lintOptions {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package dev.fluttercommunity.plus.share

import android.os.Build
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import java.io.IOException
Expand All @@ -11,48 +12,34 @@ internal class MethodCallHandler(
) : MethodChannel.MethodCallHandler {

override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
// The user used a *WithResult method
val isResultRequested = call.method.endsWith("WithResult")
// We don't attempt to return a result if the current API version doesn't support it
val isWithResult = isResultRequested && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1

when (call.method) {
"share" -> {
"share", "shareWithResult" -> {
expectMapArguments(call)
if (isWithResult && !manager.setCallback(result)) return

// Android does not support showing the share sheet at a particular point on screen.
share.share(
call.argument<Any>("text") as String,
call.argument<Any>("subject") as String?,
false,
isWithResult,
)
result.success(null)
}
"shareFiles" -> {
expectMapArguments(call)

// Android does not support showing the share sheet at a particular point on screen.
try {
share.shareFiles(
call.argument<List<String>>("paths")!!,
call.argument<List<String>?>("mimeTypes"),
call.argument<String?>("text"),
call.argument<String?>("subject"),
false,
)
result.success(null)
} catch (e: IOException) {
result.error("Share failed", e.message, null)
if (!isWithResult) {
if (isResultRequested) {
result.success("dev.fluttercommunity.plus/share/unavailable")
} else {
result.success(null)
}
}
}
"shareWithResult" -> {
"shareFiles", "shareFilesWithResult" -> {
expectMapArguments(call)
if (!manager.setCallback(result)) return

// Android does not support showing the share sheet at a particular point on screen.
share.share(
call.argument<Any>("text") as String,
call.argument<Any>("subject") as String?,
true,
)
}
"shareFilesWithResult" -> {
expectMapArguments(call)
if (!manager.setCallback(result)) return
if (isWithResult && !manager.setCallback(result)) return

// Android does not support showing the share sheet at a particular point on screen.
try {
Expand All @@ -61,8 +48,16 @@ internal class MethodCallHandler(
call.argument<List<String>?>("mimeTypes"),
call.argument<String?>("text"),
call.argument<String?>("subject"),
true,
isWithResult,
)

if (!isWithResult) {
if (isResultRequested) {
result.success("dev.fluttercommunity.plus/share/unavailable")
} else {
result.success(null)
}
}
} catch (e: IOException) {
result.error("Share failed", e.message, null)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ android {

defaultConfig {
applicationId "io.flutter.plugins.shareexample"
minSdkVersion 22
minSdkVersion 16
targetSdkVersion 31
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
Expand Down
28 changes: 20 additions & 8 deletions packages/share_plus/share_plus/lib/share_plus.dart
Original file line number Diff line number Diff line change
Expand Up @@ -87,12 +87,18 @@ class Share {
/// any other call to any share method that returns a result _might_ result in
/// a [PlatformException] (on Android).
///
/// Because IOS, Android and macOS provide different feedback on share-sheet interaction,
/// a result on IOS will be more specific than on Android or macOS. While IOS can detect if
/// the user actually completed his selected action or aborted it midway, Android and macOS
/// only record if the user selected an action or outright dismissed the share-sheet.
/// Because IOS, Android and macOS provide different feedback on share-sheet
/// interaction, a result on IOS will be more specific than on Android or macOS.
/// While on IOS the selected action can inform its caller that it was completed
/// or dismissed midway (_actions are free to return whatever they want_),
/// Android and macOS only record if the user selected an action or outright
/// dismissed the share-sheet. It is not guaranteed that the user actually shared
/// something.
///
/// **Currently only implemented on IOS, Android and macOS.**
///
/// Will gracefully fall back to the non result variant if not implemented
/// for the current environment and return [ShareResult.unavailable].
static Future<ShareResult> shareWithResult(
String text, {
String? subject,
Expand All @@ -111,12 +117,18 @@ class Share {
/// any other call to any share method that returns a result _might_ result in
/// a [PlatformException] (on Android).
///
/// Because IOS, Android and macOS provide different feedback on share-sheet interaction,
/// a result on IOS will be more specific than on Android or macOS. While IOS can detect if
/// the user actually completed his selected action or aborted it midway, Android and macOS
/// only record if the user selected an action or outright dismissed the share-sheet.
/// Because IOS, Android and macOS provide different feedback on share-sheet
/// interaction, a result on IOS will be more specific than on Android or macOS.
/// While on IOS the selected action can inform its caller that it was completed
/// or dismissed midway (_actions are free to return whatever they want_),
/// Android and macOS only record if the user selected an action or outright
/// dismissed the share-sheet. It is not guaranteed that the user actually shared
/// something.
///
/// **Currently only implemented on IOS, Android and macOS.**
///
/// Will gracefully fall back to the non result variant if not implemented
/// for the current environment and return [ShareResult.unavailable].
static Future<ShareResult> shareFilesWithResult(
List<String> paths, {
List<String>? mimeTypes,
Expand Down
4 changes: 2 additions & 2 deletions packages/share_plus/share_plus/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: share_plus
description: Flutter plugin for sharing content via the platform share UI, using the ACTION_SEND intent on Android and UIActivityViewController on iOS.
version: 4.0.2
version: 4.0.3
homepage: https://plus.fluttercommunity.dev/
repository: https://github.com/fluttercommunity/plus_plugins/tree/main/packages/

Expand All @@ -26,7 +26,7 @@ dependencies:
mime: ^1.0.0
flutter:
sdk: flutter
share_plus_platform_interface: ^3.0.0
share_plus_platform_interface: ^3.0.2
share_plus_linux: ^3.0.0
share_plus_macos: ^3.0.0
share_plus_windows: ^3.0.0
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 3.0.2

- Gracefully fall back from `shareWithResult` to regular `share` methods on unsupported platforms

## 3.0.1

- Set min Flutter to 1.20.0 to match Share plugins on all platforms
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,13 @@ class SharePlatform extends PlatformInterface {
String? subject,
Rect? sharePositionOrigin,
}) async {
throw UnimplementedError(
'shareWithResult() has only been implemented on IOS, Android & macOS');
await _instance.share(
text,
subject: subject,
sharePositionOrigin: sharePositionOrigin,
);

return _resultUnavailable;
}

/// Share files with Result.
Expand All @@ -78,8 +83,15 @@ class SharePlatform extends PlatformInterface {
String? text,
Rect? sharePositionOrigin,
}) async {
throw UnimplementedError(
'shareWithResult() has only been implemented on IOS, Android & macOS');
await _instance.shareFiles(
paths,
mimeTypes: mimeTypes,
subject: subject,
text: text,
sharePositionOrigin: sharePositionOrigin,
);

return _resultUnavailable;
}
}

Expand All @@ -94,8 +106,8 @@ class ShareResult {
///
/// Note that an empty string means the share-sheet was
/// dismissed without any action and the special value
/// `dev.fluttercommunity.plus/share/unavailable` is caused
/// by an unavailable Android Activity at runtime.
/// `dev.fluttercommunity.plus/share/unavailable` points
/// to the current environment not supporting share results.
final String raw;

/// The action the user has taken
Expand All @@ -115,3 +127,9 @@ enum ShareResultStatus {
/// The status can not be determined
unavailable,
}

/// Returned if the platform is not supported
const _resultUnavailable = ShareResult(
'dev.fluttercommunity.plus/share/unavailable',
ShareResultStatus.unavailable,
);
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: share_plus_platform_interface
description: A common platform interface for the share_plus plugin.
version: 3.0.1
version: 3.0.2
homepage: https://plus.fluttercommunity.dev/
repository: https://github.com/fluttercommunity/plus_plugins/tree/main/packages/

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,19 +179,48 @@ void main() {
});
});

test('withResult methods throw unimplemented on non IOS & Android', () async {
test('withResult methods return unavailable on non IOS & Android', () async {
const resultUnavailable = ShareResult(
'dev.fluttercommunity.plus/share/unavailable',
ShareResultStatus.unavailable,
);

expect(
() => sharePlatform.shareWithResult('some text to share'),
throwsA(const TypeMatcher<UnimplementedError>()),
sharePlatform.shareWithResult('some text to share'),
completion(equals(resultUnavailable)),
);

await withFile('tempfile-83649d.png', (File fd) async {
expect(
() => sharePlatform.shareFilesWithResult([fd.path]),
throwsA(const TypeMatcher<UnimplementedError>()),
sharePlatform.shareFilesWithResult([fd.path]),
completion(equals(resultUnavailable)),
);
});
});

test('withResult methods invoke normal share on non IOS & Android', () async {
await sharePlatform.shareWithResult(
'some text to share',
subject: 'some subject to share',
sharePositionOrigin: const Rect.fromLTWH(1.0, 2.0, 3.0, 4.0),
);
verify(mockChannel.invokeMethod<void>('share', <String, dynamic>{
'text': 'some text to share',
'subject': 'some subject to share',
'originX': 1.0,
'originY': 2.0,
'originWidth': 3.0,
'originHeight': 4.0,
}));

await withFile('tempfile-83649e.png', (File fd) async {
await sharePlatform.shareFilesWithResult([fd.path]);
verify(mockChannel.invokeMethod('shareFiles', <String, dynamic>{
'paths': [fd.path],
'mimeTypes': ['image/png'],
}));
});
});
}

/// Execute a block within a context that handles creation and deletion of a helper file
Expand Down