From 177f60c718a99ede6b5a0248c2849eec155047cd Mon Sep 17 00:00:00 2001 From: greymag Date: Mon, 3 May 2021 12:15:28 +0300 Subject: [PATCH 01/28] Update example's .gitignore files. --- example/.gitignore | 56 +++++++++----------------------------- example/android/.gitignore | 11 ++++++++ example/ios/.gitignore | 32 ++++++++++++++++++++++ 3 files changed, 56 insertions(+), 43 deletions(-) create mode 100644 example/android/.gitignore create mode 100644 example/ios/.gitignore diff --git a/example/.gitignore b/example/.gitignore index 47e0b4d..9d532b1 100644 --- a/example/.gitignore +++ b/example/.gitignore @@ -1,6 +1,5 @@ # Miscellaneous *.class -*.lock *.log *.pyc *.swp @@ -16,56 +15,27 @@ *.iws .idea/ -# Visual Studio Code related -.vscode/ +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ # Flutter/Dart/Pub related **/doc/api/ +**/ios/Flutter/.last_build_id .dart_tool/ .flutter-plugins +.flutter-plugins-dependencies .packages .pub-cache/ .pub/ -build/ +/build/ -# Android related -**/android/**/gradle-wrapper.jar -**/android/.gradle -**/android/captures/ -**/android/gradlew -**/android/gradlew.bat -**/android/local.properties -**/android/**/GeneratedPluginRegistrant.java +# Web related +lib/generated_plugin_registrant.dart -# iOS/XCode related -**/ios/**/*.mode1v3 -**/ios/**/*.mode2v3 -**/ios/**/*.moved-aside -**/ios/**/*.pbxuser -**/ios/**/*.perspectivev3 -**/ios/**/*sync/ -**/ios/**/.sconsign.dblite -**/ios/**/.tags* -**/ios/**/.vagrant/ -**/ios/**/DerivedData/ -**/ios/**/Icon? -**/ios/**/Pods/ -**/ios/**/.symlinks/ -**/ios/**/profile -**/ios/**/xcuserdata -**/ios/.generated/ -**/ios/Flutter/App.framework -**/ios/Flutter/Flutter.framework -**/ios/Flutter/Generated.xcconfig -**/ios/Flutter/app.flx -**/ios/Flutter/app.zip -**/ios/Flutter/flutter_assets/ -**/ios/ServiceDefinitions.json -**/ios/Runner/GeneratedPluginRegistrant.* +# Symbolication related +app.*.symbols -# Exceptions to above rules. -!**/ios/**/default.mode1v3 -!**/ios/**/default.mode2v3 -!**/ios/**/default.pbxuser -!**/ios/**/default.perspectivev3 -!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages +# Obfuscation related +app.*.map.json diff --git a/example/android/.gitignore b/example/android/.gitignore new file mode 100644 index 0000000..0a741cb --- /dev/null +++ b/example/android/.gitignore @@ -0,0 +1,11 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java + +# Remember to never publicly share your keystore. +# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app +key.properties diff --git a/example/ios/.gitignore b/example/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/example/ios/.gitignore @@ -0,0 +1,32 @@ +*.mode1v3 +*.mode2v3 +*.moved-aside +*.pbxuser +*.perspectivev3 +**/*sync/ +.sconsign.dblite +.tags* +**/.vagrant/ +**/DerivedData/ +Icon? +**/Pods/ +**/.symlinks/ +profile +xcuserdata +**/.generated/ +Flutter/App.framework +Flutter/Flutter.framework +Flutter/Flutter.podspec +Flutter/Generated.xcconfig +Flutter/app.flx +Flutter/app.zip +Flutter/flutter_assets/ +Flutter/flutter_export_environment.sh +ServiceDefinitions.json +Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!default.mode1v3 +!default.mode2v3 +!default.pbxuser +!default.perspectivev3 From 23b7ca98b9a8cf760cbc3dbc0659a98d405e50ec Mon Sep 17 00:00:00 2001 From: greymag Date: Mon, 3 May 2021 12:16:07 +0300 Subject: [PATCH 02/28] Migrate to null safety. Update path_provider to 2.0.0 --- CHANGELOG.md | 5 +++++ example/pubspec.yaml | 17 ++++++----------- pubspec.yaml | 9 +++------ 3 files changed, 14 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b83051..333faa3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## 2.0.0 + +* migrate to null safety +* update path_provider to 2.0.0 + ## 1.0.3 * update example app diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 04da2c1..0df9612 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,9 +1,9 @@ name: esys_flutter_share_example description: Demonstrates how to use the esys_flutter_share plugin. -publish_to: 'none' +publish_to: "none" environment: - sdk: ">=2.1.0 <3.0.0" + sdk: ">=2.12.0 <3.0.0" dependencies: flutter: @@ -25,7 +25,6 @@ dev_dependencies: # The following section is specific to Flutter. flutter: - # The following line ensures that the Material Icons font is # included with your application, so that you can use the icons in # the material Icons class. @@ -36,18 +35,14 @@ flutter: # - images/a_dot_burr.jpeg # - images/a_dot_ham.jpeg assets: - - assets/cat.mp3 - - assets/image1.png - - assets/image2.png - - assets/addresses.csv - - + - assets/cat.mp3 + - assets/image1.png + - assets/image2.png + - assets/addresses.csv # An image asset can refer to one or more resolution-specific "variants", see # https://flutter.io/assets-and-images/#resolution-aware. - # For details regarding adding assets from package dependencies, see # https://flutter.io/assets-and-images/#from-packages - # To add custom fonts to your application, add a fonts section here, # in this "flutter" section. Each entry in this list should have a # "family" key with the font family name, and a "fonts" key with a diff --git a/pubspec.yaml b/pubspec.yaml index 8bfc35d..13db0a2 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,20 +1,19 @@ name: esys_flutter_share description: A Flutter plugin for sharing images & text with other applications. -version: 1.0.2 +version: 2.0.0 author: ESYS GmbH homepage: https://github.com/esysberlin/esys-flutter-share environment: - sdk: ">=2.0.0-dev.68.0 <3.0.0" + sdk: ">=2.12.0 <3.0.0" dependencies: flutter: sdk: flutter - path_provider: ^1.1.0 + path_provider: ^2.0.0 # For information on the generic Dart part of this file, see the # following page: https://www.dartlang.org/tools/pub/pubspec - # The following section is specific to Flutter. flutter: # This section identifies this Flutter project as a plugin project. @@ -24,7 +23,6 @@ flutter: plugin: androidPackage: de.esys.esysfluttershare pluginClass: EsysFlutterSharePlugin - # To add assets to your plugin package, add an assets section, like this: # assets: # - images/a_dot_burr.jpeg @@ -35,7 +33,6 @@ flutter: # # An image asset can refer to one or more resolution-specific "variants", see # https://flutter.io/assets-and-images/#resolution-aware. - # To add custom fonts to your plugin package, add a fonts section here, # in this "flutter" section. Each entry in this list should have a # "family" key with the font family name, and a "fonts" key with a From 43e64dda4eeb06050991552895d869e347a0f76b Mon Sep 17 00:00:00 2001 From: mongugay Date: Mon, 29 Nov 2021 11:07:47 +0300 Subject: [PATCH 03/28] Add embedding version 2 --- CHANGELOG.md | 4 ++++ android/build.gradle | 8 ++++---- pubspec.yaml | 2 +- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 333faa3..ed4722f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.1 + +* migrate to V2 + ## 2.0.0 * migrate to null safety diff --git a/android/build.gradle b/android/build.gradle index 7a7d8da..0bc34ba 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -4,18 +4,18 @@ version '1.0-SNAPSHOT' buildscript { repositories { google() - jcenter() + mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:3.2.1' + classpath 'com.android.tools.build:gradle:4.1.3' } } rootProject.allprojects { repositories { google() - jcenter() + mavenCentral() } } @@ -35,4 +35,4 @@ android { dependencies { implementation 'androidx.legacy:legacy-support-v4:1.0.0-beta01' -} +} \ No newline at end of file diff --git a/pubspec.yaml b/pubspec.yaml index 13db0a2..1e4d07e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: esys_flutter_share description: A Flutter plugin for sharing images & text with other applications. -version: 2.0.0 +version: 2.0.1 author: ESYS GmbH homepage: https://github.com/esysberlin/esys-flutter-share From 7b6d750684294d9da4ecb1c4a0e3164ddb00855d Mon Sep 17 00:00:00 2001 From: mongugay Date: Mon, 29 Nov 2021 12:04:16 +0300 Subject: [PATCH 04/28] Change to MethodChannel, FlutterPlugin. --- .../EsysFlutterSharePlugin.java | 72 +++++++++++-------- 1 file changed, 44 insertions(+), 28 deletions(-) diff --git a/android/src/main/java/de/esys/esysfluttershare/EsysFlutterSharePlugin.java b/android/src/main/java/de/esys/esysfluttershare/EsysFlutterSharePlugin.java index 715a38b..314aa41 100644 --- a/android/src/main/java/de/esys/esysfluttershare/EsysFlutterSharePlugin.java +++ b/android/src/main/java/de/esys/esysfluttershare/EsysFlutterSharePlugin.java @@ -2,43 +2,41 @@ import android.content.Context; import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; import android.net.Uri; -import android.util.Log; +import androidx.annotation.NonNull; import androidx.core.content.FileProvider; import java.io.File; import java.util.ArrayList; import java.util.HashMap; +import java.util.List; +import io.flutter.embedding.engine.plugins.FlutterPlugin; import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.MethodChannel.MethodCallHandler; import io.flutter.plugin.common.MethodChannel.Result; -import io.flutter.plugin.common.PluginRegistry.Registrar; -/** - * EsysFlutterSharePlugin - */ -public class EsysFlutterSharePlugin implements MethodCallHandler { +/** EsysfluttersharePlugin */ +public class EsysFlutterSharePlugin implements FlutterPlugin, MethodCallHandler { private final String PROVIDER_AUTH_EXT = ".fileprovider.github.com/orgs/esysberlin/esys-flutter-share"; - private Registrar _registrar; - private EsysFlutterSharePlugin(Registrar registrar) { - this._registrar = registrar; - } + private MethodChannel channel; + private FlutterPluginBinding binding; - /** - * Plugin registration. - */ - public static void registerWith(Registrar registrar) { - final MethodChannel channel = new MethodChannel(registrar.messenger(), "channel:github.com/orgs/esysberlin/esys-flutter-share"); - channel.setMethodCallHandler(new EsysFlutterSharePlugin(registrar)); + @Override + public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) { + channel = new MethodChannel(flutterPluginBinding.getBinaryMessenger(), "channel:github.com/orgs/esysberlin/esys-flutter-share"); + binding = flutterPluginBinding; + channel.setMethodCallHandler(this); } @Override - public void onMethodCall(MethodCall call, Result result) { + public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) { if (call.method.equals("text")) { text(call.arguments); } @@ -50,6 +48,11 @@ public void onMethodCall(MethodCall call, Result result) { } } + @Override + public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) { + channel.setMethodCallHandler(null); + } + private void text(Object arguments) { @SuppressWarnings("unchecked") HashMap argsMap = (HashMap) arguments; @@ -57,12 +60,16 @@ private void text(Object arguments) { String text = argsMap.get("text"); String mimeType = argsMap.get("mimeType"); - Context activeContext = _registrar.activeContext(); + Context activeContext = binding.getApplicationContext(); Intent shareIntent = new Intent(Intent.ACTION_SEND); + shareIntent.setType(mimeType); shareIntent.putExtra(Intent.EXTRA_TEXT, text); - activeContext.startActivity(Intent.createChooser(shareIntent, title)); + Intent chooserIntent = Intent.createChooser(shareIntent, title); + chooserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + chooserIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); + activeContext.startActivity(chooserIntent); } private void file(Object arguments) { @@ -73,7 +80,7 @@ private void file(Object arguments) { String mimeType = argsMap.get("mimeType"); String text = argsMap.get("text"); - Context activeContext = _registrar.activeContext(); + Context activeContext = binding.getApplicationContext(); Intent shareIntent = new Intent(Intent.ACTION_SEND); shareIntent.setType(mimeType); @@ -83,7 +90,10 @@ private void file(Object arguments) { shareIntent.putExtra(Intent.EXTRA_STREAM, contentUri); // add optional text if (!text.isEmpty()) shareIntent.putExtra(Intent.EXTRA_TEXT, text); - activeContext.startActivity(Intent.createChooser(shareIntent, title)); + Intent chooserIntent = Intent.createChooser(shareIntent, title); + chooserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + + activeContext.startActivity(chooserIntent); } private void files(Object arguments) { @@ -96,22 +106,28 @@ private void files(Object arguments) { String mimeType = (String) argsMap.get("mimeType"); String text = (String) argsMap.get("text"); - Context activeContext = _registrar.activeContext(); + Context activeContext = binding.getApplicationContext(); Intent shareIntent = new Intent(Intent.ACTION_SEND_MULTIPLE); shareIntent.setType(mimeType); ArrayList contentUris = new ArrayList<>(); + shareIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, contentUris); + // add optional text + if (!text.isEmpty()) shareIntent.putExtra(Intent.EXTRA_TEXT, text); + + Intent chooserIntent = Intent.createChooser(shareIntent, title); + for (String name : names) { File file = new File(activeContext.getCacheDir(), name); String fileProviderAuthority = activeContext.getPackageName() + PROVIDER_AUTH_EXT; - contentUris.add(FileProvider.getUriForFile(activeContext, fileProviderAuthority, file)); + Uri contentUri = FileProvider.getUriForFile(activeContext, fileProviderAuthority, file); + contentUris.add(contentUri); } - shareIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, contentUris); - // add optional text - if (!text.isEmpty()) shareIntent.putExtra(Intent.EXTRA_TEXT, text); - activeContext.startActivity(Intent.createChooser(shareIntent, title)); + chooserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + + activeContext.startActivity(chooserIntent); } -} +} \ No newline at end of file From 6bee8070472c166952cd0cc8ac2751ba6f39f888 Mon Sep 17 00:00:00 2001 From: mongugay Date: Mon, 29 Nov 2021 12:35:10 +0300 Subject: [PATCH 05/28] Change place code. --- .../esysfluttershare/EsysFlutterSharePlugin.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/android/src/main/java/de/esys/esysfluttershare/EsysFlutterSharePlugin.java b/android/src/main/java/de/esys/esysfluttershare/EsysFlutterSharePlugin.java index 314aa41..5e3cfc7 100644 --- a/android/src/main/java/de/esys/esysfluttershare/EsysFlutterSharePlugin.java +++ b/android/src/main/java/de/esys/esysfluttershare/EsysFlutterSharePlugin.java @@ -113,12 +113,6 @@ private void files(Object arguments) { ArrayList contentUris = new ArrayList<>(); - shareIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, contentUris); - // add optional text - if (!text.isEmpty()) shareIntent.putExtra(Intent.EXTRA_TEXT, text); - - Intent chooserIntent = Intent.createChooser(shareIntent, title); - for (String name : names) { File file = new File(activeContext.getCacheDir(), name); String fileProviderAuthority = activeContext.getPackageName() + PROVIDER_AUTH_EXT; @@ -126,6 +120,12 @@ private void files(Object arguments) { contentUris.add(contentUri); } + shareIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, contentUris); + // add optional text + if (!text.isEmpty()) shareIntent.putExtra(Intent.EXTRA_TEXT, text); + + Intent chooserIntent = Intent.createChooser(shareIntent, title); + chooserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); activeContext.startActivity(chooserIntent); From 4c7a2723fca19c887ce665f3a6c586e5af3dddd3 Mon Sep 17 00:00:00 2001 From: greymag Date: Mon, 21 Feb 2022 11:34:30 +0300 Subject: [PATCH 06/28] iOS project files --- example/ios/Runner.xcodeproj/project.pbxproj | 17 +---------------- .../contents.xcworkspacedata | 2 +- .../xcshareddata/WorkspaceSettings.xcsettings | 8 -------- 3 files changed, 2 insertions(+), 25 deletions(-) delete mode 100644 example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index 7ef591e..2de765a 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -10,11 +10,7 @@ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 30CC177B0653FC1250DBBDDC /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9BB236F61766429B48517DC1 /* Pods_Runner.framework */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; }; - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; }; - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; @@ -27,8 +23,6 @@ dstPath = ""; dstSubfolderSpec = 10; files = ( - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */, - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */, ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; @@ -39,13 +33,11 @@ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; - 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; @@ -59,8 +51,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, 30CC177B0653FC1250DBBDDC /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -86,9 +76,7 @@ 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( - 3B80C3931E831B6300D905FE /* App.framework */, 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, - 9740EEBA1CF902C7004384FC /* Flutter.framework */, 9740EEB21CF90195004384FC /* Debug.xcconfig */, 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 9740EEB31CF90195004384FC /* Generated.xcconfig */, @@ -225,7 +213,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; }; 53F69E7EBD03F2E7D52A5B83 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; @@ -317,7 +305,6 @@ /* Begin XCBuildConfiguration section */ 249021D3217E4FDB00AE95B9 /* Profile */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; @@ -392,7 +379,6 @@ }; 97C147031CF9000F007C117D /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; @@ -448,7 +434,6 @@ }; 97C147041CF9000F007C117D /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; diff --git a/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata index 1d526a1..919434a 100644 --- a/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ b/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -2,6 +2,6 @@ + location = "self:"> diff --git a/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings deleted file mode 100644 index 949b678..0000000 --- a/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +++ /dev/null @@ -1,8 +0,0 @@ - - - - - BuildSystemType - Original - - From e9ef2a7922021ff091a976bd93aac02cb6953201 Mon Sep 17 00:00:00 2001 From: greymag Date: Mon, 21 Feb 2022 11:34:34 +0300 Subject: [PATCH 07/28] Refactor --- lib/esys_flutter_share.dart | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/esys_flutter_share.dart b/lib/esys_flutter_share.dart index d8c37d4..fb92a24 100644 --- a/lib/esys_flutter_share.dart +++ b/lib/esys_flutter_share.dart @@ -20,7 +20,8 @@ class Share { /// Sends a file to other apps. static Future file( - String title, String name, List bytes, String mimeType, {String text = ''}) async { + String title, String name, List bytes, String mimeType, + {String text = ''}) async { Map argsMap = { 'title': '$title', 'name': '$name', @@ -37,7 +38,8 @@ class Share { /// Sends multiple files to other apps. static Future files( - String title, Map> files, String mimeType, {String text = ''}) async { + String title, Map> files, String mimeType, + {String text = ''}) async { Map argsMap = { 'title': '$title', 'names': files.entries.toList().map((x) => x.key).toList(), From 57bd89a81fd427dc68c67486dcde47fb16eaea36 Mon Sep 17 00:00:00 2001 From: greymag Date: Mon, 21 Feb 2022 11:39:13 +0300 Subject: [PATCH 08/28] Example: embedding-v2 --- example/android/app/src/main/AndroidManifest.xml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml index 446eeef..032ab4d 100644 --- a/example/android/app/src/main/AndroidManifest.xml +++ b/example/android/app/src/main/AndroidManifest.xml @@ -13,7 +13,7 @@ additional functionality it is fine to subclass or reimplement FlutterApplication and put your custom class here. --> + + + From c60f41a2cdc8627980f9dc886c56ab88bf92a5e2 Mon Sep 17 00:00:00 2001 From: greymag Date: Mon, 21 Feb 2022 11:39:32 +0300 Subject: [PATCH 09/28] Changed name: esys_flutter_share_plus --- README.md | 6 ++++-- example/lib/main.dart | 2 +- example/pubspec.yaml | 2 +- ...s_flutter_share.dart => esys_flutter_share_plus.dart} | 0 pubspec.yaml | 9 +++++---- 5 files changed, 11 insertions(+), 8 deletions(-) rename lib/{esys_flutter_share.dart => esys_flutter_share_plus.dart} (100%) diff --git a/README.md b/README.md index 7cfb3ee..8fb0a99 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,6 @@ -# esys_flutter_share +# esys_flutter_share_plus + +It's fork of [esys_flutter_share](https://github.com/esysberlin/esys-flutter-share). A [Flutter](https://flutter.io) plugin for sharing files & text with other applications. @@ -33,7 +35,7 @@ Instead, if you have already a non-swift project, you can check this issue to so Import: ```dart -import 'package:esys_flutter_share/esys_flutter_share.dart'; +import 'package:esys_flutter_share_plus/esys_flutter_share_plus.dart'; ``` Share text: diff --git a/example/lib/main.dart b/example/lib/main.dart index 8da9b8c..0f7e3a5 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -5,7 +5,7 @@ import 'dart:typed_data'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:esys_flutter_share/esys_flutter_share.dart'; +import 'package:esys_flutter_share_plus/esys_flutter_share_plus.dart'; void main() => runApp(MaterialApp( home: MaterialApp( diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 0df9612..2aaeb05 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -17,7 +17,7 @@ dev_dependencies: flutter_test: sdk: flutter - esys_flutter_share: + esys_flutter_share_plus: path: ../ # For information on the generic Dart part of this file, see the diff --git a/lib/esys_flutter_share.dart b/lib/esys_flutter_share_plus.dart similarity index 100% rename from lib/esys_flutter_share.dart rename to lib/esys_flutter_share_plus.dart diff --git a/pubspec.yaml b/pubspec.yaml index 1e4d07e..7058504 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,8 +1,9 @@ -name: esys_flutter_share -description: A Flutter plugin for sharing images & text with other applications. +name: esys_flutter_share_plus +description: A Flutter plugin for sharing images & text with other applications. Fork by Innim version: 2.0.1 -author: ESYS GmbH -homepage: https://github.com/esysberlin/esys-flutter-share +homepage: https://github.com/Innim/esys-flutter-share +repository: https://github.com/Innim/esys-flutter-share +issue_tracker: https://github.com/Innim/esys-flutter-share/issues environment: sdk: ">=2.12.0 <3.0.0" From dab85d32ec1720949aca1999eb9ce07375de00f8 Mon Sep 17 00:00:00 2001 From: greymag Date: Mon, 21 Feb 2022 11:45:25 +0300 Subject: [PATCH 10/28] Update gitignore --- .gitignore | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index fcf48ea..0ec7457 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ -# Flutter/Dart/Pub related .DS_Store .dart_tool/ +.idea/ .packages .pub/ @@ -8,11 +8,18 @@ pubspec.lock build/ -# IntelliJ related -*.iml -*.ipr -*.iws -.idea/ - -# Visual Studio Code related +# VSCode settings .vscode/ + +android/.settings/ +android/.classpath +android/.project +example/android/.settings/ +example/android/.classpath +example/android/.project +example/android/app/.settings/ +example/android/app/.classpath +example/android/app/.project + +# FVM +.fvm/ \ No newline at end of file From 8fe9a8afb884638b72bc582c0293e83a2fda38f0 Mon Sep 17 00:00:00 2001 From: greymag Date: Mon, 21 Feb 2022 11:45:32 +0300 Subject: [PATCH 11/28] Remove redundant files. --- android/.idea/.name | 1 - android/.idea/caches/build_file_checksums.ser | Bin 493 -> 0 bytes android/.idea/codeStyles/Project.xml | 29 ------------- android/.idea/gradle.xml | 17 -------- android/.idea/misc.xml | 38 ------------------ android/.idea/modules.xml | 8 ---- android/.idea/runConfigurations.xml | 12 ------ 7 files changed, 105 deletions(-) delete mode 100644 android/.idea/.name delete mode 100644 android/.idea/caches/build_file_checksums.ser delete mode 100644 android/.idea/codeStyles/Project.xml delete mode 100644 android/.idea/gradle.xml delete mode 100644 android/.idea/misc.xml delete mode 100644 android/.idea/modules.xml delete mode 100644 android/.idea/runConfigurations.xml diff --git a/android/.idea/.name b/android/.idea/.name deleted file mode 100644 index c419cbc..0000000 --- a/android/.idea/.name +++ /dev/null @@ -1 +0,0 @@ -esys_flutter_share \ No newline at end of file diff --git a/android/.idea/caches/build_file_checksums.ser b/android/.idea/caches/build_file_checksums.ser deleted file mode 100644 index e20a885d12a9edcbc6f496d684c1f567ecf869e9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 493 zcmZ4UmVvdnh`~NNKUXg?FQq6yGexf?KR>5fFEb@IQ7^qHF(oHeub?PDD>b=9F91S2 zm1gFoxMk*~I%lLNXBU^|7Q2L-Ts|(GuF1r}nf0c10SK*8#oScM7POJcMS|7Lonol(M| z>1-7fTAW%`9FvlmmzkOq12rH95jq8_MJ1W3#ifM|bqs7EQ?AJN-0WxA#PYI%bHe;TV28+kdvRBm;(xP3{wxT@b;P`|J6VD in#c724Ud3s6U5_&JD)!9$#S1QBXpWT*^ir@T@?Ugzpmu~ diff --git a/android/.idea/codeStyles/Project.xml b/android/.idea/codeStyles/Project.xml deleted file mode 100644 index 30aa626..0000000 --- a/android/.idea/codeStyles/Project.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - - - \ No newline at end of file diff --git a/android/.idea/gradle.xml b/android/.idea/gradle.xml deleted file mode 100644 index 47bd81f..0000000 --- a/android/.idea/gradle.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/android/.idea/misc.xml b/android/.idea/misc.xml deleted file mode 100644 index b0c7b20..0000000 --- a/android/.idea/misc.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/android/.idea/modules.xml b/android/.idea/modules.xml deleted file mode 100644 index f9b4966..0000000 --- a/android/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/android/.idea/runConfigurations.xml b/android/.idea/runConfigurations.xml deleted file mode 100644 index 7f68460..0000000 --- a/android/.idea/runConfigurations.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - \ No newline at end of file From f47449dd96112c7b58f71b8ee835198e84fcffbe Mon Sep 17 00:00:00 2001 From: greymag Date: Mon, 21 Feb 2022 11:47:48 +0300 Subject: [PATCH 12/28] Use "platforms" instead of deprecated "androidPackage" and "pluginClass". --- pubspec.yaml | 44 ++++++-------------------------------------- 1 file changed, 6 insertions(+), 38 deletions(-) diff --git a/pubspec.yaml b/pubspec.yaml index 7058504..7379d64 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -13,43 +13,11 @@ dependencies: sdk: flutter path_provider: ^2.0.0 -# For information on the generic Dart part of this file, see the -# following page: https://www.dartlang.org/tools/pub/pubspec -# The following section is specific to Flutter. flutter: - # This section identifies this Flutter project as a plugin project. - # The androidPackage and pluginClass identifiers should not ordinarily - # be modified. They are used by the tooling to maintain consistency when - # adding or updating assets for this project. plugin: - androidPackage: de.esys.esysfluttershare - pluginClass: EsysFlutterSharePlugin - # To add assets to your plugin package, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg - # - # For details regarding assets in packages, see - # https://flutter.io/assets-and-images/#from-packages - # - # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.io/assets-and-images/#resolution-aware. - # To add custom fonts to your plugin package, add a fonts section here, - # in this "flutter" section. Each entry in this list should have a - # "family" key with the font family name, and a "fonts" key with a - # list giving the asset and other descriptors for the font. For - # example: - # fonts: - # - family: Schyler - # fonts: - # - asset: fonts/Schyler-Regular.ttf - # - asset: fonts/Schyler-Italic.ttf - # style: italic - # - family: Trajan Pro - # fonts: - # - asset: fonts/TrajanPro.ttf - # - asset: fonts/TrajanPro_Bold.ttf - # weight: 700 - # - # For details regarding fonts in packages, see - # https://flutter.io/custom-fonts/#from-packages + platforms: + android: + package: de.esys.esysfluttershare + pluginClass: EsysFlutterSharePlugin + ios: + pluginClass: EsysFlutterSharePlugin \ No newline at end of file From 2f8614f2e008254285404da9b2c937278773ba8b Mon Sep 17 00:00:00 2001 From: greymag Date: Mon, 21 Feb 2022 11:48:25 +0300 Subject: [PATCH 13/28] Min Flutter v2.0 --- pubspec.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/pubspec.yaml b/pubspec.yaml index 7379d64..e5cc2b6 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -7,6 +7,7 @@ issue_tracker: https://github.com/Innim/esys-flutter-share/issues environment: sdk: ">=2.12.0 <3.0.0" + flutter: ">=2.0.0" dependencies: flutter: From 237ee82f0e4c7f46cf28fd56d70d5e155671c15c Mon Sep 17 00:00:00 2001 From: greymag Date: Mon, 21 Feb 2022 16:22:59 +0300 Subject: [PATCH 14/28] Fixed: failed to run because native plugins wasn't rename. --- android/settings.gradle | 2 +- ios/Classes/EsysFlutterSharePlugin.m | 2 +- ...ys_flutter_share.podspec => esys_flutter_share_plus.podspec} | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename ios/{esys_flutter_share.podspec => esys_flutter_share_plus.podspec} (92%) diff --git a/android/settings.gradle b/android/settings.gradle index e9362d1..dc83e70 100644 --- a/android/settings.gradle +++ b/android/settings.gradle @@ -1 +1 @@ -rootProject.name = 'esys_flutter_share' +rootProject.name = 'esys_flutter_share_plus' diff --git a/ios/Classes/EsysFlutterSharePlugin.m b/ios/Classes/EsysFlutterSharePlugin.m index 7cbfc6d..bfbf406 100644 --- a/ios/Classes/EsysFlutterSharePlugin.m +++ b/ios/Classes/EsysFlutterSharePlugin.m @@ -1,5 +1,5 @@ #import "EsysFlutterSharePlugin.h" -#import +#import @implementation EsysFlutterSharePlugin + (void)registerWithRegistrar:(NSObject*)registrar { diff --git a/ios/esys_flutter_share.podspec b/ios/esys_flutter_share_plus.podspec similarity index 92% rename from ios/esys_flutter_share.podspec rename to ios/esys_flutter_share_plus.podspec index a2b96fd..191cbeb 100644 --- a/ios/esys_flutter_share.podspec +++ b/ios/esys_flutter_share_plus.podspec @@ -2,7 +2,7 @@ # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html # Pod::Spec.new do |s| - s.name = 'esys_flutter_share' + s.name = 'esys_flutter_share_plus' s.version = '0.0.1' s.summary = 'A new flutter plugin project.' s.description = <<-DESC From a396174c4d775111534b891af34eb78599593b61 Mon Sep 17 00:00:00 2001 From: greymag Date: Mon, 21 Feb 2022 16:23:35 +0300 Subject: [PATCH 15/28] Example: Updated Android. --- example/android/app/build.gradle | 2 +- .../de/esys/esysfluttershareexample/MainActivity.java | 9 +-------- example/android/build.gradle | 2 +- example/android/gradle/wrapper/gradle-wrapper.properties | 2 +- 4 files changed, 4 insertions(+), 11 deletions(-) diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle index b6f07a1..b2542b4 100644 --- a/example/android/app/build.gradle +++ b/example/android/app/build.gradle @@ -25,7 +25,7 @@ apply plugin: 'com.android.application' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" android { - compileSdkVersion 28 + compileSdkVersion 31 lintOptions { disable 'InvalidPackage' diff --git a/example/android/app/src/main/java/de/esys/esysfluttershareexample/MainActivity.java b/example/android/app/src/main/java/de/esys/esysfluttershareexample/MainActivity.java index 29ffb90..fe9481d 100644 --- a/example/android/app/src/main/java/de/esys/esysfluttershareexample/MainActivity.java +++ b/example/android/app/src/main/java/de/esys/esysfluttershareexample/MainActivity.java @@ -1,13 +1,6 @@ package de.esys.esysfluttershareexample; -import android.os.Bundle; -import io.flutter.app.FlutterActivity; -import io.flutter.plugins.GeneratedPluginRegistrant; +import io.flutter.embedding.android.FlutterActivity;; public class MainActivity extends FlutterActivity { - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - GeneratedPluginRegistrant.registerWith(this); - } } diff --git a/example/android/build.gradle b/example/android/build.gradle index bb8a303..fab3c2e 100644 --- a/example/android/build.gradle +++ b/example/android/build.gradle @@ -5,7 +5,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:3.2.1' + classpath 'com.android.tools.build:gradle:4.1.3' } } diff --git a/example/android/gradle/wrapper/gradle-wrapper.properties b/example/android/gradle/wrapper/gradle-wrapper.properties index 2819f02..90f271d 100644 --- a/example/android/gradle/wrapper/gradle-wrapper.properties +++ b/example/android/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip From c92e24d2fdf91da7086d26592dc11c4f4d9883ea Mon Sep 17 00:00:00 2001 From: greymag Date: Mon, 21 Feb 2022 16:23:59 +0300 Subject: [PATCH 16/28] Example: Create/update iOS files. --- example/ios/Flutter/AppFrameworkInfo.plist | 2 +- example/ios/Podfile | 70 ++++++------------- example/ios/Podfile.lock | 28 ++++++++ example/ios/Runner.xcodeproj/project.pbxproj | 45 +++++++----- .../xcshareddata/xcschemes/Runner.xcscheme | 2 +- 5 files changed, 82 insertions(+), 65 deletions(-) create mode 100644 example/ios/Podfile.lock diff --git a/example/ios/Flutter/AppFrameworkInfo.plist b/example/ios/Flutter/AppFrameworkInfo.plist index 9367d48..8d4492f 100644 --- a/example/ios/Flutter/AppFrameworkInfo.plist +++ b/example/ios/Flutter/AppFrameworkInfo.plist @@ -21,6 +21,6 @@ CFBundleVersion 1.0 MinimumOSVersion - 8.0 + 9.0 diff --git a/example/ios/Podfile b/example/ios/Podfile index 2dfb501..1e8c3c9 100644 --- a/example/ios/Podfile +++ b/example/ios/Podfile @@ -4,62 +4,38 @@ # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' -def parse_KV_file(file, separator='=') - file_abs_path = File.expand_path(file) - if !File.exists? file_abs_path - return []; +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches end - pods_ary = [] - skip_line_start_symbols = ["#", "/"] - File.foreach(file_abs_path) { |line| - next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ } - plugin = line.split(pattern=separator) - if plugin.length == 2 - podname = plugin[0].strip() - path = plugin[1].strip() - podpath = File.expand_path("#{path}", file_abs_path) - pods_ary.push({:name => podname, :path => podpath}); - else - puts "Invalid plugin specification: #{line}" - end - } - return pods_ary + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" end -target 'Runner' do - use_frameworks! +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) - # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock - # referring to absolute paths on developers' machines. - system('rm -rf .symlinks') - system('mkdir -p .symlinks/plugins') +flutter_ios_podfile_setup - # Flutter Pods - generated_xcode_build_settings = parse_KV_file('./Flutter/Generated.xcconfig') - if generated_xcode_build_settings.empty? - puts "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter packages get is executed first." - end - generated_xcode_build_settings.map { |p| - if p[:name] == 'FLUTTER_FRAMEWORK_DIR' - symlink = File.join('.symlinks', 'flutter') - File.symlink(File.dirname(p[:path]), symlink) - pod 'Flutter', :path => File.join(symlink, File.basename(p[:path])) - end - } +target 'Runner' do + use_frameworks! + use_modular_headers! - # Plugin Pods - plugin_pods = parse_KV_file('../.flutter-plugins') - plugin_pods.map { |p| - symlink = File.join('.symlinks', 'plugins', p[:name]) - File.symlink(p[:path], symlink) - pod p[:name], :path => File.join(symlink, 'ios') - } + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) end post_install do |installer| installer.pods_project.targets.each do |target| - target.build_configurations.each do |config| - config.build_settings['ENABLE_BITCODE'] = 'NO' - end + flutter_additional_ios_build_settings(target) end end diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock new file mode 100644 index 0000000..f9d9334 --- /dev/null +++ b/example/ios/Podfile.lock @@ -0,0 +1,28 @@ +PODS: + - esys_flutter_share_plus (0.0.1): + - Flutter + - Flutter (1.0.0) + - path_provider_ios (0.0.1): + - Flutter + +DEPENDENCIES: + - esys_flutter_share_plus (from `.symlinks/plugins/esys_flutter_share_plus/ios`) + - Flutter (from `Flutter`) + - path_provider_ios (from `.symlinks/plugins/path_provider_ios/ios`) + +EXTERNAL SOURCES: + esys_flutter_share_plus: + :path: ".symlinks/plugins/esys_flutter_share_plus/ios" + Flutter: + :path: Flutter + path_provider_ios: + :path: ".symlinks/plugins/path_provider_ios/ios" + +SPEC CHECKSUMS: + esys_flutter_share_plus: 302b73471e2686a9ce282898d1df5d6f4382edba + Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a + path_provider_ios: 7d7ce634493af4477d156294792024ec3485acd5 + +PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c + +COCOAPODS: 1.11.2 diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index 2de765a..d16d53b 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + objectVersion = 50; objects = { /* Begin PBXBuildFile section */ @@ -32,6 +32,8 @@ /* Begin PBXFileReference section */ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 26201889920F18FC0EE8103A /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + 2B56A6B0B506295147C54482 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; @@ -44,6 +46,7 @@ 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 9BB236F61766429B48517DC1 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + BEA10537A5AA0AC2E1EDDE31 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -69,6 +72,9 @@ 4204C137FD4F389FE8CF8C94 /* Pods */ = { isa = PBXGroup; children = ( + BEA10537A5AA0AC2E1EDDE31 /* Pods-Runner.debug.xcconfig */, + 26201889920F18FC0EE8103A /* Pods-Runner.release.xcconfig */, + 2B56A6B0B506295147C54482 /* Pods-Runner.profile.xcconfig */, ); name = Pods; sourceTree = ""; @@ -157,7 +163,7 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0940; + LastUpgradeCheck = 1300; ORGANIZATIONNAME = "The Chromium Authors"; TargetAttributes = { 97C146ED1CF9000F007C117D = { @@ -221,20 +227,18 @@ files = ( ); inputPaths = ( - "${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh", - "${PODS_ROOT}/../.symlinks/flutter/ios/Flutter.framework", - "${BUILT_PRODUCTS_DIR}/esys_flutter_share/esys_flutter_share.framework", - "${BUILT_PRODUCTS_DIR}/path_provider/path_provider.framework", + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh", + "${BUILT_PRODUCTS_DIR}/esys_flutter_share_plus/esys_flutter_share_plus.framework", + "${BUILT_PRODUCTS_DIR}/path_provider_ios/path_provider_ios.framework", ); name = "[CP] Embed Pods Frameworks"; outputPaths = ( - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/esys_flutter_share.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/path_provider.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/esys_flutter_share_plus.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/path_provider_ios.framework", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; 9740EEB61CF901F6004384FC /* Run Script */ = { @@ -344,7 +348,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; @@ -365,7 +369,10 @@ "$(PROJECT_DIR)/Flutter", ); INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); LIBRARY_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Flutter", @@ -424,7 +431,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -473,7 +480,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; @@ -496,7 +503,10 @@ "$(PROJECT_DIR)/Flutter", ); INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); LIBRARY_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Flutter", @@ -525,7 +535,10 @@ "$(PROJECT_DIR)/Flutter", ); INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); LIBRARY_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Flutter", diff --git a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 03f8387..3db53b6 100644 --- a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ Date: Mon, 21 Feb 2022 16:24:07 +0300 Subject: [PATCH 17/28] v2.1.0 --- CHANGELOG.md | 5 +++++ pubspec.yaml | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ed4722f..4a3ede3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## 2.1.0 + +* Published as `esys_flutter_share_plus`. +* `compileSdkVersion` upgraded to 31. + ## 2.0.1 * migrate to V2 diff --git a/pubspec.yaml b/pubspec.yaml index e5cc2b6..4944a50 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: esys_flutter_share_plus description: A Flutter plugin for sharing images & text with other applications. Fork by Innim -version: 2.0.1 +version: 2.1.0 homepage: https://github.com/Innim/esys-flutter-share repository: https://github.com/Innim/esys-flutter-share issue_tracker: https://github.com/Innim/esys-flutter-share/issues @@ -12,7 +12,7 @@ environment: dependencies: flutter: sdk: flutter - path_provider: ^2.0.0 + path_provider: ^2.0.9 flutter: plugin: From 71198ea933ea65bdd5fc9da783b9e938adb7eb81 Mon Sep 17 00:00:00 2001 From: "s.t.o.k.a.t.o" Date: Wed, 20 Jul 2022 14:57:32 +0300 Subject: [PATCH 18/28] Fixed bug by granting permission. So now granting permission for the uri for each resolvable application. --- CHANGELOG.md | 4 ++++ .../esysfluttershare/EsysFlutterSharePlugin.java | 14 ++++++++++++++ pubspec.yaml | 2 +- 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a3ede3..b514999 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.1.1 + +* Fixed bug by granting permission. So now granting permission for the uri for each resolvable application. + ## 2.1.0 * Published as `esys_flutter_share_plus`. diff --git a/android/src/main/java/de/esys/esysfluttershare/EsysFlutterSharePlugin.java b/android/src/main/java/de/esys/esysfluttershare/EsysFlutterSharePlugin.java index 5e3cfc7..169d703 100644 --- a/android/src/main/java/de/esys/esysfluttershare/EsysFlutterSharePlugin.java +++ b/android/src/main/java/de/esys/esysfluttershare/EsysFlutterSharePlugin.java @@ -93,6 +93,12 @@ private void file(Object arguments) { Intent chooserIntent = Intent.createChooser(shareIntent, title); chooserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + List resInfoList = activeContext.getPackageManager().queryIntentActivities(chooserIntent, PackageManager.MATCH_DEFAULT_ONLY); + + for (ResolveInfo resolveInfo : resInfoList) { + String packageName = resolveInfo.activityInfo.packageName; + activeContext.grantUriPermission(packageName, contentUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION); + } activeContext.startActivity(chooserIntent); } @@ -128,6 +134,14 @@ private void files(Object arguments) { chooserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + List resInfoList = activeContext.getPackageManager().queryIntentActivities(chooserIntent, PackageManager.MATCH_DEFAULT_ONLY); + + for (ResolveInfo resolveInfo : resInfoList) { + String packageName = resolveInfo.activityInfo.packageName; + for(Uri uri: contentUris){ + activeContext.grantUriPermission(packageName, uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION); + } + } activeContext.startActivity(chooserIntent); } } \ No newline at end of file diff --git a/pubspec.yaml b/pubspec.yaml index 4944a50..88cc017 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: esys_flutter_share_plus description: A Flutter plugin for sharing images & text with other applications. Fork by Innim -version: 2.1.0 +version: 2.1.1 homepage: https://github.com/Innim/esys-flutter-share repository: https://github.com/Innim/esys-flutter-share issue_tracker: https://github.com/Innim/esys-flutter-share/issues From b39ac8d657e302ff55644e4f007ef43cd4cc97d4 Mon Sep 17 00:00:00 2001 From: Maxim Date: Fri, 12 Aug 2022 14:58:41 +0300 Subject: [PATCH 19/28] Fix share file with text. When the text with one file was not shown. (#3) Fix share file with text. When the text with one file was not shown. Detailed file type processing. --- CHANGELOG.md | 6 ++ .../EsysFlutterSharePlugin.java | 65 ++++++++++++++++--- example/lib/main.dart | 15 +++-- lib/esys_flutter_share_plus.dart | 15 ++++- pubspec.yaml | 2 +- 5 files changed, 84 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b514999..a5eb4fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## 2.2.0 + +* Fix share file with text. When the text with one file was not shown. +* Detailed file type processing. +* **Breaking change**. To `files()` you need to pass the `mimeType` array. + ## 2.1.1 * Fixed bug by granting permission. So now granting permission for the uri for each resolvable application. diff --git a/android/src/main/java/de/esys/esysfluttershare/EsysFlutterSharePlugin.java b/android/src/main/java/de/esys/esysfluttershare/EsysFlutterSharePlugin.java index 169d703..5e4f822 100644 --- a/android/src/main/java/de/esys/esysfluttershare/EsysFlutterSharePlugin.java +++ b/android/src/main/java/de/esys/esysfluttershare/EsysFlutterSharePlugin.java @@ -109,13 +109,11 @@ private void files(Object arguments) { @SuppressWarnings("unchecked") ArrayList names = (ArrayList) argsMap.get("names"); - String mimeType = (String) argsMap.get("mimeType"); + ArrayList mimeTypes = (ArrayList) argsMap.get("mimeTypes"); String text = (String) argsMap.get("text"); Context activeContext = binding.getApplicationContext(); - - Intent shareIntent = new Intent(Intent.ACTION_SEND_MULTIPLE); - shareIntent.setType(mimeType); + Intent shareIntent = new Intent(); ArrayList contentUris = new ArrayList<>(); @@ -125,15 +123,22 @@ private void files(Object arguments) { Uri contentUri = FileProvider.getUriForFile(activeContext, fileProviderAuthority, file); contentUris.add(contentUri); } + + if (contentUris.size() == 1) { + shareIntent.setAction(Intent.ACTION_SEND); + shareIntent.putExtra(Intent.EXTRA_STREAM, contentUris.get(0)); + } else { + shareIntent.setAction(Intent.ACTION_SEND_MULTIPLE); + shareIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, contentUris); + } - shareIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, contentUris); - // add optional text - if (!text.isEmpty()) shareIntent.putExtra(Intent.EXTRA_TEXT, text); + String mimeType = reduceMimeTypes(mimeTypes); + shareIntent.setType(mimeType); + if (!text.isEmpty()) shareIntent.putExtra(Intent.EXTRA_TEXT, text); + Intent chooserIntent = Intent.createChooser(shareIntent, title); - chooserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - List resInfoList = activeContext.getPackageManager().queryIntentActivities(chooserIntent, PackageManager.MATCH_DEFAULT_ONLY); for (ResolveInfo resolveInfo : resInfoList) { @@ -142,6 +147,48 @@ private void files(Object arguments) { activeContext.grantUriPermission(packageName, uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION); } } + chooserIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); activeContext.startActivity(chooserIntent); } + + /** + * Reduces provided MIME types to a common one to provide [Intent] with a correct type + * to share multiple files + */ + private String reduceMimeTypes(ArrayList mimeTypes) { + String reducedMimeType = "*/*"; + int size = mimeTypes.size(); + + if (size == 1) { + reducedMimeType = mimeTypes.get(0); + } else if (size > 1) { + String commonMimeType = mimeTypes.get(0); + String commonMimeTypeBase = getMimeTypeBase(commonMimeType); + for (int i = 1; i < size; ++i) { + String iterabelType = mimeTypes.get(i); + if (!commonMimeType.equals(iterabelType)) { + String iterableTypeBase = getMimeTypeBase(iterabelType); + if (commonMimeTypeBase == iterableTypeBase) { + commonMimeType = iterableTypeBase + "/*"; + } else { + commonMimeType = "*/*"; + break; + } + } + } + reducedMimeType = commonMimeType; + } + return reducedMimeType; + } + + /** + * Returns the first part of provided MIME type, which comes before '/' symbol + */ + private String getMimeTypeBase(String mimeType) { + if (mimeType == null || !mimeType.contains("/")) { + return "*"; + } else { + return mimeType.substring(0, mimeType.indexOf("/")); + } + } } \ No newline at end of file diff --git a/example/lib/main.dart b/example/lib/main.dart index 0f7e3a5..f670f2a 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -89,12 +89,13 @@ class _MyHomePageState extends State { final ByteData bytes2 = await rootBundle.load('assets/image2.png'); await Share.files( - 'esys images', - { - 'esys.png': bytes1.buffer.asUint8List(), - 'bluedan.png': bytes2.buffer.asUint8List(), - }, - 'image/png'); + 'esys images', + { + 'esys.png': bytes1.buffer.asUint8List(), + 'bluedan.png': bytes2.buffer.asUint8List(), + }, + {'image/png'}, + ); } catch (e) { print('error: $e'); } @@ -123,7 +124,7 @@ class _MyHomePageState extends State { 'bluedan.png': bytes2.buffer.asUint8List(), 'addresses.csv': bytes3.buffer.asUint8List(), }, - '*/*', + {'*/*'}, text: 'My optional text.'); } catch (e) { print('error: $e'); diff --git a/lib/esys_flutter_share_plus.dart b/lib/esys_flutter_share_plus.dart index fb92a24..b3ea480 100644 --- a/lib/esys_flutter_share_plus.dart +++ b/lib/esys_flutter_share_plus.dart @@ -37,13 +37,24 @@ class Share { } /// Sends multiple files to other apps. + /// + /// The optional `mimeTypes` parameter can be used to specify MIME types for + /// the provided files. + /// Android supports all natively available MIME types (wildcards like image/* + /// are also supported) and it's considered best practice to avoid mixing + /// unrelated file types (eg. image/jpg & application/pdf). If MIME types are + /// mixed the plugin attempts to find the lowest common denominator. Even + /// if MIME types are supplied the receiving app decides if those are used + /// or handled. + /// On iOS image/jpg, image/jpeg and image/png are handled as images, while + /// every other MIME type is considered a normal file. static Future files( - String title, Map> files, String mimeType, + String title, Map> files, Set mimeTypes, {String text = ''}) async { Map argsMap = { 'title': '$title', 'names': files.entries.toList().map((x) => x.key).toList(), - 'mimeType': mimeType, + 'mimeTypes': mimeTypes.toList(), 'text': '$text' }; diff --git a/pubspec.yaml b/pubspec.yaml index 88cc017..cbd390e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: esys_flutter_share_plus description: A Flutter plugin for sharing images & text with other applications. Fork by Innim -version: 2.1.1 +version: 2.2.0 homepage: https://github.com/Innim/esys-flutter-share repository: https://github.com/Innim/esys-flutter-share issue_tracker: https://github.com/Innim/esys-flutter-share/issues From 3163310e72113838087dcbae8bfb3116b0fd4c2e Mon Sep 17 00:00:00 2001 From: Lucas Krause <60433542+krausecloudcrm@users.noreply.github.com> Date: Wed, 4 Dec 2024 10:04:45 -0300 Subject: [PATCH 20/28] Update build.gradle (#4) define namespace --- android/build.gradle | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/android/build.gradle b/android/build.gradle index 0bc34ba..1775c8b 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -22,6 +22,7 @@ rootProject.allprojects { apply plugin: 'com.android.library' android { + namespace "de.esys.esysfluttershare" compileSdkVersion 28 defaultConfig { @@ -35,4 +36,4 @@ android { dependencies { implementation 'androidx.legacy:legacy-support-v4:1.0.0-beta01' -} \ No newline at end of file +} From 039fec36bc8f5a0a2ec00345f642fde6a6a0c53b Mon Sep 17 00:00:00 2001 From: Alexander <60105225+Vabiel@users.noreply.github.com> Date: Wed, 4 Dec 2024 16:27:10 +0300 Subject: [PATCH 21/28] Out of memory fix (#5) * Refactoring: - Fixed potential memory issues when using methods that accept byte arrays. - New Methods Added: - fileFromStorage() and filesFromStorage() (for sharing files, especially large ones). - fileFromMemory() and filesFromMemory() (for sharing small files using byte arrays). - file() and files() are now deprecated methods. * v2.3.0 * Revert deleted info about MIME type * Add extended documentation for filesFromMemory(). --- CHANGELOG.md | 8 ++ README.md | 38 ++++++-- example/lib/main.dart | 13 ++- lib/esys_flutter_share_plus.dart | 148 ++++++++++++++++++++++++++----- pubspec.yaml | 2 +- 5 files changed, 175 insertions(+), 34 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a5eb4fe..8f90372 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +## 2.3.0 + +* **Added** new methods `fileFromMemory()` and `filesFromMemory()` for sharing small files using byte arrays. These methods should be used cautiously and are **not recommended for large files** due to potential memory issues. +* **Added** new methods `fileFromStorage()` and `filesFromStorage()` for sharing files using file paths. These methods are **recommended** for general use, especially with large files, to avoid memory-related errors. +* **Deprecated** methods `file()` and `files()`. It is recommended to use `fileFromStorage()` and `filesFromStorage()` instead. For small files, `fileFromMemory()` and `filesFromMemory()` can be used, but they are not recommended for large files due to potential memory issues. +* **Updated documentation** to clearly state the intended use cases for each method and to guide users toward the recommended approaches. +* **Breaking change**: If you are using the deprecated methods `file()` and `files()`, please switch to the new methods to avoid possible memory issues. + ## 2.2.0 * Fix share file with text. When the text with one file was not shown. diff --git a/README.md b/README.md index 8fb0a99..156aff1 100644 --- a/README.md +++ b/README.md @@ -44,21 +44,49 @@ Share text: Share.text('my text title', 'This is my text to share with other applications.', 'text/plain'); ``` -Share file: +Share File from Storage (Recommended): +**Note:** This method is recommended for sharing files, especially large files, to avoid potential memory issues. + +```dart +await EsysFlutterShare.fileFromStorage( + 'Share File', + 'example.pdf', + '/path/to/your/example.pdf', + 'application/pdf', + text: 'Check out this file!', +); +``` + +Share File from Memory (Use with Caution): +**Warning:** Use this method only for small files. For large files, use fileFromStorage to avoid potential out-of-memory errors. ```dart final ByteData bytes = await rootBundle.load('assets/image1.png'); -await Share.file('esys image', 'esys.png', bytes.buffer.asUint8List(), 'image/png', text: 'My optional text.'); +await Share.fileFromMemory('esys image', 'esys.png', bytes.buffer.asUint8List(), 'image/png', text: 'My optional text.'); +``` + +Share Multiple Files from Storage (Recommended): + +```dart +await EsysFlutterShare.filesFromStorage( + 'Share Files', + { + 'image1.png': '/path/to/your/image1.png', + 'document.pdf': '/path/to/your/document.pdf', + }, + {'image/png', 'application/pdf'}, + text: 'Here are some files!', +); ``` -Share files: +Share Multiple Files from Memory (Use with Caution): ```dart final ByteData bytes1 = await rootBundle.load('assets/image1.png'); final ByteData bytes2 = await rootBundle.load('assets/image2.png'); final ByteData bytes3 = await rootBundle.load('assets/addresses.csv'); -await Share.files( +await Share.filesFromMemory( 'esys images', { 'esys.png': bytes1.buffer.asUint8List(), @@ -75,7 +103,7 @@ Share file from url: var request = await HttpClient().getUrl(Uri.parse('https://shop.esys.eu/media/image/6f/8f/af/amlog_transport-berwachung.jpg')); var response = await request.close(); Uint8List bytes = await consolidateHttpClientResponseBytes(response); -await Share.file('ESYS AMLOG', 'amlog.jpg', bytes, 'image/jpg'); +await Share.fileFromMemory('ESYS AMLOG', 'amlog.jpg', bytes, 'image/jpg'); ``` Check out the example app in the Repository for further information. diff --git a/example/lib/main.dart b/example/lib/main.dart index f670f2a..8b8c84b 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,6 +1,5 @@ import 'dart:async'; import 'dart:io'; -import 'dart:typed_data'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; @@ -75,7 +74,7 @@ class _MyHomePageState extends State { Future _shareImage() async { try { final ByteData bytes = await rootBundle.load('assets/image1.png'); - await Share.file( + await Share.fileFromMemory( 'esys image', 'esys.png', bytes.buffer.asUint8List(), 'image/png', text: 'My optional text.'); } catch (e) { @@ -88,7 +87,7 @@ class _MyHomePageState extends State { final ByteData bytes1 = await rootBundle.load('assets/image1.png'); final ByteData bytes2 = await rootBundle.load('assets/image2.png'); - await Share.files( + await Share.filesFromMemory( 'esys images', { 'esys.png': bytes1.buffer.asUint8List(), @@ -104,7 +103,7 @@ class _MyHomePageState extends State { Future _shareCSV() async { try { final ByteData bytes = await rootBundle.load('assets/addresses.csv'); - await Share.file( + await Share.fileFromMemory( 'addresses', 'addresses.csv', bytes.buffer.asUint8List(), 'text/csv'); } catch (e) { print('error: $e'); @@ -117,7 +116,7 @@ class _MyHomePageState extends State { final ByteData bytes2 = await rootBundle.load('assets/image2.png'); final ByteData bytes3 = await rootBundle.load('assets/addresses.csv'); - await Share.files( + await Share.filesFromMemory( 'esys images', { 'esys.png': bytes1.buffer.asUint8List(), @@ -137,7 +136,7 @@ class _MyHomePageState extends State { 'https://shop.esys.eu/media/image/6f/8f/af/amlog_transport-berwachung.jpg')); var response = await request.close(); Uint8List bytes = await consolidateHttpClientResponseBytes(response); - await Share.file('ESYS AMLOG', 'amlog.jpg', bytes, 'image/jpg'); + await Share.fileFromMemory('ESYS AMLOG', 'amlog.jpg', bytes, 'image/jpg'); } catch (e) { print('error: $e'); } @@ -146,7 +145,7 @@ class _MyHomePageState extends State { Future _shareSound() async { try { final ByteData bytes = await rootBundle.load('assets/cat.mp3'); - await Share.file( + await Share.fileFromMemory( 'Sound', 'cat.mp3', bytes.buffer.asUint8List(), 'audio/*'); } catch (e) { print('error: $e'); diff --git a/lib/esys_flutter_share_plus.dart b/lib/esys_flutter_share_plus.dart index b3ea480..d9f05c2 100644 --- a/lib/esys_flutter_share_plus.dart +++ b/lib/esys_flutter_share_plus.dart @@ -11,33 +11,73 @@ class Share { /// Sends a text to other apps. static void text(String title, String text, String mimeType) { Map argsMap = { - 'title': '$title', - 'text': '$text', - 'mimeType': '$mimeType' + 'title': title, + 'text': text, + 'mimeType': mimeType }; _channel.invokeMethod('text', argsMap); } /// Sends a file to other apps. + /// + /// **Note:** It's recommended to use [fileFromStorage] for better performance + /// and to avoid potential memory issues. Use this method only for small files. + @Deprecated( + 'Use fileFromStorage instead. For small files, you can use fileFromMemory(), which is not recommended for large files due to memory constraints.') static Future file( - String title, String name, List bytes, String mimeType, - {String text = ''}) async { - Map argsMap = { - 'title': '$title', - 'name': '$name', - 'mimeType': '$mimeType', - 'text': '$text' + String title, + String name, + List bytes, + String mimeType, { + String text = '', + }) async { + await fileFromMemory(title, name, bytes, mimeType, text: text); + } + + /// Sends multiple files to other apps. + /// + /// **Note:** It's recommended to use [filesFromStorage] for better performance + /// and to avoid potential memory issues. Use this method only for small files. + @Deprecated( + 'Use filesFromStorage instead. For small files, you can use filesFromMemory(), which is not recommended for large files due to memory constraints.') + static Future files( + String title, + Map> files, + Set mimeTypes, { + String text = '', + }) async { + await filesFromMemory(title, files, mimeTypes, text: text); + } + + /// Sends a file to other apps from memory. + /// + /// **Warning:** Use this method only for small files. For large files, use [fileFromStorage] + /// to avoid potential out of memory errors. + static Future fileFromMemory( + String title, + String name, + List bytes, + String mimeType, { + String text = '', + }) async { + Map argsMap = { + 'title': title, + 'name': name, + 'mimeType': mimeType, + 'text': text }; final tempDir = await getTemporaryDirectory(); - final file = await new File('${tempDir.path}/$name').create(); + final file = await File('${tempDir.path}/$name').create(); await file.writeAsBytes(bytes); _channel.invokeMethod('file', argsMap); } - /// Sends multiple files to other apps. - /// + /// Sends multiple files to other apps from memory. + /// + /// **Warning:** Use this method only for small files. For large files, use [filesFromStorage] + /// to avoid potential out of memory errors. /// The optional `mimeTypes` parameter can be used to specify MIME types for /// the provided files. /// Android supports all natively available MIME types (wildcards like image/* @@ -48,23 +88,89 @@ class Share { /// or handled. /// On iOS image/jpg, image/jpeg and image/png are handled as images, while /// every other MIME type is considered a normal file. - static Future files( - String title, Map> files, Set mimeTypes, - {String text = ''}) async { - Map argsMap = { - 'title': '$title', - 'names': files.entries.toList().map((x) => x.key).toList(), + static Future filesFromMemory( + String title, + Map> files, + Set mimeTypes, { + String text = '', + }) async { + Map argsMap = { + 'title': title, + 'names': files.keys.toList(), 'mimeTypes': mimeTypes.toList(), - 'text': '$text' + 'text': text }; final tempDir = await getTemporaryDirectory(); for (var entry in files.entries) { - final file = await new File('${tempDir.path}/${entry.key}').create(); + final file = await File('${tempDir.path}/${entry.key}').create(); await file.writeAsBytes(entry.value); } _channel.invokeMethod('files', argsMap); } + + /// Sends a file to other apps using a file path. + /// + /// This method is recommended for sharing files to avoid memory issues. + static Future fileFromStorage( + String title, + String name, + String filePath, + String mimeType, { + String text = '', + }) async { + Map argsMap = { + 'title': title, + 'name': name, + 'mimeType': mimeType, + 'text': text + }; + + final tempDir = await getTemporaryDirectory(); + final sourceFile = File(filePath); + final destFile = await File('${tempDir.path}/$name').create(); + + await sourceFile.copy(destFile.path); + + _channel.invokeMethod('file', argsMap); + } + + /// Sends multiple files to other apps using file paths. + /// + /// This method is recommended for sharing files to avoid memory issues. + /// The optional `mimeTypes` parameter can be used to specify MIME types for + /// the provided files. + /// Android supports all natively available MIME types (wildcards like image/* + /// are also supported) and it's considered best practice to avoid mixing + /// unrelated file types (eg. image/jpg & application/pdf). If MIME types are + /// mixed the plugin attempts to find the lowest common denominator. Even + /// if MIME types are supplied the receiving app decides if those are used + /// or handled. + /// On iOS image/jpg, image/jpeg and image/png are handled as images, while + /// every other MIME type is considered a normal file. + static Future filesFromStorage( + String title, + Map files, + Set mimeTypes, { + String text = '', + }) async { + Map argsMap = { + 'title': title, + 'names': files.keys.toList(), + 'mimeTypes': mimeTypes.toList(), + 'text': text + }; + + final tempDir = await getTemporaryDirectory(); + + for (var entry in files.entries) { + final sourceFile = File(entry.value); + final destFile = await File('${tempDir.path}/${entry.key}').create(); + await sourceFile.copy(destFile.path); + } + + _channel.invokeMethod('files', argsMap); + } } diff --git a/pubspec.yaml b/pubspec.yaml index cbd390e..81ee03c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: esys_flutter_share_plus description: A Flutter plugin for sharing images & text with other applications. Fork by Innim -version: 2.2.0 +version: 2.3.0 homepage: https://github.com/Innim/esys-flutter-share repository: https://github.com/Innim/esys-flutter-share issue_tracker: https://github.com/Innim/esys-flutter-share/issues From 92358122f0dd13c72542a7687f89df521b574389 Mon Sep 17 00:00:00 2001 From: SF97 Date: Wed, 4 Dec 2024 18:47:29 +0500 Subject: [PATCH 22/28] Update CHANGELOG.md --- CHANGELOG.md | 1 + example/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f90372..bb11819 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ * **Added** new methods `fileFromMemory()` and `filesFromMemory()` for sharing small files using byte arrays. These methods should be used cautiously and are **not recommended for large files** due to potential memory issues. * **Added** new methods `fileFromStorage()` and `filesFromStorage()` for sharing files using file paths. These methods are **recommended** for general use, especially with large files, to avoid memory-related errors. +* **Added** explicit namespace declaration for compatibility with latest Android Gradle Plugin. * **Deprecated** methods `file()` and `files()`. It is recommended to use `fileFromStorage()` and `filesFromStorage()` instead. For small files, `fileFromMemory()` and `filesFromMemory()` can be used, but they are not recommended for large files due to potential memory issues. * **Updated documentation** to clearly state the intended use cases for each method and to guide users toward the recommended approaches. * **Breaking change**: If you are using the deprecated methods `file()` and `files()`, please switch to the new methods to avoid possible memory issues. diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 2aaeb05..c15dcec 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -11,7 +11,7 @@ dependencies: # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. - cupertino_icons: ^0.1.2 + cupertino_icons: ^1.0.1 dev_dependencies: flutter_test: From 9cca0b3098d8a774ae3881edba3bc38eff4089ba Mon Sep 17 00:00:00 2001 From: greymag Date: Wed, 4 Dec 2024 15:02:38 +0100 Subject: [PATCH 23/28] update constraint --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 81ee03c..a3a47d3 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -6,7 +6,7 @@ repository: https://github.com/Innim/esys-flutter-share issue_tracker: https://github.com/Innim/esys-flutter-share/issues environment: - sdk: ">=2.12.0 <3.0.0" + sdk: ">=2.12.0 <4.0.0" flutter: ">=2.0.0" dependencies: From b7430486d1f70283759789a241c56bb5688f233a Mon Sep 17 00:00:00 2001 From: Maksim <69686849+ulezkin@users.noreply.github.com> Date: Fri, 8 Aug 2025 18:00:06 +0300 Subject: [PATCH 24/28] =?UTF-8?q?Added=20new=20method=20`deleteTempShareFi?= =?UTF-8?q?lesByExtension`=20for=20removing=20tempo=E2=80=A6=20(#6)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Added new method `deleteTempShareFilesByExtension` for removing temporary files created by`filesFromStorage` and `fileFromStorage`. Implemented automatic deletion of temporary files created in `filesFromStorage` and `fileFromStorage` after sharing is completed (when the share window is closed). * Added init() method. Update readme. * Create temp share dir if not exists. * Add random string to path for temp share files. * Refactor. * Delete recursive flags. * wrong _initialise field type. --------- Co-authored-by: ulezkin --- CHANGELOG.md | 33 +++++-- README.md | 7 ++ .../EsysFlutterSharePlugin.java | 98 +++++++++++++------ example/lib/main.dart | 7 ++ ios/Classes/SwiftEsysFlutterSharePlugin.swift | 47 +++++---- lib/esys_flutter_share_plus.dart | 74 ++++++++++++-- pubspec.yaml | 2 +- 7 files changed, 201 insertions(+), 67 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bb11819..b4ab72a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,26 @@ +## 2.4.0 + +* **Added** new method `init()` for initializing the Share plugin and cleaning up temporary files. + This method should be called at app startup or before starting to work with sharing. +* Implemented automatic deletion of temporary files created in `filesFromStorage` and + `fileFromStorage` after sharing is completed (when the share window is closed). + ## 2.3.0 -* **Added** new methods `fileFromMemory()` and `filesFromMemory()` for sharing small files using byte arrays. These methods should be used cautiously and are **not recommended for large files** due to potential memory issues. -* **Added** new methods `fileFromStorage()` and `filesFromStorage()` for sharing files using file paths. These methods are **recommended** for general use, especially with large files, to avoid memory-related errors. +* **Added** new methods `fileFromMemory()` and `filesFromMemory()` for sharing small files using + byte arrays. These methods should be used cautiously and are **not recommended for large files** + due to potential memory issues. +* **Added** new methods `fileFromStorage()` and `filesFromStorage()` for sharing files using file + paths. These methods are **recommended** for general use, especially with large files, to avoid + memory-related errors. * **Added** explicit namespace declaration for compatibility with latest Android Gradle Plugin. -* **Deprecated** methods `file()` and `files()`. It is recommended to use `fileFromStorage()` and `filesFromStorage()` instead. For small files, `fileFromMemory()` and `filesFromMemory()` can be used, but they are not recommended for large files due to potential memory issues. -* **Updated documentation** to clearly state the intended use cases for each method and to guide users toward the recommended approaches. -* **Breaking change**: If you are using the deprecated methods `file()` and `files()`, please switch to the new methods to avoid possible memory issues. +* **Deprecated** methods `file()` and `files()`. It is recommended to use `fileFromStorage()` and + `filesFromStorage()` instead. For small files, `fileFromMemory()` and `filesFromMemory()` can be + used, but they are not recommended for large files due to potential memory issues. +* **Updated documentation** to clearly state the intended use cases for each method and to guide + users toward the recommended approaches. +* **Breaking change**: If you are using the deprecated methods `file()` and `files()`, please switch + to the new methods to avoid possible memory issues. ## 2.2.0 @@ -15,7 +30,8 @@ ## 2.1.1 -* Fixed bug by granting permission. So now granting permission for the uri for each resolvable application. +* Fixed bug by granting permission. So now granting permission for the uri for each resolvable + application. ## 2.1.0 @@ -51,7 +67,10 @@ ## 0.0.9 -* Breaking change. Migrate from the deprecated original Android Support Library to AndroidX. This shouldn't result in any functional changes, but it requires any Android apps using this plugin to [also migrate](https://developer.android.com/jetpack/androidx/migrate) if they're using the original support library. +* Breaking change. Migrate from the deprecated original Android Support Library to AndroidX. This + shouldn't result in any functional changes, but it requires any Android apps using this plugin + to [also migrate](https://developer.android.com/jetpack/androidx/migrate) if they're using the + original support library. ## 0.0.8 diff --git a/README.md b/README.md index 156aff1..dc07e35 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,13 @@ Import: import 'package:esys_flutter_share_plus/esys_flutter_share_plus.dart'; ``` +Initialize the plugin (required): + +```dart +// Call this method at app startup or before starting to work with sharing +await Share.init(); +``` + Share text: ```dart diff --git a/android/src/main/java/de/esys/esysfluttershare/EsysFlutterSharePlugin.java b/android/src/main/java/de/esys/esysfluttershare/EsysFlutterSharePlugin.java index 5e4f822..55d2749 100644 --- a/android/src/main/java/de/esys/esysfluttershare/EsysFlutterSharePlugin.java +++ b/android/src/main/java/de/esys/esysfluttershare/EsysFlutterSharePlugin.java @@ -19,14 +19,22 @@ import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.MethodChannel.MethodCallHandler; import io.flutter.plugin.common.MethodChannel.Result; +import android.app.Activity; +import android.content.IntentSender; +import io.flutter.embedding.engine.plugins.activity.ActivityAware; +import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding; +import io.flutter.plugin.common.PluginRegistry; /** EsysfluttersharePlugin */ -public class EsysFlutterSharePlugin implements FlutterPlugin, MethodCallHandler { +public class EsysFlutterSharePlugin implements FlutterPlugin, MethodCallHandler, ActivityAware, PluginRegistry.ActivityResultListener { private final String PROVIDER_AUTH_EXT = ".fileprovider.github.com/orgs/esysberlin/esys-flutter-share"; + private static final int SHARE_REQUEST_CODE = 9023; private MethodChannel channel; private FlutterPluginBinding binding; + private Activity activity; + private Result pendingResult; @Override public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) { @@ -38,13 +46,13 @@ public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBindin @Override public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) { if (call.method.equals("text")) { - text(call.arguments); + text(call.arguments, result); } if (call.method.equals("file")) { - file(call.arguments); + file(call.arguments, result); } if (call.method.equals("files")) { - files(call.arguments); + files(call.arguments, result); } } @@ -53,77 +61,104 @@ public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) { channel.setMethodCallHandler(null); } - private void text(Object arguments) { + @Override + public void onAttachedToActivity(ActivityPluginBinding binding) { + this.activity = binding.getActivity(); + binding.addActivityResultListener(this); + } + + @Override + public void onDetachedFromActivityForConfigChanges() { + this.activity = null; + } + + @Override + public void onReattachedToActivityForConfigChanges(ActivityPluginBinding binding) { + this.activity = binding.getActivity(); + binding.addActivityResultListener(this); + } + + @Override + public void onDetachedFromActivity() { + this.activity = null; + } + + @Override + public boolean onActivityResult(int requestCode, int resultCode, Intent data) { + if (requestCode == SHARE_REQUEST_CODE && pendingResult != null) { + boolean success = (resultCode == Activity.RESULT_OK); + pendingResult.success(success); + pendingResult = null; + return true; + } + return false; + } + + private void text(Object arguments, Result result) { @SuppressWarnings("unchecked") HashMap argsMap = (HashMap) arguments; String title = argsMap.get("title"); String text = argsMap.get("text"); String mimeType = argsMap.get("mimeType"); - - Context activeContext = binding.getApplicationContext(); - Intent shareIntent = new Intent(Intent.ACTION_SEND); - shareIntent.setType(mimeType); shareIntent.putExtra(Intent.EXTRA_TEXT, text); Intent chooserIntent = Intent.createChooser(shareIntent, title); - chooserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); chooserIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); - activeContext.startActivity(chooserIntent); + if (activity != null) { + pendingResult = result; + activity.startActivityForResult(chooserIntent, SHARE_REQUEST_CODE); + } else { + result.error("NO_ACTIVITY", "No foreground activity", null); + } } - private void file(Object arguments) { + private void file(Object arguments, Result result) { @SuppressWarnings("unchecked") HashMap argsMap = (HashMap) arguments; String title = argsMap.get("title"); String name = argsMap.get("name"); String mimeType = argsMap.get("mimeType"); String text = argsMap.get("text"); - Context activeContext = binding.getApplicationContext(); - Intent shareIntent = new Intent(Intent.ACTION_SEND); shareIntent.setType(mimeType); File file = new File(activeContext.getCacheDir(), name); String fileProviderAuthority = activeContext.getPackageName() + PROVIDER_AUTH_EXT; Uri contentUri = FileProvider.getUriForFile(activeContext, fileProviderAuthority, file); shareIntent.putExtra(Intent.EXTRA_STREAM, contentUri); - // add optional text if (!text.isEmpty()) shareIntent.putExtra(Intent.EXTRA_TEXT, text); Intent chooserIntent = Intent.createChooser(shareIntent, title); - chooserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - List resInfoList = activeContext.getPackageManager().queryIntentActivities(chooserIntent, PackageManager.MATCH_DEFAULT_ONLY); - for (ResolveInfo resolveInfo : resInfoList) { String packageName = resolveInfo.activityInfo.packageName; activeContext.grantUriPermission(packageName, contentUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION); } - activeContext.startActivity(chooserIntent); + if (activity != null) { + pendingResult = result; + activity.startActivityForResult(chooserIntent, SHARE_REQUEST_CODE); + } else { + result.error("NO_ACTIVITY", "No foreground activity", null); + } } - private void files(Object arguments) { + private void files(Object arguments, Result result) { @SuppressWarnings("unchecked") HashMap argsMap = (HashMap) arguments; String title = (String) argsMap.get("title"); - @SuppressWarnings("unchecked") ArrayList names = (ArrayList) argsMap.get("names"); ArrayList mimeTypes = (ArrayList) argsMap.get("mimeTypes"); String text = (String) argsMap.get("text"); - Context activeContext = binding.getApplicationContext(); Intent shareIntent = new Intent(); - ArrayList contentUris = new ArrayList<>(); - for (String name : names) { File file = new File(activeContext.getCacheDir(), name); String fileProviderAuthority = activeContext.getPackageName() + PROVIDER_AUTH_EXT; Uri contentUri = FileProvider.getUriForFile(activeContext, fileProviderAuthority, file); contentUris.add(contentUri); } - if (contentUris.size() == 1) { shareIntent.setAction(Intent.ACTION_SEND); shareIntent.putExtra(Intent.EXTRA_STREAM, contentUris.get(0)); @@ -131,24 +166,23 @@ private void files(Object arguments) { shareIntent.setAction(Intent.ACTION_SEND_MULTIPLE); shareIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, contentUris); } - String mimeType = reduceMimeTypes(mimeTypes); shareIntent.setType(mimeType); - if (!text.isEmpty()) shareIntent.putExtra(Intent.EXTRA_TEXT, text); - Intent chooserIntent = Intent.createChooser(shareIntent, title); - List resInfoList = activeContext.getPackageManager().queryIntentActivities(chooserIntent, PackageManager.MATCH_DEFAULT_ONLY); - for (ResolveInfo resolveInfo : resInfoList) { String packageName = resolveInfo.activityInfo.packageName; for(Uri uri: contentUris){ activeContext.grantUriPermission(packageName, uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION); } } - chooserIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - activeContext.startActivity(chooserIntent); + if (activity != null) { + pendingResult = result; + activity.startActivityForResult(chooserIntent, SHARE_REQUEST_CODE); + } else { + result.error("NO_ACTIVITY", "No foreground activity", null); + } } /** diff --git a/example/lib/main.dart b/example/lib/main.dart index 8b8c84b..4423e3f 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -20,6 +20,13 @@ class MyHomePage extends StatefulWidget { } class _MyHomePageState extends State { + @override + void initState() { + super.initState(); + // initialise the plugin before work with share. + Share.init(); + } + @override Widget build(BuildContext context) { return Scaffold( diff --git a/ios/Classes/SwiftEsysFlutterSharePlugin.swift b/ios/Classes/SwiftEsysFlutterSharePlugin.swift index ee97425..ea31679 100644 --- a/ios/Classes/SwiftEsysFlutterSharePlugin.swift +++ b/ios/Classes/SwiftEsysFlutterSharePlugin.swift @@ -11,91 +11,98 @@ public class SwiftEsysFlutterSharePlugin: NSObject, FlutterPlugin { public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { if(call.method == "text"){ - self.text(arguments: call.arguments) + self.text(arguments: call.arguments) { success in + result(success) + } } if(call.method == "file"){ - self.file(arguments: call.arguments) + self.file(arguments: call.arguments) { success in + result(success) + } } if(call.method == "files"){ - self.files(arguments: call.arguments) + self.files(arguments: call.arguments) { success in + result(success) + } } } - func text(arguments:Any?) -> Void { + func text(arguments:Any?, completion: @escaping (Bool) -> Void) { // prepare method channel args // no use in ios //// let title:String = argsMap.value(forKey: "title") as! String let argsMap = arguments as! NSDictionary let text:String = argsMap.value(forKey: "text") as! String - + // set up activity view controller let activityViewController:UIActivityViewController = UIActivityViewController(activityItems: [text], applicationActivities: nil) - + // present the view controller let controller = UIApplication.shared.keyWindow!.rootViewController as! FlutterViewController activityViewController.popoverPresentationController?.sourceView = controller.view - + activityViewController.completionWithItemsHandler = { activityType, completed, returnedItems, error in + completion(completed) + } controller.show(activityViewController, sender: self) } - func file(arguments:Any?) -> Void { + func file(arguments:Any?, completion: @escaping (Bool) -> Void) { // prepare method channel args // no use in ios //// let title:String = argsMap.value(forKey: "title") as! String let argsMap = arguments as! NSDictionary let name:String = argsMap.value(forKey: "name") as! String let text:String = argsMap.value(forKey: "text") as! String - // load the file let docsPath:String = NSSearchPathForDirectoriesInDomains(.cachesDirectory,.userDomainMask , true).first!; let contentUri = NSURL(fileURLWithPath: docsPath).appendingPathComponent(name) - // prepare sctivity items var activityItems:[Any] = [contentUri!]; if(!text.isEmpty){ // add optional text activityItems.append(text); } - // set up activity view controller let activityViewController:UIActivityViewController = UIActivityViewController(activityItems: activityItems, applicationActivities: nil) - // present the view controller let controller = UIApplication.shared.keyWindow!.rootViewController as! FlutterViewController activityViewController.popoverPresentationController?.sourceView = controller.view - + activityViewController.completionWithItemsHandler = { activityType, completed, returnedItems, error in + completion(completed) + } controller.show(activityViewController, sender: self) } - func files(arguments:Any?) -> Void { + func files(arguments:Any?, completion: @escaping (Bool) -> Void) { // prepare method channel args // no use in ios //// let title:String = argsMap.value(forKey: "title") as! String let argsMap = arguments as! NSDictionary let names:[String] = argsMap.value(forKey: "names") as! [String] let text:String = argsMap.value(forKey: "text") as! String - + // prepare sctivity items var activityItems:[Any] = []; - + // load the files for name in names { let docsPath:String = NSSearchPathForDirectoriesInDomains(.cachesDirectory,.userDomainMask , true).first!; activityItems.append(NSURL(fileURLWithPath: docsPath).appendingPathComponent(name)!); } - if(!text.isEmpty){ // add optional text activityItems.append(text); } - + // set up activity view controller let activityViewController:UIActivityViewController = UIActivityViewController(activityItems: activityItems, applicationActivities: nil) - + // present the view controller let controller = UIApplication.shared.keyWindow!.rootViewController as! FlutterViewController activityViewController.popoverPresentationController?.sourceView = controller.view - + activityViewController.completionWithItemsHandler = { activityType, completed, returnedItems, error in + completion(completed) + } controller.show(activityViewController, sender: self) } } diff --git a/lib/esys_flutter_share_plus.dart b/lib/esys_flutter_share_plus.dart index d9f05c2..d2aa52d 100644 --- a/lib/esys_flutter_share_plus.dart +++ b/lib/esys_flutter_share_plus.dart @@ -1,5 +1,6 @@ import 'dart:async'; import 'dart:io'; +import 'dart:math'; import 'package:flutter/services.dart'; import 'package:path_provider/path_provider.dart'; @@ -8,6 +9,24 @@ class Share { static const MethodChannel _channel = const MethodChannel( 'channel:github.com/orgs/esysberlin/esys-flutter-share'); + static const _tempShareDirectoryName = 'org_innim_esys_flutter_share_tmp'; + + static Future? _initialise; + + /// Initializes the Share plugin. + /// + /// This method should be called at app startup or before starting to work with sharing. + /// It performs cleanup of temporary files that may have been left from previous + /// sharing sessions, especially if the app was closed or crashed before the share + /// window was properly closed. + /// + /// It's recommended to call this method in your app's initialization code + /// (e.g., in main() or in the initState of your main widget) to ensure + /// a clean state before any sharing operations. + static Future init() async { + await (_initialise ??= _init()); + } + /// Sends a text to other apps. static void text(String title, String text, String mimeType) { Map argsMap = { @@ -60,6 +79,7 @@ class Share { String mimeType, { String text = '', }) async { + await init(); Map argsMap = { 'title': title, 'name': name, @@ -94,6 +114,7 @@ class Share { Set mimeTypes, { String text = '', }) async { + await init(); Map argsMap = { 'title': title, 'names': files.keys.toList(), @@ -121,6 +142,7 @@ class Share { String mimeType, { String text = '', }) async { + await init(); Map argsMap = { 'title': title, 'name': name, @@ -128,13 +150,15 @@ class Share { 'text': text }; - final tempDir = await getTemporaryDirectory(); + final tempShareDir = await _getDirectoryForShareFile(); final sourceFile = File(filePath); - final destFile = await File('${tempDir.path}/$name').create(); + final destFile = await File('${tempShareDir.path}/$name').create(); await sourceFile.copy(destFile.path); - _channel.invokeMethod('file', argsMap); + _channel.invokeMethod('file', argsMap).then((_) { + destFile.delete(); + }); } /// Sends multiple files to other apps using file paths. @@ -156,6 +180,7 @@ class Share { Set mimeTypes, { String text = '', }) async { + await init(); Map argsMap = { 'title': title, 'names': files.keys.toList(), @@ -163,14 +188,49 @@ class Share { 'text': text }; - final tempDir = await getTemporaryDirectory(); - + final tempShareDir = await _getDirectoryForShareFile(); + final tempFilesList = []; for (var entry in files.entries) { final sourceFile = File(entry.value); - final destFile = await File('${tempDir.path}/${entry.key}').create(); + final destFile = await File('${tempShareDir.path}/${entry.key}').create(); + tempFilesList.add(destFile); await sourceFile.copy(destFile.path); } - _channel.invokeMethod('files', argsMap); + _channel.invokeMethod('files', argsMap).then((_) { + for (final file in tempFilesList) { + file.delete(); + } + }); + ; + } + + static Future _init() async { + _clearTempShareDirectory(); + } + + static Future _getDirectoryForShareFile() async { + final tempShareDir = await _getBaseTempShareDirectory(); + final dirForFile = Directory('${tempShareDir.path}/${_getRandomString()}'); + dirForFile.create(recursive: true); + return dirForFile; + } + + static Future _getBaseTempShareDirectory() async { + final tempDir = await getTemporaryDirectory(); + final tempShareDir = Directory('${tempDir.path}/$_tempShareDirectoryName'); + return tempShareDir; + } + + static String _getRandomString() { + final random = Random(); + return random.nextInt(100000).toString(); + } + + static Future _clearTempShareDirectory() async { + final tempShareDir = await _getBaseTempShareDirectory(); + if (await tempShareDir.exists()) { + tempShareDir.delete(recursive: true); + } } } diff --git a/pubspec.yaml b/pubspec.yaml index a3a47d3..8a28bd8 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: esys_flutter_share_plus description: A Flutter plugin for sharing images & text with other applications. Fork by Innim -version: 2.3.0 +version: 2.4.0 homepage: https://github.com/Innim/esys-flutter-share repository: https://github.com/Innim/esys-flutter-share issue_tracker: https://github.com/Innim/esys-flutter-share/issues From 87c8f13b4e269cdb582dfb6c3fb20c55289c6336 Mon Sep 17 00:00:00 2001 From: Maksim <69686849+ulezkin@users.noreply.github.com> Date: Fri, 29 Aug 2025 15:04:00 +0300 Subject: [PATCH 25/28] Fixed: broken share * Fixed: broken files share * Added clear for share from memory --------- Co-authored-by: ulezkin --- CHANGELOG.md | 4 + .../EsysFlutterSharePlugin.java | 10 +-- ios/Classes/SwiftEsysFlutterSharePlugin.swift | 34 ++++---- lib/esys_flutter_share_plus.dart | 80 +++++++++++-------- pubspec.yaml | 2 +- 5 files changed, 71 insertions(+), 59 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b4ab72a..ff44676 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.4.0+1 + +* **Fixed** Fix share file error on ios. + ## 2.4.0 * **Added** new method `init()` for initializing the Share plugin and cleaning up temporary files. diff --git a/android/src/main/java/de/esys/esysfluttershare/EsysFlutterSharePlugin.java b/android/src/main/java/de/esys/esysfluttershare/EsysFlutterSharePlugin.java index 55d2749..f6f0a86 100644 --- a/android/src/main/java/de/esys/esysfluttershare/EsysFlutterSharePlugin.java +++ b/android/src/main/java/de/esys/esysfluttershare/EsysFlutterSharePlugin.java @@ -117,13 +117,13 @@ private void file(Object arguments, Result result) { @SuppressWarnings("unchecked") HashMap argsMap = (HashMap) arguments; String title = argsMap.get("title"); - String name = argsMap.get("name"); String mimeType = argsMap.get("mimeType"); String text = argsMap.get("text"); + String filePath = argsMap.get("filePath"); Context activeContext = binding.getApplicationContext(); Intent shareIntent = new Intent(Intent.ACTION_SEND); shareIntent.setType(mimeType); - File file = new File(activeContext.getCacheDir(), name); + File file = new File(filePath); String fileProviderAuthority = activeContext.getPackageName() + PROVIDER_AUTH_EXT; Uri contentUri = FileProvider.getUriForFile(activeContext, fileProviderAuthority, file); shareIntent.putExtra(Intent.EXTRA_STREAM, contentUri); @@ -147,14 +147,14 @@ private void files(Object arguments, Result result) { HashMap argsMap = (HashMap) arguments; String title = (String) argsMap.get("title"); @SuppressWarnings("unchecked") - ArrayList names = (ArrayList) argsMap.get("names"); + ArrayList filePaths = (ArrayList) argsMap.get("filePaths"); ArrayList mimeTypes = (ArrayList) argsMap.get("mimeTypes"); String text = (String) argsMap.get("text"); Context activeContext = binding.getApplicationContext(); Intent shareIntent = new Intent(); ArrayList contentUris = new ArrayList<>(); - for (String name : names) { - File file = new File(activeContext.getCacheDir(), name); + for (String filePath : filePaths) { + File file = new File(filePath); String fileProviderAuthority = activeContext.getPackageName() + PROVIDER_AUTH_EXT; Uri contentUri = FileProvider.getUriForFile(activeContext, fileProviderAuthority, file); contentUris.add(contentUri); diff --git a/ios/Classes/SwiftEsysFlutterSharePlugin.swift b/ios/Classes/SwiftEsysFlutterSharePlugin.swift index ea31679..87aabb1 100644 --- a/ios/Classes/SwiftEsysFlutterSharePlugin.swift +++ b/ios/Classes/SwiftEsysFlutterSharePlugin.swift @@ -47,17 +47,14 @@ public class SwiftEsysFlutterSharePlugin: NSObject, FlutterPlugin { } func file(arguments:Any?, completion: @escaping (Bool) -> Void) { - // prepare method channel args - // no use in ios - //// let title:String = argsMap.value(forKey: "title") as! String let argsMap = arguments as! NSDictionary - let name:String = argsMap.value(forKey: "name") as! String let text:String = argsMap.value(forKey: "text") as! String - // load the file - let docsPath:String = NSSearchPathForDirectoriesInDomains(.cachesDirectory,.userDomainMask , true).first!; - let contentUri = NSURL(fileURLWithPath: docsPath).appendingPathComponent(name) - // prepare sctivity items - var activityItems:[Any] = [contentUri!]; + let filePath:String = argsMap.value(forKey: "filePath") as! String + + let fileURL = URL(fileURLWithPath: filePath) + + // prepare activity items + var activityItems:[Any] = [fileURL]; if(!text.isEmpty){ // add optional text activityItems.append(text); @@ -74,21 +71,17 @@ public class SwiftEsysFlutterSharePlugin: NSObject, FlutterPlugin { } func files(arguments:Any?, completion: @escaping (Bool) -> Void) { - // prepare method channel args - // no use in ios - //// let title:String = argsMap.value(forKey: "title") as! String let argsMap = arguments as! NSDictionary - let names:[String] = argsMap.value(forKey: "names") as! [String] let text:String = argsMap.value(forKey: "text") as! String + let filePaths:[String] = argsMap.value(forKey: "filePaths") as! [String] - // prepare sctivity items - var activityItems:[Any] = []; - - // load the files - for name in names { - let docsPath:String = NSSearchPathForDirectoriesInDomains(.cachesDirectory,.userDomainMask , true).first!; - activityItems.append(NSURL(fileURLWithPath: docsPath).appendingPathComponent(name)!); + // prepare file URLs and activity items + var activityItems:[Any] = [] + for filePath in filePaths { + let url = URL(fileURLWithPath: filePath) + activityItems.append(url) } + if(!text.isEmpty){ // add optional text activityItems.append(text); @@ -105,4 +98,5 @@ public class SwiftEsysFlutterSharePlugin: NSObject, FlutterPlugin { } controller.show(activityViewController, sender: self) } + } diff --git a/lib/esys_flutter_share_plus.dart b/lib/esys_flutter_share_plus.dart index d2aa52d..cce1095 100644 --- a/lib/esys_flutter_share_plus.dart +++ b/lib/esys_flutter_share_plus.dart @@ -80,18 +80,21 @@ class Share { String text = '', }) async { await init(); + + final tempDir = await _getDirectoryForShareFile(); + final file = await File('${tempDir.path}/$name').create(); + await file.writeAsBytes(bytes); + Map argsMap = { 'title': title, - 'name': name, 'mimeType': mimeType, - 'text': text + 'text': text, + 'filePath': file.path, }; - final tempDir = await getTemporaryDirectory(); - final file = await File('${tempDir.path}/$name').create(); - await file.writeAsBytes(bytes); - - _channel.invokeMethod('file', argsMap); + _channel.invokeMethod('file', argsMap).whenComplete(() { + file.delete(); + }); } /// Sends multiple files to other apps from memory. @@ -115,21 +118,29 @@ class Share { String text = '', }) async { await init(); - Map argsMap = { - 'title': title, - 'names': files.keys.toList(), - 'mimeTypes': mimeTypes.toList(), - 'text': text - }; - final tempDir = await getTemporaryDirectory(); + final tempDir = await _getDirectoryForShareFile(); + + final filePaths = []; + final tempFilesList = []; for (var entry in files.entries) { final file = await File('${tempDir.path}/${entry.key}').create(); await file.writeAsBytes(entry.value); + filePaths.add(file.path); + tempFilesList.add(file); } - - _channel.invokeMethod('files', argsMap); + Map argsMap = { + 'title': title, + 'mimeTypes': mimeTypes.toList(), + 'text': text, + 'filePaths': filePaths, + }; + _channel.invokeMethod('files', argsMap).whenComplete(() { + for (final file in tempFilesList) { + file.delete(); + } + }); } /// Sends a file to other apps using a file path. @@ -143,20 +154,20 @@ class Share { String text = '', }) async { await init(); - Map argsMap = { - 'title': title, - 'name': name, - 'mimeType': mimeType, - 'text': text - }; - final tempShareDir = await _getDirectoryForShareFile(); final sourceFile = File(filePath); final destFile = await File('${tempShareDir.path}/$name').create(); await sourceFile.copy(destFile.path); - _channel.invokeMethod('file', argsMap).then((_) { + Map argsMap = { + 'title': title, + 'mimeType': mimeType, + 'text': text, + 'filePath': destFile.path + }; + + _channel.invokeMethod('file', argsMap).whenComplete(() { destFile.delete(); }); } @@ -181,23 +192,26 @@ class Share { String text = '', }) async { await init(); - Map argsMap = { - 'title': title, - 'names': files.keys.toList(), - 'mimeTypes': mimeTypes.toList(), - 'text': text - }; - final tempShareDir = await _getDirectoryForShareFile(); final tempFilesList = []; + final filePaths = []; + for (var entry in files.entries) { final sourceFile = File(entry.value); final destFile = await File('${tempShareDir.path}/${entry.key}').create(); tempFilesList.add(destFile); + filePaths.add(destFile.path); await sourceFile.copy(destFile.path); } - _channel.invokeMethod('files', argsMap).then((_) { + Map argsMap = { + 'title': title, + 'mimeTypes': mimeTypes.toList(), + 'text': text, + 'filePaths': filePaths + }; + + _channel.invokeMethod('files', argsMap).whenComplete(() { for (final file in tempFilesList) { file.delete(); } @@ -212,7 +226,7 @@ class Share { static Future _getDirectoryForShareFile() async { final tempShareDir = await _getBaseTempShareDirectory(); final dirForFile = Directory('${tempShareDir.path}/${_getRandomString()}'); - dirForFile.create(recursive: true); + await dirForFile.create(recursive: true); return dirForFile; } diff --git a/pubspec.yaml b/pubspec.yaml index 8a28bd8..3c228e5 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: esys_flutter_share_plus description: A Flutter plugin for sharing images & text with other applications. Fork by Innim -version: 2.4.0 +version: 2.4.0+1 homepage: https://github.com/Innim/esys-flutter-share repository: https://github.com/Innim/esys-flutter-share issue_tracker: https://github.com/Innim/esys-flutter-share/issues From 7b8016d536ed22ce1bfc8b35e5f60aa98c2eb241 Mon Sep 17 00:00:00 2001 From: greymag Date: Wed, 14 Jan 2026 11:05:16 +0100 Subject: [PATCH 26/28] ci: analyze and publish --- .github/workflows/dart.yml | 30 ++++++++++++++++++++++++++++++ .github/workflows/publish.yml | 23 +++++++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 .github/workflows/dart.yml create mode 100644 .github/workflows/publish.yml diff --git a/.github/workflows/dart.yml b/.github/workflows/dart.yml new file mode 100644 index 0000000..e945211 --- /dev/null +++ b/.github/workflows/dart.yml @@ -0,0 +1,30 @@ +name: Analyze & Test + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-java@v1 + with: + java-version: '12.x' + - uses: subosito/flutter-action@v2 + with: + channel: 'stable' + + - name: Install dependencies + run: flutter pub get + + - name: Analyze project source + run: flutter analyze + + # No test for now + # - name: Run tests + # run: flutter test \ No newline at end of file diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..0a8350c --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,23 @@ +name: Publish + +on: + workflow_run: + workflows: ["Analyze & Test"] + types: [completed] + branches: [master] + + workflow_dispatch: + +jobs: + publish: + runs-on: ubuntu-latest + if: ${{ github.event.workflow_run.conclusion == 'success' }} + steps: + - uses: actions/checkout@v2 + - name: Dart and Flutter Package Publisher + uses: k-paxian/dart-package-publisher@v1.5.1 + with: + accessToken: ${{ secrets.OAUTH_ACCESS_TOKEN }} + refreshToken: ${{ secrets.OAUTH_REFRESH_TOKEN }} + skipTests: true + flutter: true From a2b7f1b4f53ca112482cca4693de66c013e82982 Mon Sep 17 00:00:00 2001 From: Evgen Date: Wed, 14 Jan 2026 13:07:11 +0300 Subject: [PATCH 27/28] Feature/share in separate activity (#8) * Upgraded `compileSdkVersion` to 35, `minSdkVersion` to 21, `gradle` to 8.10 * Updated example * Added optional ability to run sharing in separate activity * Version and changelog * Remove redundant activity * Unused dependency --- CHANGELOG.md | 8 +++ android/build.gradle | 6 +- .../gradle/wrapper/gradle-wrapper.properties | 3 +- .../EsysFlutterSharePlugin.java | 21 +++++- example/android/app/build.gradle | 67 +++++++------------ .../android/app/src/main/AndroidManifest.xml | 33 ++++++++- .../app/src/main/res/values/styles.xml | 14 +++- .../app/src/main/res/xml/provider_paths.xml | 8 +++ example/android/build.gradle | 21 ++---- .../gradle/wrapper/gradle-wrapper.properties | 3 +- example/android/settings.gradle | 30 ++++++--- lib/esys_flutter_share_plus.dart | 13 +++- pubspec.yaml | 2 +- 13 files changed, 145 insertions(+), 84 deletions(-) create mode 100644 example/android/app/src/main/res/xml/provider_paths.xml diff --git a/CHANGELOG.md b/CHANGELOG.md index ff44676..5aedd85 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +## 2.5.0 + +* Update Android `compileSdkVersion` to 35 +* Update Android `minSdkVersion` to 21 +* Update Android `gradle` version to 8.10 +* Update Android example app. +* On Android sharing now launches in a separate Activity by default. To keep it in the current Activity, set `useSeparateActivity: false` in the `init` method. + ## 2.4.0+1 * **Fixed** Fix share file error on ios. diff --git a/android/build.gradle b/android/build.gradle index 1775c8b..2a48d31 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -23,10 +23,10 @@ apply plugin: 'com.android.library' android { namespace "de.esys.esysfluttershare" - compileSdkVersion 28 + compileSdkVersion 35 defaultConfig { - minSdkVersion 16 + minSdkVersion 21 testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } lintOptions { @@ -35,5 +35,5 @@ android { } dependencies { - implementation 'androidx.legacy:legacy-support-v4:1.0.0-beta01' + implementation 'androidx.legacy:legacy-support-v4:1.0.0' } diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index 9a4163a..bd702ea 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,6 @@ +#Wed Dec 03 14:18:55 MSK 2025 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/android/src/main/java/de/esys/esysfluttershare/EsysFlutterSharePlugin.java b/android/src/main/java/de/esys/esysfluttershare/EsysFlutterSharePlugin.java index f6f0a86..6fc5d1a 100644 --- a/android/src/main/java/de/esys/esysfluttershare/EsysFlutterSharePlugin.java +++ b/android/src/main/java/de/esys/esysfluttershare/EsysFlutterSharePlugin.java @@ -1,5 +1,7 @@ package de.esys.esysfluttershare; +import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; + import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; @@ -19,13 +21,16 @@ import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.MethodChannel.MethodCallHandler; import io.flutter.plugin.common.MethodChannel.Result; + import android.app.Activity; -import android.content.IntentSender; + import io.flutter.embedding.engine.plugins.activity.ActivityAware; import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding; import io.flutter.plugin.common.PluginRegistry; -/** EsysfluttersharePlugin */ +/** + * EsysfluttersharePlugin + */ public class EsysFlutterSharePlugin implements FlutterPlugin, MethodCallHandler, ActivityAware, PluginRegistry.ActivityResultListener { private final String PROVIDER_AUTH_EXT = ".fileprovider.github.com/orgs/esysberlin/esys-flutter-share"; @@ -35,6 +40,7 @@ public class EsysFlutterSharePlugin implements FlutterPlugin, MethodCallHandler, private FlutterPluginBinding binding; private Activity activity; private Result pendingResult; + private Boolean useSeparateActivity; @Override public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) { @@ -45,6 +51,9 @@ public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBindin @Override public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) { + if (call.method.equals("init")) { + initPlugin(call.arguments, result); + } if (call.method.equals("text")) { text(call.arguments, result); } @@ -91,8 +100,13 @@ public boolean onActivityResult(int requestCode, int resultCode, Intent data) { pendingResult = null; return true; } + return false; } + + private void initPlugin(Object arguments, Result result) { + useSeparateActivity = (Boolean) arguments; + } private void text(Object arguments, Result result) { @SuppressWarnings("unchecked") @@ -105,6 +119,7 @@ private void text(Object arguments, Result result) { shareIntent.putExtra(Intent.EXTRA_TEXT, text); Intent chooserIntent = Intent.createChooser(shareIntent, title); chooserIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); + if (useSeparateActivity) chooserIntent.addFlags(FLAG_ACTIVITY_NEW_TASK); if (activity != null) { pendingResult = result; activity.startActivityForResult(chooserIntent, SHARE_REQUEST_CODE); @@ -129,6 +144,7 @@ private void file(Object arguments, Result result) { shareIntent.putExtra(Intent.EXTRA_STREAM, contentUri); if (!text.isEmpty()) shareIntent.putExtra(Intent.EXTRA_TEXT, text); Intent chooserIntent = Intent.createChooser(shareIntent, title); + if (useSeparateActivity) chooserIntent.addFlags(FLAG_ACTIVITY_NEW_TASK); List resInfoList = activeContext.getPackageManager().queryIntentActivities(chooserIntent, PackageManager.MATCH_DEFAULT_ONLY); for (ResolveInfo resolveInfo : resInfoList) { String packageName = resolveInfo.activityInfo.packageName; @@ -170,6 +186,7 @@ private void files(Object arguments, Result result) { shareIntent.setType(mimeType); if (!text.isEmpty()) shareIntent.putExtra(Intent.EXTRA_TEXT, text); Intent chooserIntent = Intent.createChooser(shareIntent, title); + if (useSeparateActivity) chooserIntent.addFlags(FLAG_ACTIVITY_NEW_TASK); List resInfoList = activeContext.getPackageManager().queryIntentActivities(chooserIntent, PackageManager.MATCH_DEFAULT_ONLY); for (ResolveInfo resolveInfo : resInfoList) { String packageName = resolveInfo.activityInfo.packageName; diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle index b2542b4..21d0caf 100644 --- a/example/android/app/build.gradle +++ b/example/android/app/build.gradle @@ -1,61 +1,44 @@ -def localProperties = new Properties() -def localPropertiesFile = rootProject.file('local.properties') -if (localPropertiesFile.exists()) { - localPropertiesFile.withReader('UTF-8') { reader -> - localProperties.load(reader) - } -} - -def flutterRoot = localProperties.getProperty('flutter.sdk') -if (flutterRoot == null) { - throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") -} - -def flutterVersionCode = localProperties.getProperty('flutter.versionCode') -if (flutterVersionCode == null) { - flutterVersionCode = '1' -} - -def flutterVersionName = localProperties.getProperty('flutter.versionName') -if (flutterVersionName == null) { - flutterVersionName = '1.0' +plugins { + id "com.android.application" + id "kotlin-android" + // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. + id "dev.flutter.flutter-gradle-plugin" } -apply plugin: 'com.android.application' -apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" - android { - compileSdkVersion 31 + namespace = "de.esys.esysfluttershareexample" + compileSdk = flutter.compileSdkVersion + ndkVersion = flutter.ndkVersion + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } - lintOptions { - disable 'InvalidPackage' + kotlinOptions { + jvmTarget = JavaVersion.VERSION_1_8 } defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId "de.esys.esysfluttershareexample" - minSdkVersion 16 - targetSdkVersion 28 - versionCode flutterVersionCode.toInteger() - versionName flutterVersionName - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + applicationId = "de.esys.esysfluttershareexample" + // You can update the following values to match your application needs. + // For more information, see: https://flutter.dev/to/review-gradle-config. + minSdk = flutter.minSdkVersion + targetSdk = flutter.targetSdkVersion + versionCode = flutter.versionCode + versionName = flutter.versionName } buildTypes { release { // TODO: Add your own signing config for the release build. // Signing with the debug keys for now, so `flutter run --release` works. - signingConfig signingConfigs.debug + signingConfig = signingConfigs.debug } } } flutter { - source '../..' -} - -dependencies { - testImplementation 'junit:junit:4.12' - androidTestImplementation 'androidx.test:runner:1.1.0-alpha4' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0-alpha4' -} + source = "../.." +} \ No newline at end of file diff --git a/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml index 032ab4d..f0496cf 100644 --- a/example/android/app/src/main/AndroidManifest.xml +++ b/example/android/app/src/main/AndroidManifest.xml @@ -1,5 +1,5 @@ +xmlns:tools="http://schemas.android.com/tools"> + android:name="io.flutter.embedding.android.NormalTheme" + android:resource="@style/NormalTheme" + /> @@ -41,5 +44,29 @@ + + + + + + + + + + + + diff --git a/example/android/app/src/main/res/values/styles.xml b/example/android/app/src/main/res/values/styles.xml index 00fa441..cb1ef88 100644 --- a/example/android/app/src/main/res/values/styles.xml +++ b/example/android/app/src/main/res/values/styles.xml @@ -1,8 +1,18 @@ - + + diff --git a/example/android/app/src/main/res/xml/provider_paths.xml b/example/android/app/src/main/res/xml/provider_paths.xml new file mode 100644 index 0000000..d777673 --- /dev/null +++ b/example/android/app/src/main/res/xml/provider_paths.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/example/android/build.gradle b/example/android/build.gradle index fab3c2e..8e9de9d 100644 --- a/example/android/build.gradle +++ b/example/android/build.gradle @@ -1,29 +1,18 @@ -buildscript { - repositories { - google() - jcenter() - } - - dependencies { - classpath 'com.android.tools.build:gradle:4.1.3' - } -} - allprojects { repositories { google() - jcenter() + mavenCentral() } } -rootProject.buildDir = '../build' +rootProject.buildDir = "../build" subprojects { project.buildDir = "${rootProject.buildDir}/${project.name}" } subprojects { - project.evaluationDependsOn(':app') + project.evaluationDependsOn(":app") } -task clean(type: Delete) { +tasks.register("clean", Delete) { delete rootProject.buildDir -} +} \ No newline at end of file diff --git a/example/android/gradle/wrapper/gradle-wrapper.properties b/example/android/gradle/wrapper/gradle-wrapper.properties index 90f271d..1a7a6f8 100644 --- a/example/android/gradle/wrapper/gradle-wrapper.properties +++ b/example/android/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip + diff --git a/example/android/settings.gradle b/example/android/settings.gradle index 5a2f14f..b9e43bd 100644 --- a/example/android/settings.gradle +++ b/example/android/settings.gradle @@ -1,15 +1,25 @@ -include ':app' +pluginManagement { + def flutterSdkPath = { + def properties = new Properties() + file("local.properties").withInputStream { properties.load(it) } + def flutterSdkPath = properties.getProperty("flutter.sdk") + assert flutterSdkPath != null, "flutter.sdk not set in local.properties" + return flutterSdkPath + }() -def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") -def plugins = new Properties() -def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') -if (pluginsFile.exists()) { - pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } + repositories { + google() + mavenCentral() + gradlePluginPortal() + } } -plugins.each { name, path -> - def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() - include ":$name" - project(":$name").projectDir = pluginDirectory +plugins { + id "dev.flutter.flutter-plugin-loader" version "1.0.0" + id "com.android.application" version "8.1.0" apply false + id "org.jetbrains.kotlin.android" version "1.8.22" apply false } + +include ":app" diff --git a/lib/esys_flutter_share_plus.dart b/lib/esys_flutter_share_plus.dart index cce1095..542da1b 100644 --- a/lib/esys_flutter_share_plus.dart +++ b/lib/esys_flutter_share_plus.dart @@ -23,8 +23,8 @@ class Share { /// It's recommended to call this method in your app's initialization code /// (e.g., in main() or in the initState of your main widget) to ensure /// a clean state before any sharing operations. - static Future init() async { - await (_initialise ??= _init()); + static Future init({bool useSeparateActivity = true}) async { + await (_initialise ??= _init(useSeparateActivity)); } /// Sends a text to other apps. @@ -219,10 +219,17 @@ class Share { ; } - static Future _init() async { + static Future _init(bool useSeparateActivity) async { + if (Platform.isAndroid) { + await _initNativeAndroid(useSeparateActivity); + } _clearTempShareDirectory(); } + static Future _initNativeAndroid(bool useSeparateActivity) async { + _channel.invokeMethod('init', useSeparateActivity); + } + static Future _getDirectoryForShareFile() async { final tempShareDir = await _getBaseTempShareDirectory(); final dirForFile = Directory('${tempShareDir.path}/${_getRandomString()}'); diff --git a/pubspec.yaml b/pubspec.yaml index 3c228e5..a13e95c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: esys_flutter_share_plus description: A Flutter plugin for sharing images & text with other applications. Fork by Innim -version: 2.4.0+1 +version: 2.5.0 homepage: https://github.com/Innim/esys-flutter-share repository: https://github.com/Innim/esys-flutter-share issue_tracker: https://github.com/Innim/esys-flutter-share/issues From 6a00b956d4d6e2784b9ba48f6703d0913b26351c Mon Sep 17 00:00:00 2001 From: Evgen Date: Fri, 30 Jan 2026 14:35:22 +0300 Subject: [PATCH 28/28] fix(android): temporary files were deleted before share completed (#9) * fix(android): temporary files were deleted before share completed * set `_useSeparateActivity` once on initializing --- CHANGELOG.md | 5 +++++ README.md | 9 +++++++++ lib/esys_flutter_share_plus.dart | 30 ++++++++++++++++++++---------- pubspec.yaml | 2 +- 4 files changed, 35 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5aedd85..18a28b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +# 2.5.1 + +* **Fixed** Android: an issue where files were deleted before being shared to another activity. +* **Added** public method `clean()` to trigger the cleanup of the temporary files directory. + ## 2.5.0 * Update Android `compileSdkVersion` to 35 diff --git a/README.md b/README.md index dc07e35..2f19637 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,15 @@ end Instead, if you have already a non-swift project, you can check this issue to solve the problem: [Friction adding swift plugin to objective-c project](https://github.com/flutter/flutter/issues/16049). +## IMPORTANT Note for Android +On Android, the Share function launches by default in a separate system task and activity. This maintains the cleanliness of your application's navigation stack. However, in this mode, the application cannot wait for the process to complete or reliably receive its result. + +Therefore, we cannot determine precisely whether the user has finished sharing the file to safely delete the temporary files. As a result, the temporary file directory is cleared each time a new sharing operation is initiated. + +You can also force a cleanup when you are certain the user has finished with the Share function (for example, when leaving the screen of your app from which sharing was launched). To do this, use the `clean()` method. + +Alternative option: You can disable launching in a separate system activity by setting the parameter `useSeparateActivity: false` in the `init()` method. In this case, the result of the Share operation will be returned to your application, and the cleanup of temporary files will happen automatically. + ## Usage Import: diff --git a/lib/esys_flutter_share_plus.dart b/lib/esys_flutter_share_plus.dart index 542da1b..ad28b4f 100644 --- a/lib/esys_flutter_share_plus.dart +++ b/lib/esys_flutter_share_plus.dart @@ -13,6 +13,8 @@ class Share { static Future? _initialise; + static bool _useSeparateActivity = true; + /// Initializes the Share plugin. /// /// This method should be called at app startup or before starting to work with sharing. @@ -25,8 +27,12 @@ class Share { /// a clean state before any sharing operations. static Future init({bool useSeparateActivity = true}) async { await (_initialise ??= _init(useSeparateActivity)); + await _clearTempShareDirectory(); } + /// Clearing the directory with temporary files. + static Future clear() => _clearTempShareDirectory(); + /// Sends a text to other apps. static void text(String title, String text, String mimeType) { Map argsMap = { @@ -93,7 +99,7 @@ class Share { }; _channel.invokeMethod('file', argsMap).whenComplete(() { - file.delete(); + if (!_useSeparateActivity || Platform.isIOS) file.delete(); }); } @@ -137,8 +143,10 @@ class Share { 'filePaths': filePaths, }; _channel.invokeMethod('files', argsMap).whenComplete(() { - for (final file in tempFilesList) { - file.delete(); + if (!_useSeparateActivity || Platform.isIOS) { + for (final file in tempFilesList) { + file.delete(); + } } }); } @@ -168,7 +176,7 @@ class Share { }; _channel.invokeMethod('file', argsMap).whenComplete(() { - destFile.delete(); + if (!_useSeparateActivity || Platform.isIOS) destFile.delete(); }); } @@ -212,22 +220,24 @@ class Share { }; _channel.invokeMethod('files', argsMap).whenComplete(() { - for (final file in tempFilesList) { - file.delete(); + if (!_useSeparateActivity || Platform.isIOS) { + for (final file in tempFilesList) { + file.delete(); + } } }); ; } static Future _init(bool useSeparateActivity) async { + _useSeparateActivity = useSeparateActivity; if (Platform.isAndroid) { - await _initNativeAndroid(useSeparateActivity); + await _initNativeAndroid(); } - _clearTempShareDirectory(); } - static Future _initNativeAndroid(bool useSeparateActivity) async { - _channel.invokeMethod('init', useSeparateActivity); + static Future _initNativeAndroid() async { + _channel.invokeMethod('init', _useSeparateActivity); } static Future _getDirectoryForShareFile() async { diff --git a/pubspec.yaml b/pubspec.yaml index a13e95c..05ae997 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: esys_flutter_share_plus description: A Flutter plugin for sharing images & text with other applications. Fork by Innim -version: 2.5.0 +version: 2.5.1 homepage: https://github.com/Innim/esys-flutter-share repository: https://github.com/Innim/esys-flutter-share issue_tracker: https://github.com/Innim/esys-flutter-share/issues