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
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
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0b83051..18a28b5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,69 @@
+# 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
+* 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.
+
+## 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** 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.
+
+## 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.
+
+## 2.1.0
+
+* Published as `esys_flutter_share_plus`.
+* `compileSdkVersion` upgraded to 31.
+
+## 2.0.1
+
+* migrate to V2
+
+## 2.0.0
+
+* migrate to null safety
+* update path_provider to 2.0.0
+
## 1.0.3
* update example app
@@ -18,7 +84,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 7cfb3ee..2f19637 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.
@@ -28,12 +30,28 @@ 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:
```dart
-import 'package:esys_flutter_share/esys_flutter_share.dart';
+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:
@@ -42,21 +60,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(),
@@ -73,7 +119,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/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 e20a885..0000000
Binary files a/android/.idea/caches/build_file_checksums.ser and /dev/null differ
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
diff --git a/android/build.gradle b/android/build.gradle
index 7a7d8da..2a48d31 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -4,28 +4,29 @@ 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()
}
}
apply plugin: 'com.android.library'
android {
- compileSdkVersion 28
+ namespace "de.esys.esysfluttershare"
+ compileSdkVersion 35
defaultConfig {
- minSdkVersion 16
+ minSdkVersion 21
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
lintOptions {
@@ -34,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/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/android/src/main/java/de/esys/esysfluttershare/EsysFlutterSharePlugin.java b/android/src/main/java/de/esys/esysfluttershare/EsysFlutterSharePlugin.java
index 715a38b..6fc5d1a 100644
--- a/android/src/main/java/de/esys/esysfluttershare/EsysFlutterSharePlugin.java
+++ b/android/src/main/java/de/esys/esysfluttershare/EsysFlutterSharePlugin.java
@@ -1,117 +1,245 @@
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;
+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;
+
+import android.app.Activity;
+
+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 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 Registrar _registrar;
+ private static final int SHARE_REQUEST_CODE = 9023;
- private EsysFlutterSharePlugin(Registrar registrar) {
- this._registrar = registrar;
- }
+ private MethodChannel channel;
+ private FlutterPluginBinding binding;
+ private Activity activity;
+ private Result pendingResult;
+ private Boolean useSeparateActivity;
- /**
- * 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("init")) {
+ initPlugin(call.arguments, 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);
}
}
- private void text(Object arguments) {
+ @Override
+ public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
+ channel.setMethodCallHandler(null);
+ }
+
+ @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 initPlugin(Object arguments, Result result) {
+ useSeparateActivity = (Boolean) arguments;
+ }
+
+ 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 = _registrar.activeContext();
-
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_GRANT_WRITE_URI_PERMISSION);
+ if (useSeparateActivity) chooserIntent.addFlags(FLAG_ACTIVITY_NEW_TASK);
+ 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 = _registrar.activeContext();
-
+ 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);
- // add optional text
if (!text.isEmpty()) shareIntent.putExtra(Intent.EXTRA_TEXT, text);
- activeContext.startActivity(Intent.createChooser(shareIntent, title));
+ 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;
+ activeContext.grantUriPermission(packageName, contentUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ }
+ 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");
- String mimeType = (String) argsMap.get("mimeType");
+ ArrayList filePaths = (ArrayList) argsMap.get("filePaths");
+ ArrayList mimeTypes = (ArrayList) argsMap.get("mimeTypes");
String text = (String) argsMap.get("text");
-
- Context activeContext = _registrar.activeContext();
-
- Intent shareIntent = new Intent(Intent.ACTION_SEND_MULTIPLE);
- shareIntent.setType(mimeType);
-
+ 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;
- 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 (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);
+ }
+ String mimeType = reduceMimeTypes(mimeTypes);
+ shareIntent.setType(mimeType);
if (!text.isEmpty()) shareIntent.putExtra(Intent.EXTRA_TEXT, text);
- activeContext.startActivity(Intent.createChooser(shareIntent, title));
+ 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;
+ for(Uri uri: contentUris){
+ activeContext.grantUriPermission(packageName, uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ }
+ }
+ if (activity != null) {
+ pendingResult = result;
+ activity.startActivityForResult(chooserIntent, SHARE_REQUEST_CODE);
+ } else {
+ result.error("NO_ACTIVITY", "No foreground activity", null);
+ }
+ }
+
+ /**
+ * 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/.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/android/app/build.gradle b/example/android/app/build.gradle
index b6f07a1..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 28
+ 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 446eeef..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"
+ />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
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/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 bb8a303..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:3.2.1'
- }
-}
-
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 2819f02..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-4.10.2-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/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
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 @@
CFBundleVersion1.0MinimumOSVersion
- 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 7ef591e..d16d53b 100644
--- a/example/ios/Runner.xcodeproj/project.pbxproj
+++ b/example/ios/Runner.xcodeproj/project.pbxproj
@@ -3,18 +3,14 @@
archiveVersion = 1;
classes = {
};
- objectVersion = 46;
+ objectVersion = 50;
objects = {
/* Begin PBXBuildFile section */
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;
@@ -38,20 +32,21 @@
/* 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 = ""; };
- 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 = ""; };
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 */
@@ -59,8 +54,6 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */,
- 3B80C3941E831B6300D905FE /* App.framework in Frameworks */,
30CC177B0653FC1250DBBDDC /* Pods_Runner.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -79,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 = "";
@@ -86,9 +82,7 @@
9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup;
children = (
- 3B80C3931E831B6300D905FE /* App.framework */,
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
- 9740EEBA1CF902C7004384FC /* Flutter.framework */,
9740EEB21CF90195004384FC /* Debug.xcconfig */,
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
9740EEB31CF90195004384FC /* Generated.xcconfig */,
@@ -169,7 +163,7 @@
97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject;
attributes = {
- LastUpgradeCheck = 0940;
+ LastUpgradeCheck = 1300;
ORGANIZATIONNAME = "The Chromium Authors";
TargetAttributes = {
97C146ED1CF9000F007C117D = {
@@ -225,7 +219,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;
@@ -233,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 */ = {
@@ -317,7 +309,6 @@
/* Begin XCBuildConfiguration section */
249021D3217E4FDB00AE95B9 /* Profile */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
@@ -357,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";
@@ -378,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",
@@ -392,7 +386,6 @@
};
97C147031CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
@@ -438,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;
@@ -448,7 +441,6 @@
};
97C147041CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
@@ -488,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";
@@ -511,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",
@@ -540,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/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.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 @@
-
-
-
- BuildSystemType
- Original
-
-
diff --git a/example/lib/main.dart b/example/lib/main.dart
index 8da9b8c..4423e3f 100644
--- a/example/lib/main.dart
+++ b/example/lib/main.dart
@@ -1,11 +1,10 @@
import 'dart:async';
import 'dart:io';
-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(
@@ -21,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(
@@ -75,7 +81,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,13 +94,14 @@ 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(
- 'esys images',
- {
- 'esys.png': bytes1.buffer.asUint8List(),
- 'bluedan.png': bytes2.buffer.asUint8List(),
- },
- 'image/png');
+ await Share.filesFromMemory(
+ 'esys images',
+ {
+ 'esys.png': bytes1.buffer.asUint8List(),
+ 'bluedan.png': bytes2.buffer.asUint8List(),
+ },
+ {'image/png'},
+ );
} catch (e) {
print('error: $e');
}
@@ -103,7 +110,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');
@@ -116,14 +123,14 @@ 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(),
'bluedan.png': bytes2.buffer.asUint8List(),
'addresses.csv': bytes3.buffer.asUint8List(),
},
- '*/*',
+ {'*/*'},
text: 'My optional text.');
} catch (e) {
print('error: $e');
@@ -136,7 +143,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');
}
@@ -145,7 +152,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/example/pubspec.yaml b/example/pubspec.yaml
index 04da2c1..c15dcec 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:
@@ -11,13 +11,13 @@ 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:
sdk: flutter
- esys_flutter_share:
+ esys_flutter_share_plus:
path: ../
# For information on the generic Dart part of this file, see the
@@ -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/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/Classes/SwiftEsysFlutterSharePlugin.swift b/ios/Classes/SwiftEsysFlutterSharePlugin.swift
index ee97425..87aabb1 100644
--- a/ios/Classes/SwiftEsysFlutterSharePlugin.swift
+++ b/ios/Classes/SwiftEsysFlutterSharePlugin.swift
@@ -11,91 +11,92 @@ 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 {
- // prepare method channel args
- // no use in ios
- //// let title:String = argsMap.value(forKey: "title") as! String
+ func file(arguments:Any?, completion: @escaping (Bool) -> Void) {
let argsMap = arguments as! NSDictionary
- let name:String = argsMap.value(forKey: "name") as! String
let text:String = argsMap.value(forKey: "text") as! String
+ let filePath:String = argsMap.value(forKey: "filePath") as! String
- // load the file
- let docsPath:String = NSSearchPathForDirectoriesInDomains(.cachesDirectory,.userDomainMask , true).first!;
- let contentUri = NSURL(fileURLWithPath: docsPath).appendingPathComponent(name)
+ let fileURL = URL(fileURLWithPath: filePath)
- // prepare sctivity items
- var activityItems:[Any] = [contentUri!];
+ // prepare activity items
+ var activityItems:[Any] = [fileURL];
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 {
- // prepare method channel args
- // no use in ios
- //// let title:String = argsMap.value(forKey: "title") as! String
+ func files(arguments:Any?, completion: @escaping (Bool) -> Void) {
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)!);
+ let filePaths:[String] = argsMap.value(forKey: "filePaths") as! [String]
+
+ // 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);
}
-
+
// 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/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
diff --git a/lib/esys_flutter_share.dart b/lib/esys_flutter_share.dart
deleted file mode 100644
index d8c37d4..0000000
--- a/lib/esys_flutter_share.dart
+++ /dev/null
@@ -1,57 +0,0 @@
-import 'dart:async';
-import 'dart:io';
-
-import 'package:flutter/services.dart';
-import 'package:path_provider/path_provider.dart';
-
-class Share {
- static const MethodChannel _channel = const MethodChannel(
- 'channel:github.com/orgs/esysberlin/esys-flutter-share');
-
- /// Sends a text to other apps.
- static void text(String title, String text, String mimeType) {
- Map argsMap = {
- 'title': '$title',
- 'text': '$text',
- 'mimeType': '$mimeType'
- };
- _channel.invokeMethod('text', argsMap);
- }
-
- /// Sends a file to other apps.
- static Future file(
- 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();
- await file.writeAsBytes(bytes);
-
- _channel.invokeMethod('file', argsMap);
- }
-
- /// Sends multiple files to other apps.
- static Future files(
- String title, Map> files, String mimeType, {String text = ''}) async {
- Map argsMap = {
- 'title': '$title',
- 'names': files.entries.toList().map((x) => x.key).toList(),
- 'mimeType': mimeType,
- 'text': '$text'
- };
-
- final tempDir = await getTemporaryDirectory();
-
- for (var entry in files.entries) {
- final file = await new File('${tempDir.path}/${entry.key}').create();
- await file.writeAsBytes(entry.value);
- }
-
- _channel.invokeMethod('files', argsMap);
- }
-}
diff --git a/lib/esys_flutter_share_plus.dart b/lib/esys_flutter_share_plus.dart
new file mode 100644
index 0000000..ad28b4f
--- /dev/null
+++ b/lib/esys_flutter_share_plus.dart
@@ -0,0 +1,267 @@
+import 'dart:async';
+import 'dart:io';
+import 'dart:math';
+
+import 'package:flutter/services.dart';
+import 'package:path_provider/path_provider.dart';
+
+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;
+
+ static bool _useSeparateActivity = true;
+
+ /// 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({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 = {
+ '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 {
+ 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 {
+ await init();
+
+ final tempDir = await _getDirectoryForShareFile();
+ final file = await File('${tempDir.path}/$name').create();
+ await file.writeAsBytes(bytes);
+
+ Map argsMap = {
+ 'title': title,
+ 'mimeType': mimeType,
+ 'text': text,
+ 'filePath': file.path,
+ };
+
+ _channel.invokeMethod('file', argsMap).whenComplete(() {
+ if (!_useSeparateActivity || Platform.isIOS) file.delete();
+ });
+ }
+
+ /// 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/*
+ /// 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 filesFromMemory(
+ String title,
+ Map> files,
+ Set mimeTypes, {
+ String text = '',
+ }) async {
+ await init();
+
+ 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);
+ }
+ Map argsMap = {
+ 'title': title,
+ 'mimeTypes': mimeTypes.toList(),
+ 'text': text,
+ 'filePaths': filePaths,
+ };
+ _channel.invokeMethod('files', argsMap).whenComplete(() {
+ if (!_useSeparateActivity || Platform.isIOS) {
+ for (final file in tempFilesList) {
+ file.delete();
+ }
+ }
+ });
+ }
+
+ /// 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 {
+ await init();
+ final tempShareDir = await _getDirectoryForShareFile();
+ final sourceFile = File(filePath);
+ final destFile = await File('${tempShareDir.path}/$name').create();
+
+ await sourceFile.copy(destFile.path);
+
+ Map argsMap = {
+ 'title': title,
+ 'mimeType': mimeType,
+ 'text': text,
+ 'filePath': destFile.path
+ };
+
+ _channel.invokeMethod('file', argsMap).whenComplete(() {
+ if (!_useSeparateActivity || Platform.isIOS) destFile.delete();
+ });
+ }
+
+ /// 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 {
+ await init();
+ 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);
+ }
+
+ Map argsMap = {
+ 'title': title,
+ 'mimeTypes': mimeTypes.toList(),
+ 'text': text,
+ 'filePaths': filePaths
+ };
+
+ _channel.invokeMethod('files', argsMap).whenComplete(() {
+ if (!_useSeparateActivity || Platform.isIOS) {
+ for (final file in tempFilesList) {
+ file.delete();
+ }
+ }
+ });
+ ;
+ }
+
+ static Future _init(bool useSeparateActivity) async {
+ _useSeparateActivity = useSeparateActivity;
+ if (Platform.isAndroid) {
+ await _initNativeAndroid();
+ }
+ }
+
+ static Future _initNativeAndroid() async {
+ _channel.invokeMethod('init', _useSeparateActivity);
+ }
+
+ static Future _getDirectoryForShareFile() async {
+ final tempShareDir = await _getBaseTempShareDirectory();
+ final dirForFile = Directory('${tempShareDir.path}/${_getRandomString()}');
+ await 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 8bfc35d..05ae997 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,57 +1,24 @@
-name: esys_flutter_share
-description: A Flutter plugin for sharing images & text with other applications.
-version: 1.0.2
-author: ESYS GmbH
-homepage: https://github.com/esysberlin/esys-flutter-share
+name: esys_flutter_share_plus
+description: A Flutter plugin for sharing images & text with other applications. Fork by Innim
+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
environment:
- sdk: ">=2.0.0-dev.68.0 <3.0.0"
+ sdk: ">=2.12.0 <4.0.0"
+ flutter: ">=2.0.0"
dependencies:
flutter:
sdk: flutter
- path_provider: ^1.1.0
+ path_provider: ^2.0.9
-# 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