From fbbbcae0d9ad36e2948f8d01c640ffdb621bfb79 Mon Sep 17 00:00:00 2001 From: Patrick Boos Date: Fri, 16 Nov 2018 18:32:48 +0900 Subject: [PATCH 1/6] Share Plugin: Add .shareFile() method (Android & iOS) On iOS file should be in getApplicationDocumentsDirectory() On Android the file should be in getExternalStorageDirectory() --- packages/share/android/build.gradle | 5 ++ .../android/src/main/AndroidManifest.xml | 11 +++ .../io/flutter/plugins/share/SharePlugin.java | 55 +++++++++++- .../main/res/xml/flutter_share_file_paths.xml | 5 ++ packages/share/ios/Classes/SharePlugin.m | 73 +++++++++++++--- packages/share/lib/share.dart | 87 +++++++++++++++++++ packages/share/test/share_test.dart | 56 +++++++++++- 7 files changed, 277 insertions(+), 15 deletions(-) create mode 100644 packages/share/android/src/main/res/xml/flutter_share_file_paths.xml diff --git a/packages/share/android/build.gradle b/packages/share/android/build.gradle index 4d965af4e153..ff1bbf67a40c 100644 --- a/packages/share/android/build.gradle +++ b/packages/share/android/build.gradle @@ -32,3 +32,8 @@ android { disable 'InvalidPackage' } } + +dependencies { + // use support-compat starting from 28.0.0 + implementation 'com.android.support:support-core-utils:27.1.1' +} \ No newline at end of file diff --git a/packages/share/android/src/main/AndroidManifest.xml b/packages/share/android/src/main/AndroidManifest.xml index 407eae4d8128..bcc7871f20e3 100644 --- a/packages/share/android/src/main/AndroidManifest.xml +++ b/packages/share/android/src/main/AndroidManifest.xml @@ -1,3 +1,14 @@ + + + + + diff --git a/packages/share/android/src/main/java/io/flutter/plugins/share/SharePlugin.java b/packages/share/android/src/main/java/io/flutter/plugins/share/SharePlugin.java index 25d4e842ae1d..c5788ce1314c 100644 --- a/packages/share/android/src/main/java/io/flutter/plugins/share/SharePlugin.java +++ b/packages/share/android/src/main/java/io/flutter/plugins/share/SharePlugin.java @@ -5,9 +5,12 @@ package io.flutter.plugins.share; import android.content.Intent; +import android.support.v4.content.FileProvider; import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.PluginRegistry.Registrar; +import android.net.Uri; +import java.io.File; import java.util.Map; /** Plugin method host for presenting a share sheet via Intent */ @@ -30,17 +33,27 @@ private SharePlugin(Registrar registrar) { @Override public void onMethodCall(MethodCall call, MethodChannel.Result result) { if (call.method.equals("share")) { - if (!(call.arguments instanceof Map)) { - throw new IllegalArgumentException("Map argument expected"); - } + expectMapArguments(call); // Android does not support showing the share sheet at a particular point on screen. share((String) call.argument("text")); result.success(null); + } else if (call.method.equals("shareFile")) { + expectMapArguments(call); + // Android does not support showing the share sheet at a particular point on screen. + shareFile((String) call.argument("path"), (String) call.argument("mimeType"), + (String) call.argument("subject"), (String) call.argument("text")); + result.success(null); } else { result.notImplemented(); } } + private void expectMapArguments(MethodCall call) throws IllegalArgumentException { + if (!(call.arguments instanceof Map)) { + throw new IllegalArgumentException("Map argument expected"); + } + } + private void share(String text) { if (text == null || text.isEmpty()) { throw new IllegalArgumentException("Non-empty text expected"); @@ -58,4 +71,40 @@ private void share(String text) { mRegistrar.context().startActivity(chooserIntent); } } + + private void shareFile(String path, String mimeType, String subject, String text) { + if (path == null || path.isEmpty()) { + throw new IllegalArgumentException("Non-empty path expected"); + } + + // TODO use normal EXTRA_STREAM with Uri.fromFile() + // TODO if file is not on external storage, then copy it to external storage into a directory + // TODO or can we share if it is in the external-files-dir ? then we might not need any permissions!! if that is true, copy it to that cache + // copy: + // String fileName = Uri.parse(fileUrl).getLastPathSegment(); + // TODO if copied, make that file deleteOnExit()? + // TODO when coming here, always clear (or even remove?) the directory on the external storage + Uri fileUri = FileProvider.getUriForFile( + mRegistrar.context(), + mRegistrar.context().getPackageName() + ".flutter.share_provider", + new File(path)); + + String tempDirPath = mRegistrar.context().getExternalCacheDir() + + File.separator + "TempFiles" + File.separator; + + Intent shareIntent = new Intent(); + shareIntent.setAction(Intent.ACTION_SEND); + shareIntent.putExtra(Intent.EXTRA_STREAM, fileUri); + if (subject != null) shareIntent.putExtra(Intent.EXTRA_SUBJECT, subject); + if (text != null) shareIntent.putExtra(Intent.EXTRA_TEXT, text); + shareIntent.setType(mimeType != null ? mimeType : "*/*"); + shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + Intent chooserIntent = Intent.createChooser(shareIntent, null /* dialog title optional */); + if (mRegistrar.activity() != null) { + mRegistrar.activity().startActivity(chooserIntent); + } else { + chooserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + mRegistrar.context().startActivity(chooserIntent); + } + } } diff --git a/packages/share/android/src/main/res/xml/flutter_share_file_paths.xml b/packages/share/android/src/main/res/xml/flutter_share_file_paths.xml new file mode 100644 index 000000000000..3d5eb273da3d --- /dev/null +++ b/packages/share/android/src/main/res/xml/flutter_share_file_paths.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/packages/share/ios/Classes/SharePlugin.m b/packages/share/ios/Classes/SharePlugin.m index 7706e58e7152..f76ecd76f18f 100644 --- a/packages/share/ios/Classes/SharePlugin.m +++ b/packages/share/ios/Classes/SharePlugin.m @@ -14,8 +14,19 @@ + (void)registerWithRegistrar:(NSObject *)registrar { binaryMessenger:registrar.messenger]; [shareChannel setMethodCallHandler:^(FlutterMethodCall *call, FlutterResult result) { + NSDictionary *arguments = [call arguments]; + NSNumber *originX = arguments[@"originX"]; + NSNumber *originY = arguments[@"originY"]; + NSNumber *originWidth = arguments[@"originWidth"]; + NSNumber *originHeight = arguments[@"originHeight"]; + + CGRect originRect; + if (originX != nil && originY != nil && originWidth != nil && originHeight != nil) { + originRect = CGRectMake([originX doubleValue], [originY doubleValue], + [originWidth doubleValue], [originHeight doubleValue]); + } + if ([@"share" isEqualToString:call.method]) { - NSDictionary *arguments = [call arguments]; NSString *shareText = arguments[@"text"]; if (shareText.length == 0) { @@ -25,18 +36,26 @@ + (void)registerWithRegistrar:(NSObject *)registrar { return; } - NSNumber *originX = arguments[@"originX"]; - NSNumber *originY = arguments[@"originY"]; - NSNumber *originWidth = arguments[@"originWidth"]; - NSNumber *originHeight = arguments[@"originHeight"]; + [self share:shareText + withController:[UIApplication sharedApplication].keyWindow.rootViewController + atSource:originRect]; + result(nil); + } else if ([@"shareFile" isEqualToString:call.method]) { + NSString *path = arguments[@"path"]; + NSString *mimeType = arguments[@"mimeType"]; + NSString *subject = arguments[@"subject"]; + NSString *text = arguments[@"text"]; - CGRect originRect; - if (originX != nil && originY != nil && originWidth != nil && originHeight != nil) { - originRect = CGRectMake([originX doubleValue], [originY doubleValue], - [originWidth doubleValue], [originHeight doubleValue]); + if (path.length == 0) { + result( + [FlutterError errorWithCode:@"error" message:@"Non-empty path expected" details:nil]); + return; } - [self share:shareText + [self shareFile:path + withMimeType:mimeType + withSubject:subject + withText:text withController:[UIApplication sharedApplication].keyWindow.rootViewController atSource:originRect]; result(nil); @@ -59,4 +78,38 @@ + (void)share:(id)sharedItems [controller presentViewController:activityViewController animated:YES completion:nil]; } ++ (void)shareFile:(id)path + withMimeType:(id)mimeType + withSubject:(NSString *)subject + withText:(NSString *)text + withController:(UIViewController *)controller + atSource:(CGRect)origin { + NSMutableArray *items = [[NSMutableArray alloc]init]; + + if (subject != nil && subject.length != 0) { + [items addObject:subject]; + } + if (text != nil && text.length != 0) { + [items addObject:text]; + } + + // TODO maybe we can just call share here? + if ([mimeType hasPrefix:@"image/"]) { + UIImage *image = [UIImage imageWithContentsOfFile:path]; + [items addObject:image]; + } else { + NSURL *url = [NSURL fileURLWithPath:path]; + [items addObject:url]; + } + + UIActivityViewController *activityViewController = + [[UIActivityViewController alloc] initWithActivityItems:items + applicationActivities:nil]; + activityViewController.popoverPresentationController.sourceView = controller.view; + if (!CGRectIsEmpty(origin)) { + activityViewController.popoverPresentationController.sourceRect = origin; + } + [controller presentViewController:activityViewController animated:YES completion:nil]; +} + @end diff --git a/packages/share/lib/share.dart b/packages/share/lib/share.dart index dc6354e89f8b..a11058b5f900 100644 --- a/packages/share/lib/share.dart +++ b/packages/share/lib/share.dart @@ -3,6 +3,7 @@ // found in the LICENSE file. import 'dart:async'; +import 'dart:io'; import 'dart:ui'; import 'package:flutter/services.dart'; @@ -43,4 +44,90 @@ class Share { return channel.invokeMethod('share', params); } + + /// Summons the platform's share sheet to share a file. + /// + /// Wraps the platform's native share dialog. Can share a file. + /// It uses the ACTION_SEND Intent on Android and UIActivityViewController + /// on iOS. + /// + /// The optional `sharePositionOrigin` parameter can be used to specify a global + /// origin rect for the share sheet to popover from on iPads. It has no effect + /// on non-iPads. + /// + /// May throw [PlatformException] or [FormatException] + /// from [MethodChannel]. + static Future shareFile(File file, + {String mimeType, String subject, String text, Rect sharePositionOrigin}) { + assert(file != null); + assert(file.existsSync()); + final Map params = { + 'path': file.path, + 'mimeType': mimeType ?? _mimeTypeForFile(file), + }; + + if (subject != null) params['subject'] = subject; + if (text != null) params['text'] = text; + + if (sharePositionOrigin != null) { + params['originX'] = sharePositionOrigin.left; + params['originY'] = sharePositionOrigin.top; + params['originWidth'] = sharePositionOrigin.width; + params['originHeight'] = sharePositionOrigin.height; + } + + return channel.invokeMethod('shareFile', params); + } + + static String _mimeTypeForFile(File file) { + assert(file != null); + final String path = file.path; + + final int extensionIndex = path.lastIndexOf("\."); + if (extensionIndex == -1 || extensionIndex == 0) { + return null; + } + + final String extension = path.substring(extensionIndex + 1); + switch (extension) { + // image + case 'jpeg': + case 'jpg': + return 'image/jpeg'; + case 'gif': + return 'image/gif'; + case 'png': + return 'image/png'; + case 'svg': + return 'image/svg+xml'; + case 'tif': + case 'tiff': + return 'image/tiff'; + // audio + case 'aac': + return 'audio/aac'; + case 'oga': + return 'audio/ogg'; + // video + case 'avi': + return 'video/x-msvideo'; + case 'mpeg': + return 'video/mpeg'; + case 'ogv': + return 'video/ogg'; + // other + case 'csv': + return 'text/csv'; + case 'htm': + case 'html': + return 'text/html'; + case 'json': + return 'application/json'; + case 'pdf': + return 'application/pdf'; + case 'txt': + return 'text/plain'; + } + return null; + } } diff --git a/packages/share/test/share_test.dart b/packages/share/test/share_test.dart index 290305aa2177..a6807452e279 100644 --- a/packages/share/test/share_test.dart +++ b/packages/share/test/share_test.dart @@ -2,14 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'dart:io'; import 'dart:ui'; +import 'package:flutter/services.dart'; import 'package:mockito/mockito.dart'; import 'package:share/share.dart'; import 'package:test/test.dart'; -import 'package:flutter/services.dart'; - void main() { MockMethodChannel mockChannel; @@ -50,6 +50,58 @@ void main() { 'originHeight': 4.0, })); }); + + test('sharing null file fails', () { + expect( + () => Share.shareFile(null), + throwsA(const TypeMatcher()), + ); + verifyZeroInteractions(mockChannel); + }); + + test('sharing empty file fails', () { + expect( + () => Share.shareFile(null), + throwsA(const TypeMatcher()), + ); + verifyZeroInteractions(mockChannel); + }); + + test('sharing non existing file fails', () { + expect( + () => Share.shareFile(File('/sdcard/nofile.txt')), + throwsA(const TypeMatcher()), + ); + verifyZeroInteractions(mockChannel); + }); + + test('sharing file sets correct mimeType', () async { + final File file = File('tempfile-83649a.png'); + try { + file.createSync(); + await Share.shareFile(file); + verify(mockChannel.invokeMethod('shareFile', { + 'path': file.path, + 'mimeType': 'image/png', + })); + } finally { + file.deleteSync(); + } + }); + + test('sharing file sets passed mimeType', () async { + final File file = File('tempfile-83649a.png'); + try { + file.createSync(); + await Share.shareFile(file, mimeType: '*/*'); + verify(mockChannel.invokeMethod('shareFile', { + 'path': file.path, + 'mimeType': '*/*', + })); + } finally { + file.deleteSync(); + } + }); } class MockMethodChannel extends Mock implements MethodChannel {} From 963c34e6999622d95863cc5168ccd4447575e97d Mon Sep 17 00:00:00 2001 From: Patrick Boos Date: Mon, 19 Nov 2018 11:42:56 +0900 Subject: [PATCH 2/6] Share: Improve sharing of files by copying files to sd card on android if needed --- .../android/src/main/AndroidManifest.xml | 5 +- .../io/flutter/plugins/share/SharePlugin.java | 116 ++++++++++++++---- .../main/res/xml/flutter_share_file_paths.xml | 5 +- 3 files changed, 96 insertions(+), 30 deletions(-) diff --git a/packages/share/android/src/main/AndroidManifest.xml b/packages/share/android/src/main/AndroidManifest.xml index bcc7871f20e3..ce3d3828b273 100644 --- a/packages/share/android/src/main/AndroidManifest.xml +++ b/packages/share/android/src/main/AndroidManifest.xml @@ -1,5 +1,6 @@ + package="io.flutter.plugins.share"> + + android:resource="@xml/flutter_share_file_paths" /> diff --git a/packages/share/android/src/main/java/io/flutter/plugins/share/SharePlugin.java b/packages/share/android/src/main/java/io/flutter/plugins/share/SharePlugin.java index c5788ce1314c..aa14426b5f7f 100644 --- a/packages/share/android/src/main/java/io/flutter/plugins/share/SharePlugin.java +++ b/packages/share/android/src/main/java/io/flutter/plugins/share/SharePlugin.java @@ -5,12 +5,15 @@ package io.flutter.plugins.share; import android.content.Intent; +import android.net.Uri; +import android.os.Environment; +import android.support.annotation.NonNull; import android.support.v4.content.FileProvider; import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.PluginRegistry.Registrar; -import android.net.Uri; -import java.io.File; + +import java.io.*; import java.util.Map; /** Plugin method host for presenting a share sheet via Intent */ @@ -32,19 +35,27 @@ private SharePlugin(Registrar registrar) { @Override public void onMethodCall(MethodCall call, MethodChannel.Result result) { - if (call.method.equals("share")) { - expectMapArguments(call); - // Android does not support showing the share sheet at a particular point on screen. - share((String) call.argument("text")); - result.success(null); - } else if (call.method.equals("shareFile")) { - expectMapArguments(call); - // Android does not support showing the share sheet at a particular point on screen. - shareFile((String) call.argument("path"), (String) call.argument("mimeType"), + switch (call.method) { + case "share": + expectMapArguments(call); + // Android does not support showing the share sheet at a particular point on screen. + share((String) call.argument("text")); + result.success(null); + break; + case "shareFile": + expectMapArguments(call); + // Android does not support showing the share sheet at a particular point on screen. + try { + shareFile((String) call.argument("path"), (String) call.argument("mimeType"), (String) call.argument("subject"), (String) call.argument("text")); - result.success(null); - } else { - result.notImplemented(); + result.success(null); + } catch (IOException e) { + result.error(e.getMessage(), null, null); + } + break; + default: + result.notImplemented(); + break; } } @@ -72,25 +83,21 @@ private void share(String text) { } } - private void shareFile(String path, String mimeType, String subject, String text) { + private void shareFile(String path, String mimeType, String subject, String text) throws IOException { if (path == null || path.isEmpty()) { throw new IllegalArgumentException("Non-empty path expected"); } - // TODO use normal EXTRA_STREAM with Uri.fromFile() - // TODO if file is not on external storage, then copy it to external storage into a directory - // TODO or can we share if it is in the external-files-dir ? then we might not need any permissions!! if that is true, copy it to that cache - // copy: - // String fileName = Uri.parse(fileUrl).getLastPathSegment(); - // TODO if copied, make that file deleteOnExit()? - // TODO when coming here, always clear (or even remove?) the directory on the external storage + File file = new File(path); + clearExternalShareFolder(); + if (!fileIsOnExternal(file)) { + file = copyToExternalShareFolder(file); + } + Uri fileUri = FileProvider.getUriForFile( mRegistrar.context(), mRegistrar.context().getPackageName() + ".flutter.share_provider", - new File(path)); - - String tempDirPath = mRegistrar.context().getExternalCacheDir() - + File.separator + "TempFiles" + File.separator; + file); Intent shareIntent = new Intent(); shareIntent.setAction(Intent.ACTION_SEND); @@ -107,4 +114,61 @@ private void shareFile(String path, String mimeType, String subject, String text mRegistrar.context().startActivity(chooserIntent); } } + + private boolean fileIsOnExternal(File file) { + try { + String filePath = file.getCanonicalPath(); + File externalDir = Environment.getExternalStorageDirectory(); + return externalDir != null && filePath.startsWith(externalDir.getCanonicalPath()); + } catch (IOException e) { + return false; + } + } + + @SuppressWarnings("ResultOfMethodCallIgnored") + private void clearExternalShareFolder() { + File folder = getExternalShareFolder(); + if (folder.exists()) { + for (File file : folder.listFiles()) { + file.delete(); + } + folder.delete(); + } + } + + @SuppressWarnings("ResultOfMethodCallIgnored") + private File copyToExternalShareFolder(File file) throws IOException { + File folder = getExternalShareFolder(); + if (!folder.exists()) { + folder.mkdirs(); + } + + File newFile = new File(folder, file.getName()); + copy(file, newFile); + return newFile; + } + + @NonNull + private File getExternalShareFolder() { + return new File(mRegistrar.context().getExternalCacheDir(), "share"); + } + + private static void copy(File src, File dst) throws IOException { + InputStream in = new FileInputStream(src); + try { + OutputStream out = new FileOutputStream(dst); + try { + // Transfer bytes from in to out + byte[] buf = new byte[1024]; + int len; + while ((len = in.read(buf)) > 0) { + out.write(buf, 0, len); + } + } finally { + out.close(); + } + } finally { + in.close(); + } + } } diff --git a/packages/share/android/src/main/res/xml/flutter_share_file_paths.xml b/packages/share/android/src/main/res/xml/flutter_share_file_paths.xml index 3d5eb273da3d..ce94d87583e4 100644 --- a/packages/share/android/src/main/res/xml/flutter_share_file_paths.xml +++ b/packages/share/android/src/main/res/xml/flutter_share_file_paths.xml @@ -1,5 +1,6 @@ - - + + + \ No newline at end of file From 111703b3ec14b6d63364e83ff2155f3abc23d47d Mon Sep 17 00:00:00 2001 From: Patrick Boos Date: Fri, 7 Dec 2018 14:34:51 +0100 Subject: [PATCH 3/6] Share: Refactoring --- packages/share/ios/Classes/SharePlugin.m | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/packages/share/ios/Classes/SharePlugin.m b/packages/share/ios/Classes/SharePlugin.m index f76ecd76f18f..07caa923003e 100644 --- a/packages/share/ios/Classes/SharePlugin.m +++ b/packages/share/ios/Classes/SharePlugin.m @@ -36,7 +36,7 @@ + (void)registerWithRegistrar:(NSObject *)registrar { return; } - [self share:shareText + [self share:@[ shareText ] withController:[UIApplication sharedApplication].keyWindow.rootViewController atSource:originRect]; result(nil); @@ -65,11 +65,11 @@ + (void)registerWithRegistrar:(NSObject *)registrar { }]; } -+ (void)share:(id)sharedItems ++ (void)share:(NSArray *)shareItems withController:(UIViewController *)controller atSource:(CGRect)origin { UIActivityViewController *activityViewController = - [[UIActivityViewController alloc] initWithActivityItems:@[ sharedItems ] + [[UIActivityViewController alloc] initWithActivityItems:shareItems applicationActivities:nil]; activityViewController.popoverPresentationController.sourceView = controller.view; if (!CGRectIsEmpty(origin)) { @@ -93,7 +93,6 @@ + (void)shareFile:(id)path [items addObject:text]; } - // TODO maybe we can just call share here? if ([mimeType hasPrefix:@"image/"]) { UIImage *image = [UIImage imageWithContentsOfFile:path]; [items addObject:image]; @@ -102,14 +101,9 @@ + (void)shareFile:(id)path [items addObject:url]; } - UIActivityViewController *activityViewController = - [[UIActivityViewController alloc] initWithActivityItems:items - applicationActivities:nil]; - activityViewController.popoverPresentationController.sourceView = controller.view; - if (!CGRectIsEmpty(origin)) { - activityViewController.popoverPresentationController.sourceRect = origin; - } - [controller presentViewController:activityViewController animated:YES completion:nil]; + [self share:items + withController:controller + atSource:origin]; } @end From 0abff262c3c8072b730071796ad044f73be9a055 Mon Sep 17 00:00:00 2001 From: Patrick Boos Date: Fri, 7 Dec 2018 14:58:55 +0100 Subject: [PATCH 4/6] Share: Updated README.md --- packages/share/README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/share/README.md b/packages/share/README.md index 4536c5818b7d..0a58de0f7f61 100644 --- a/packages/share/README.md +++ b/packages/share/README.md @@ -22,3 +22,8 @@ Then invoke the static `share` method anywhere in your Dart code ``` dart Share.share('check out my website https://example.com'); ``` + +To share a file invoke the static `shareFile` method anywhere in your Dart code +``` dart +Share.shareFile(File('${directory.path}/image.jpg')); +``` From 32d70052e89ccb4ea8c528f174dd29023c037a16 Mon Sep 17 00:00:00 2001 From: Patrick Boos Date: Fri, 7 Dec 2018 15:10:25 +0100 Subject: [PATCH 5/6] Share: Fix formatting --- .../io/flutter/plugins/share/SharePlugin.java | 20 +++++++++++-------- packages/share/ios/Classes/SharePlugin.m | 14 ++++++------- packages/share/lib/share.dart | 5 ++++- 3 files changed, 22 insertions(+), 17 deletions(-) diff --git a/packages/share/android/src/main/java/io/flutter/plugins/share/SharePlugin.java b/packages/share/android/src/main/java/io/flutter/plugins/share/SharePlugin.java index aa14426b5f7f..d2a33b432fc4 100644 --- a/packages/share/android/src/main/java/io/flutter/plugins/share/SharePlugin.java +++ b/packages/share/android/src/main/java/io/flutter/plugins/share/SharePlugin.java @@ -12,7 +12,6 @@ import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.PluginRegistry.Registrar; - import java.io.*; import java.util.Map; @@ -46,8 +45,11 @@ public void onMethodCall(MethodCall call, MethodChannel.Result result) { expectMapArguments(call); // Android does not support showing the share sheet at a particular point on screen. try { - shareFile((String) call.argument("path"), (String) call.argument("mimeType"), - (String) call.argument("subject"), (String) call.argument("text")); + shareFile( + (String) call.argument("path"), + (String) call.argument("mimeType"), + (String) call.argument("subject"), + (String) call.argument("text")); result.success(null); } catch (IOException e) { result.error(e.getMessage(), null, null); @@ -83,7 +85,8 @@ private void share(String text) { } } - private void shareFile(String path, String mimeType, String subject, String text) throws IOException { + private void shareFile(String path, String mimeType, String subject, String text) + throws IOException { if (path == null || path.isEmpty()) { throw new IllegalArgumentException("Non-empty path expected"); } @@ -94,10 +97,11 @@ private void shareFile(String path, String mimeType, String subject, String text file = copyToExternalShareFolder(file); } - Uri fileUri = FileProvider.getUriForFile( - mRegistrar.context(), - mRegistrar.context().getPackageName() + ".flutter.share_provider", - file); + Uri fileUri = + FileProvider.getUriForFile( + mRegistrar.context(), + mRegistrar.context().getPackageName() + ".flutter.share_provider", + file); Intent shareIntent = new Intent(); shareIntent.setAction(Intent.ACTION_SEND); diff --git a/packages/share/ios/Classes/SharePlugin.m b/packages/share/ios/Classes/SharePlugin.m index 07caa923003e..2411650ae56e 100644 --- a/packages/share/ios/Classes/SharePlugin.m +++ b/packages/share/ios/Classes/SharePlugin.m @@ -47,8 +47,9 @@ + (void)registerWithRegistrar:(NSObject *)registrar { NSString *text = arguments[@"text"]; if (path.length == 0) { - result( - [FlutterError errorWithCode:@"error" message:@"Non-empty path expected" details:nil]); + result([FlutterError errorWithCode:@"error" + message:@"Non-empty path expected" + details:nil]); return; } @@ -69,8 +70,7 @@ + (void)share:(NSArray *)shareItems withController:(UIViewController *)controller atSource:(CGRect)origin { UIActivityViewController *activityViewController = - [[UIActivityViewController alloc] initWithActivityItems:shareItems - applicationActivities:nil]; + [[UIActivityViewController alloc] initWithActivityItems:shareItems applicationActivities:nil]; activityViewController.popoverPresentationController.sourceView = controller.view; if (!CGRectIsEmpty(origin)) { activityViewController.popoverPresentationController.sourceRect = origin; @@ -84,7 +84,7 @@ + (void)shareFile:(id)path withText:(NSString *)text withController:(UIViewController *)controller atSource:(CGRect)origin { - NSMutableArray *items = [[NSMutableArray alloc]init]; + NSMutableArray *items = [[NSMutableArray alloc] init]; if (subject != nil && subject.length != 0) { [items addObject:subject]; @@ -101,9 +101,7 @@ + (void)shareFile:(id)path [items addObject:url]; } - [self share:items - withController:controller - atSource:origin]; + [self share:items withController:controller atSource:origin]; } @end diff --git a/packages/share/lib/share.dart b/packages/share/lib/share.dart index a11058b5f900..1ab2af3110f7 100644 --- a/packages/share/lib/share.dart +++ b/packages/share/lib/share.dart @@ -58,7 +58,10 @@ class Share { /// May throw [PlatformException] or [FormatException] /// from [MethodChannel]. static Future shareFile(File file, - {String mimeType, String subject, String text, Rect sharePositionOrigin}) { + {String mimeType, + String subject, + String text, + Rect sharePositionOrigin}) { assert(file != null); assert(file.existsSync()); final Map params = { From 53024e9ea1b6ef5fbd514bba5074c64f05f13f46 Mon Sep 17 00:00:00 2001 From: "Tom J. Wassing" Date: Mon, 8 Jul 2019 10:46:44 +0200 Subject: [PATCH 6/6] upgraded to android x --- packages/share/android/src/main/AndroidManifest.xml | 2 +- .../src/main/java/io/flutter/plugins/share/SharePlugin.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/share/android/src/main/AndroidManifest.xml b/packages/share/android/src/main/AndroidManifest.xml index ce3d3828b273..e687dab0032d 100644 --- a/packages/share/android/src/main/AndroidManifest.xml +++ b/packages/share/android/src/main/AndroidManifest.xml @@ -3,7 +3,7 @@ diff --git a/packages/share/android/src/main/java/io/flutter/plugins/share/SharePlugin.java b/packages/share/android/src/main/java/io/flutter/plugins/share/SharePlugin.java index d2a33b432fc4..76e6b7a95028 100644 --- a/packages/share/android/src/main/java/io/flutter/plugins/share/SharePlugin.java +++ b/packages/share/android/src/main/java/io/flutter/plugins/share/SharePlugin.java @@ -7,8 +7,8 @@ import android.content.Intent; import android.net.Uri; import android.os.Environment; -import android.support.annotation.NonNull; -import android.support.v4.content.FileProvider; +import androidx.annotation.NonNull; +import androidx.core.content.FileProvider; import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.PluginRegistry.Registrar;