diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 44a350d..bc0b3a7 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -33,6 +33,16 @@
+
+
+
+
+
+
+
+
+
+
@@ -46,19 +56,11 @@
android:name="com.google.android.datatransport.runtime.scheduling.jobscheduling.JobInfoSchedulerService"
tools:node="remove">
-
-
-
-
-
diff --git a/dependencies b/dependencies
index 83475a9..7930d97 160000
--- a/dependencies
+++ b/dependencies
@@ -1 +1 @@
-Subproject commit 83475a912851acb6a718ea32a6f0f754d64a50d8
+Subproject commit 7930d9727019344238297d810661bc3e8f724c37
diff --git a/ios/Podfile b/ios/Podfile
index a5993b4..f30e30f 100644
--- a/ios/Podfile
+++ b/ios/Podfile
@@ -43,6 +43,13 @@ target 'Runner' do
target 'RunnerTests' do
inherit! :search_paths
end
+
+ # Share Extension is name of Extension which you created which is in this case 'Share Extension'
+ target 'ShareExtension' do
+ inherit! :search_paths
+ # flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
+ end
+
end
post_install do |installer|
diff --git a/ios/Podfile.lock b/ios/Podfile.lock
index a6414db..301b4b9 100644
--- a/ios/Podfile.lock
+++ b/ios/Podfile.lock
@@ -122,6 +122,8 @@ PODS:
- flutter_secure_storage_darwin (10.0.0):
- Flutter
- FlutterMacOS
+ - flutter_sharing_intent (1.0.1):
+ - Flutter
- flutter_volume_controller (0.0.1):
- Flutter
- gal (1.0.0):
@@ -260,7 +262,7 @@ PODS:
- nanopb/encode (= 3.30910.0)
- nanopb/decode (3.30910.0)
- nanopb/encode (3.30910.0)
- - "no_screenshot (0.0.1+4)":
+ - no_screenshot (0.3.2-beta.3):
- Flutter
- ScreenProtectorKit (~> 1.3.1)
- objective_c (0.0.1):
@@ -350,6 +352,7 @@ DEPENDENCIES:
- flutter_keyboard_visibility_temp_fork (from `.symlinks/plugins/flutter_keyboard_visibility_temp_fork/ios`)
- flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`)
- flutter_secure_storage_darwin (from `.symlinks/plugins/flutter_secure_storage_darwin/darwin`)
+ - flutter_sharing_intent (from `.symlinks/plugins/flutter_sharing_intent/ios`)
- flutter_volume_controller (from `.symlinks/plugins/flutter_volume_controller/ios`)
- gal (from `.symlinks/plugins/gal/darwin`)
- google_mlkit_barcode_scanning (from `.symlinks/plugins/google_mlkit_barcode_scanning/ios`)
@@ -441,6 +444,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/flutter_local_notifications/ios"
flutter_secure_storage_darwin:
:path: ".symlinks/plugins/flutter_secure_storage_darwin/darwin"
+ flutter_sharing_intent:
+ :path: ".symlinks/plugins/flutter_sharing_intent/ios"
flutter_volume_controller:
:path: ".symlinks/plugins/flutter_volume_controller/ios"
gal:
@@ -507,7 +512,8 @@ SPEC CHECKSUMS:
flutter_image_compress_common: 1697a328fd72bfb335507c6bca1a65fa5ad87df1
flutter_keyboard_visibility_temp_fork: 95b2d534bacf6ac62e7fcbe5c2a9e2c2a17ce06f
flutter_local_notifications: a5a732f069baa862e728d839dd2ebb904737effb
- flutter_secure_storage_darwin: ce237a8775b39723566dc72571190a3769d70468
+ flutter_secure_storage_darwin: acdb3f316ed05a3e68f856e0353b133eec373a23
+ flutter_sharing_intent: 0c1e53949f09fa8df8ac2268505687bde8ff264c
flutter_volume_controller: c2be490cb0487e8b88d0d9fc2b7e1c139a4ebccb
gal: baecd024ebfd13c441269ca7404792a7152fde89
google_mlkit_barcode_scanning: 8f5987f244a43fe1167689c548342a5174108159
@@ -529,7 +535,7 @@ SPEC CHECKSUMS:
MLKitCommon: 07c2c33ae5640e5380beaaa6e4b9c249a205542d
MLKitVision: 45e79d68845a2de77e2dd4d7f07947f0ed157b0e
nanopb: fad817b59e0457d11a5dfbde799381cd727c1275
- no_screenshot: 6d183496405a3ab709a67a54e5cd0f639e94729e
+ no_screenshot: 89e778ede9f1e39cc3fb9404d782a42712f2a0b2
objective_c: 89e720c30d716b036faf9c9684022048eee1eee2
package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499
path_provider_foundation: bb55f6dbba17d0dccd6737fe6f7f34fbd0376880
@@ -551,6 +557,6 @@ SPEC CHECKSUMS:
url_launcher_ios: 7a95fa5b60cc718a708b8f2966718e93db0cef1b
video_player_avfoundation: dd410b52df6d2466a42d28550e33e4146928280a
-PODFILE CHECKSUM: c0c524475498435108850efecde62ba98e081c25
+PODFILE CHECKSUM: ae041999f13ba7b2285ff9ad9bc688ed647bbcb7
COCOAPODS: 1.16.2
diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj
index fb716f3..5739f2b 100644
--- a/ios/Runner.xcodeproj/project.pbxproj
+++ b/ios/Runner.xcodeproj/project.pbxproj
@@ -10,6 +10,7 @@
05CF222065FC24670B05B6D0 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1EE71614E1B4F84D6FDC2D /* Pods_RunnerTests.framework */; };
06AA21445BEAF2C45DC9DCDF /* Pods_NotificationService.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A198C9B5D90584C4F96206B2 /* Pods_NotificationService.framework */; };
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
+ 30EBDD0F93DC44E774F3B785 /* Pods_ShareExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E190E82D9973B318A389650B /* Pods_ShareExtension.framework */; };
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
@@ -19,6 +20,7 @@
CA4FDF5DD8F229C30DE512AF /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EE2CCFEE4ABECF33852F7735 /* Pods_Runner.framework */; };
D21FCEAB2D9F2B750088701D /* NotificationService.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = D21FCEA42D9F2B750088701D /* NotificationService.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
D25D4D1E2EF626E30029F805 /* StoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D25D4D1D2EF626E30029F805 /* StoreKit.framework */; };
+ D25D4D7A2EFF41DB0029F805 /* ShareExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = D25D4D702EFF41DB0029F805 /* ShareExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
F3C66D726A2EB28484DF0B10 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 16FBC6F5B58E1C6646F5D447 /* GoogleService-Info.plist */; };
/* End PBXBuildFile section */
@@ -37,6 +39,13 @@
remoteGlobalIDString = D21FCEA32D9F2B750088701D;
remoteInfo = NotificationService;
};
+ D25D4D782EFF41DB0029F805 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 97C146E61CF9000F007C117D /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = D25D4D6F2EFF41DB0029F805;
+ remoteInfo = ShareExtension;
+ };
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
@@ -56,6 +65,7 @@
dstPath = "";
dstSubfolderSpec = 13;
files = (
+ D25D4D7A2EFF41DB0029F805 /* ShareExtension.appex in Embed Foundation Extensions */,
D21FCEAB2D9F2B750088701D /* NotificationService.appex in Embed Foundation Extensions */,
);
name = "Embed Foundation Extensions";
@@ -67,10 +77,12 @@
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 = ""; };
1581CC44342D555EFB889768 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; };
+ 15CEF849B61A620CFB2DC5F1 /* Pods-ShareExtension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ShareExtension.debug.xcconfig"; path = "Target Support Files/Pods-ShareExtension/Pods-ShareExtension.debug.xcconfig"; sourceTree = ""; };
16FBC6F5B58E1C6646F5D447 /* GoogleService-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; name = "GoogleService-Info.plist"; path = "Runner/GoogleService-Info.plist"; sourceTree = ""; };
331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; };
331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
35366FD433E0EFC6EF19A452 /* Pods-NotificationService.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationService.release.xcconfig"; path = "Target Support Files/Pods-NotificationService/Pods-NotificationService.release.xcconfig"; sourceTree = ""; };
+ 39FB86A38393489D58A01B0B /* Pods-ShareExtension.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ShareExtension.profile.xcconfig"; path = "Target Support Files/Pods-ShareExtension/Pods-ShareExtension.profile.xcconfig"; sourceTree = ""; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; };
4D78471482626812FE2468E9 /* Pods-NotificationService.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationService.debug.xcconfig"; path = "Target Support Files/Pods-NotificationService/Pods-NotificationService.debug.xcconfig"; sourceTree = ""; };
6EB462F87F0A23758713308F /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; };
@@ -87,11 +99,15 @@
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 = ""; };
A198C9B5D90584C4F96206B2 /* Pods_NotificationService.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_NotificationService.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ A22BD564F16069E5FCB60767 /* Pods-ShareExtension.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ShareExtension.release.xcconfig"; path = "Target Support Files/Pods-ShareExtension/Pods-ShareExtension.release.xcconfig"; sourceTree = ""; };
B3B27B7FBEEA31DB7793A0C2 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; };
D21FCEA42D9F2B750088701D /* NotificationService.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = NotificationService.appex; sourceTree = BUILT_PRODUCTS_DIR; };
D2265DD42D920142000D99BB /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = ""; };
D25D4D1D2EF626E30029F805 /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = System/Library/Frameworks/StoreKit.framework; sourceTree = SDKROOT; };
+ D25D4D702EFF41DB0029F805 /* ShareExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = ShareExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
+ D25D4D802EFF437F0029F805 /* RunnerDebug.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = RunnerDebug.entitlements; sourceTree = ""; };
DC1EE71614E1B4F84D6FDC2D /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ E190E82D9973B318A389650B /* Pods_ShareExtension.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_ShareExtension.framework; sourceTree = BUILT_PRODUCTS_DIR; };
E96A5ACA32A7118204F050A5 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; };
EE2CCFEE4ABECF33852F7735 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
F02F7A1D63544AA9F23A1085 /* Pods-NotificationService.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationService.profile.xcconfig"; path = "Target Support Files/Pods-NotificationService/Pods-NotificationService.profile.xcconfig"; sourceTree = ""; };
@@ -105,6 +121,13 @@
);
target = D21FCEA32D9F2B750088701D /* NotificationService */;
};
+ D25D4D7E2EFF41DB0029F805 /* Exceptions for "ShareExtension" folder in "ShareExtension" target */ = {
+ isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
+ membershipExceptions = (
+ Info.plist,
+ );
+ target = D25D4D6F2EFF41DB0029F805 /* ShareExtension */;
+ };
/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */
/* Begin PBXFileSystemSynchronizedRootGroup section */
@@ -116,6 +139,14 @@
path = NotificationService;
sourceTree = "";
};
+ D25D4D712EFF41DB0029F805 /* ShareExtension */ = {
+ isa = PBXFileSystemSynchronizedRootGroup;
+ exceptions = (
+ D25D4D7E2EFF41DB0029F805 /* Exceptions for "ShareExtension" folder in "ShareExtension" target */,
+ );
+ path = ShareExtension;
+ sourceTree = "";
+ };
/* End PBXFileSystemSynchronizedRootGroup section */
/* Begin PBXFrameworksBuildPhase section */
@@ -144,6 +175,14 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
+ D25D4D6D2EFF41DB0029F805 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 30EBDD0F93DC44E774F3B785 /* Pods_ShareExtension.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
@@ -172,6 +211,7 @@
9740EEB11CF90186004384FC /* Flutter */,
97C146F01CF9000F007C117D /* Runner */,
D21FCEA52D9F2B750088701D /* NotificationService */,
+ D25D4D712EFF41DB0029F805 /* ShareExtension */,
97C146EF1CF9000F007C117D /* Products */,
331C8082294A63A400263BE5 /* RunnerTests */,
16FBC6F5B58E1C6646F5D447 /* GoogleService-Info.plist */,
@@ -186,6 +226,7 @@
97C146EE1CF9000F007C117D /* Runner.app */,
331C8081294A63A400263BE5 /* RunnerTests.xctest */,
D21FCEA42D9F2B750088701D /* NotificationService.appex */,
+ D25D4D702EFF41DB0029F805 /* ShareExtension.appex */,
);
name = Products;
sourceTree = "";
@@ -193,6 +234,7 @@
97C146F01CF9000F007C117D /* Runner */ = {
isa = PBXGroup;
children = (
+ D25D4D802EFF437F0029F805 /* RunnerDebug.entitlements */,
D2265DD42D920142000D99BB /* Runner.entitlements */,
97C146FA1CF9000F007C117D /* Main.storyboard */,
97C146FD1CF9000F007C117D /* Assets.xcassets */,
@@ -213,6 +255,7 @@
A198C9B5D90584C4F96206B2 /* Pods_NotificationService.framework */,
EE2CCFEE4ABECF33852F7735 /* Pods_Runner.framework */,
DC1EE71614E1B4F84D6FDC2D /* Pods_RunnerTests.framework */,
+ E190E82D9973B318A389650B /* Pods_ShareExtension.framework */,
);
name = Frameworks;
sourceTree = "";
@@ -229,6 +272,9 @@
4D78471482626812FE2468E9 /* Pods-NotificationService.debug.xcconfig */,
35366FD433E0EFC6EF19A452 /* Pods-NotificationService.release.xcconfig */,
F02F7A1D63544AA9F23A1085 /* Pods-NotificationService.profile.xcconfig */,
+ 15CEF849B61A620CFB2DC5F1 /* Pods-ShareExtension.debug.xcconfig */,
+ A22BD564F16069E5FCB60767 /* Pods-ShareExtension.release.xcconfig */,
+ 39FB86A38393489D58A01B0B /* Pods-ShareExtension.profile.xcconfig */,
);
path = Pods;
sourceTree = "";
@@ -274,6 +320,7 @@
);
dependencies = (
D21FCEAA2D9F2B750088701D /* PBXTargetDependency */,
+ D25D4D792EFF41DB0029F805 /* PBXTargetDependency */,
);
name = Runner;
productName = Runner;
@@ -301,6 +348,27 @@
productReference = D21FCEA42D9F2B750088701D /* NotificationService.appex */;
productType = "com.apple.product-type.app-extension";
};
+ D25D4D6F2EFF41DB0029F805 /* ShareExtension */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = D25D4D7F2EFF41DB0029F805 /* Build configuration list for PBXNativeTarget "ShareExtension" */;
+ buildPhases = (
+ 627F39EA1643E08048D23996 /* [CP] Check Pods Manifest.lock */,
+ D25D4D6C2EFF41DB0029F805 /* Sources */,
+ D25D4D6D2EFF41DB0029F805 /* Frameworks */,
+ D25D4D6E2EFF41DB0029F805 /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ fileSystemSynchronizedGroups = (
+ D25D4D712EFF41DB0029F805 /* ShareExtension */,
+ );
+ name = ShareExtension;
+ productName = ShareExtension;
+ productReference = D25D4D702EFF41DB0029F805 /* ShareExtension.appex */;
+ productType = "com.apple.product-type.app-extension";
+ };
/* End PBXNativeTarget section */
/* Begin PBXProject section */
@@ -308,7 +376,7 @@
isa = PBXProject;
attributes = {
BuildIndependentTargetsInParallel = YES;
- LastSwiftUpdateCheck = 1620;
+ LastSwiftUpdateCheck = 2610;
LastUpgradeCheck = 1510;
ORGANIZATIONNAME = "";
TargetAttributes = {
@@ -323,6 +391,9 @@
D21FCEA32D9F2B750088701D = {
CreatedOnToolsVersion = 16.2;
};
+ D25D4D6F2EFF41DB0029F805 = {
+ CreatedOnToolsVersion = 26.1.1;
+ };
};
};
buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
@@ -341,6 +412,7 @@
97C146ED1CF9000F007C117D /* Runner */,
331C8080294A63A400263BE5 /* RunnerTests */,
D21FCEA32D9F2B750088701D /* NotificationService */,
+ D25D4D6F2EFF41DB0029F805 /* ShareExtension */,
);
};
/* End PBXProject section */
@@ -372,6 +444,13 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
+ D25D4D6E2EFF41DB0029F805 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
@@ -452,6 +531,28 @@
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin\n";
};
+ 627F39EA1643E08048D23996 /* [CP] Check Pods Manifest.lock */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputFileListPaths = (
+ );
+ inputPaths = (
+ "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+ "${PODS_ROOT}/Manifest.lock",
+ );
+ name = "[CP] Check Pods Manifest.lock";
+ outputFileListPaths = (
+ );
+ outputPaths = (
+ "$(DERIVED_FILE_DIR)/Pods-ShareExtension-checkManifestLockResult.txt",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+ showEnvVarsInLog = 0;
+ };
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
@@ -533,6 +634,13 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
+ D25D4D6C2EFF41DB0029F805 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
@@ -546,6 +654,11 @@
target = D21FCEA32D9F2B750088701D /* NotificationService */;
targetProxy = D21FCEA92D9F2B750088701D /* PBXContainerItemProxy */;
};
+ D25D4D792EFF41DB0029F805 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = D25D4D6F2EFF41DB0029F805 /* ShareExtension */;
+ targetProxy = D25D4D782EFF41DB0029F805 /* PBXContainerItemProxy */;
+ };
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
@@ -631,6 +744,7 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
+ CUSTOM_GROUP_ID = group.eu.twonly.shareIntent;
DEVELOPMENT_TEAM = CN332ZUGRP;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
@@ -827,8 +941,9 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES;
CLANG_ENABLE_MODULES = YES;
- CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
+ CODE_SIGN_ENTITLEMENTS = Runner/RunnerDebug.entitlements;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
+ CUSTOM_GROUP_ID = group.eu.twonly.shareIntent;
DEVELOPMENT_TEAM = CN332ZUGRP;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
@@ -863,6 +978,7 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
+ CUSTOM_GROUP_ID = group.eu.twonly.shareIntent;
DEVELOPMENT_TEAM = CN332ZUGRP;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
@@ -1004,6 +1120,133 @@
};
name = Profile;
};
+ D25D4D7B2EFF41DB0029F805 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 15CEF849B61A620CFB2DC5F1 /* Pods-ShareExtension.debug.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CODE_SIGN_ENTITLEMENTS = ShareExtension/ShareExtensionDebug.entitlements;
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ CUSTOM_GROUP_ID = group.eu.twonly.shareIntent;
+ DEVELOPMENT_TEAM = CN332ZUGRP;
+ ENABLE_USER_SCRIPT_SANDBOXING = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu17;
+ GENERATE_INFOPLIST_FILE = YES;
+ INFOPLIST_FILE = ShareExtension/Info.plist;
+ INFOPLIST_KEY_CFBundleDisplayName = ShareExtension;
+ INFOPLIST_KEY_NSHumanReadableCopyright = "";
+ IPHONEOS_DEPLOYMENT_TARGET = 26.1;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ "@executable_path/../../Frameworks",
+ );
+ LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
+ MARKETING_VERSION = 1.0;
+ MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
+ MTL_FAST_MATH = YES;
+ PRODUCT_BUNDLE_IDENTIFIER = eu.twonly.ShareExtension;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SKIP_INSTALL = YES;
+ STRING_CATALOG_GENERATE_SYMBOLS = YES;
+ SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
+ SWIFT_APPROACHABLE_CONCURRENCY = YES;
+ SWIFT_EMIT_LOC_STRINGS = YES;
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Debug;
+ };
+ D25D4D7C2EFF41DB0029F805 /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = A22BD564F16069E5FCB60767 /* Pods-ShareExtension.release.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ CUSTOM_GROUP_ID = group.eu.twonly.shareIntent;
+ DEVELOPMENT_TEAM = CN332ZUGRP;
+ ENABLE_USER_SCRIPT_SANDBOXING = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu17;
+ GENERATE_INFOPLIST_FILE = YES;
+ INFOPLIST_FILE = ShareExtension/Info.plist;
+ INFOPLIST_KEY_CFBundleDisplayName = ShareExtension;
+ INFOPLIST_KEY_NSHumanReadableCopyright = "";
+ IPHONEOS_DEPLOYMENT_TARGET = 26.1;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ "@executable_path/../../Frameworks",
+ );
+ LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
+ MARKETING_VERSION = 1.0;
+ MTL_FAST_MATH = YES;
+ PRODUCT_BUNDLE_IDENTIFIER = eu.twonly.ShareExtension;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SKIP_INSTALL = YES;
+ STRING_CATALOG_GENERATE_SYMBOLS = YES;
+ SWIFT_APPROACHABLE_CONCURRENCY = YES;
+ SWIFT_EMIT_LOC_STRINGS = YES;
+ SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Release;
+ };
+ D25D4D7D2EFF41DB0029F805 /* Profile */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 39FB86A38393489D58A01B0B /* Pods-ShareExtension.profile.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ CUSTOM_GROUP_ID = group.eu.twonly.shareIntent;
+ DEVELOPMENT_TEAM = CN332ZUGRP;
+ ENABLE_USER_SCRIPT_SANDBOXING = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu17;
+ GENERATE_INFOPLIST_FILE = YES;
+ INFOPLIST_FILE = ShareExtension/Info.plist;
+ INFOPLIST_KEY_CFBundleDisplayName = ShareExtension;
+ INFOPLIST_KEY_NSHumanReadableCopyright = "";
+ IPHONEOS_DEPLOYMENT_TARGET = 26.1;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ "@executable_path/../../Frameworks",
+ );
+ LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
+ MARKETING_VERSION = 1.0;
+ MTL_FAST_MATH = YES;
+ PRODUCT_BUNDLE_IDENTIFIER = eu.twonly.ShareExtension;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SKIP_INSTALL = YES;
+ STRING_CATALOG_GENERATE_SYMBOLS = YES;
+ SWIFT_APPROACHABLE_CONCURRENCY = YES;
+ SWIFT_EMIT_LOC_STRINGS = YES;
+ SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Profile;
+ };
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
@@ -1047,6 +1290,16 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
+ D25D4D7F2EFF41DB0029F805 /* Build configuration list for PBXNativeTarget "ShareExtension" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ D25D4D7B2EFF41DB0029F805 /* Debug */,
+ D25D4D7C2EFF41DB0029F805 /* Release */,
+ D25D4D7D2EFF41DB0029F805 /* Profile */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
/* End XCConfigurationList section */
};
rootObject = 97C146E61CF9000F007C117D /* Project object */;
diff --git a/ios/Runner/AppDelegate.swift b/ios/Runner/AppDelegate.swift
index ae7cbe1..b36ae26 100644
--- a/ios/Runner/AppDelegate.swift
+++ b/ios/Runner/AppDelegate.swift
@@ -3,6 +3,7 @@ import Flutter
import Foundation
import UIKit
import UserNotifications
+import flutter_sharing_intent
@main
@objc class AppDelegate: FlutterAppDelegate, FlutterImplicitEngineDelegate {
@@ -14,6 +15,17 @@ import UserNotifications
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
+ override func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
+
+ let sharingIntent = SwiftFlutterSharingIntentPlugin.instance
+ if sharingIntent.hasSameSchemePrefix(url: url) {
+ return sharingIntent.application(app, open: url, options: options)
+ }
+
+ // Proceed url handling for other Flutter libraries like app_links
+ return super.application(app, open: url, options:options)
+ }
+
func didInitializeImplicitFlutterEngine(_ engineBridge: FlutterImplicitEngineBridge) {
GeneratedPluginRegistrant.register(with: engineBridge.pluginRegistry)
}
diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist
index d00d31e..8b4c63d 100644
--- a/ios/Runner/Info.plist
+++ b/ios/Runner/Info.plist
@@ -87,9 +87,21 @@
UIInterfaceOrientationLandscapeLeft
UIInterfaceOrientationLandscapeRight
-
firebase_performance_collection_deactivated
-
+
+ AppGroupId
+ $(CUSTOM_GROUP_ID)
+ CFBundleURLTypes
+
+
+ CFBundleTypeRole
+ Editor
+ CFBundleURLSchemes
+
+ SharingMedia-$(PRODUCT_BUNDLE_IDENTIFIER)
+
+
+
diff --git a/ios/Runner/RunnerDebug.entitlements b/ios/Runner/RunnerDebug.entitlements
new file mode 100644
index 0000000..dc9d4cc
--- /dev/null
+++ b/ios/Runner/RunnerDebug.entitlements
@@ -0,0 +1,20 @@
+
+
+
+
+ aps-environment
+ development
+ com.apple.developer.associated-domains
+
+ applinks:me.twonly.eu
+
+ com.apple.security.application-groups
+
+ group.eu.twonly.shareIntent
+
+ keychain-access-groups
+
+ $(AppIdentifierPrefix)eu.twonly.shared
+
+
+
diff --git a/ios/ShareExtension/Base.lproj/MainInterface.storyboard b/ios/ShareExtension/Base.lproj/MainInterface.storyboard
new file mode 100644
index 0000000..286a508
--- /dev/null
+++ b/ios/ShareExtension/Base.lproj/MainInterface.storyboard
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ios/ShareExtension/FSIShareViewController.swift b/ios/ShareExtension/FSIShareViewController.swift
new file mode 100644
index 0000000..9a2e198
--- /dev/null
+++ b/ios/ShareExtension/FSIShareViewController.swift
@@ -0,0 +1,553 @@
+// SOURCE: https://github.com/bhagat-techind/flutter_sharing_intent/blob/main/example/ios/Share%20Extension/FSIShareViewController.swift
+
+// FSIShareViewController.swift
+// Merged, optimized controller: uses RSI architecture with all FSI features preserved
+// Uses model name `SharingFile` (same fields as SharedMediaFile) where `value` = path
+
+import AVFoundation
+import MobileCoreServices
+import Social
+import UIKit
+import UniformTypeIdentifiers
+
+public let kSchemePrefix = "SharingMedia"
+public let kUserDefaultsKey = "SharingKey"
+public let kUserDefaultsMessageKey = "SharingMessageKey"
+public let kAppGroupIdKey = "AppGroupId"
+public let kAppChannel = "flutter_sharing_intent"
+
+@available(swift, introduced: 5.0)
+open class FSIShareViewController: SLComposeServiceViewController {
+ // MARK: - Config
+ private(set) var hostAppBundleIdentifier: String = ""
+ private(set) var appGroupId: String = ""
+
+ // Results
+ private var sharedMedia: [SharingFile] = []
+
+ // Debug
+ private let debugLogs = false
+
+ // MARK: - Lifecycle
+ open override func viewDidLoad() {
+ super.viewDidLoad()
+ loadIds()
+ }
+
+ open override func isContentValid() -> Bool {
+ return true
+ }
+
+ open override func didSelectPost() {
+ if self.sharedMedia.isEmpty {
+ if let text = self.contentText, !text.isEmpty {
+ self.sharedMedia.append(
+ SharingFile(value: text, thumbnail: nil, duration: nil, type: .text)
+ )
+ self.saveAndRedirect(message: text)
+ return
+ }
+ self.completeAndExit()
+ } else {
+ self.saveAndRedirect()
+ }
+ }
+
+ open override func viewDidAppear(_ animated: Bool) {
+ super.viewDidAppear(animated)
+ // Process attachments automatically on appear like original FSI
+ processAttachments()
+ }
+
+ // MARK: - Load Ids
+ private func loadIds() {
+ let shareExtId = Bundle.main.bundleIdentifier ?? ""
+ if let idx = shareExtId.lastIndex(of: ".") {
+ hostAppBundleIdentifier = String(shareExtId[.. media, else fallback to complete
+ if !self.sharedMedia.isEmpty {
+ self.saveAndRedirect()
+ } else {
+ print("FSIShare: No shared media → stopping.")
+ self.completeAndExit()
+ }
+ }
+ }
+
+ // MARK: - Individual handlers (preserve FSI behavior)
+ private func handleTextItem(data: NSSecureCoding?, index: Int, total: Int) {
+ if let s = data as? String {
+ sharedMedia.append(SharingFile(value: s, thumbnail: nil, duration: nil, type: .text))
+ } else if let url = data as? URL {
+ sharedMedia.append(SharingFile(value: url.absoluteString, thumbnail: nil, duration: nil, type: .url))
+ }
+
+ }
+
+ private func handleUrlItem(data: NSSecureCoding?, index: Int, total: Int) {
+ if let url = data as? URL {
+ sharedMedia.append(SharingFile(value: url.absoluteString, thumbnail: nil, duration: nil, type: .url))
+ } else if let s = data as? String {
+ sharedMedia.append(SharingFile(value: s, thumbnail: nil, duration: nil, type: .text))
+ }
+
+ }
+
+ private func handleImageItem(data: NSSecureCoding?, index: Int, total: Int) {
+ // data can be URL, UIImage, or Data
+ if let url = data as? URL {
+ let filename = getFileName(from: url, type: .image)
+ if let dst = containerURL()?.appendingPathComponent(filename) {
+ if copyFile(at: url, to: dst) {
+ sharedMedia.append(SharingFile(value: dst.absoluteString, mimeType: url.mimeType(), thumbnail: nil, duration: nil, type: .image))
+ }
+ }
+ } else if let img = data as? UIImage {
+ if let saved = writeTempImage(img) {
+ sharedMedia.append(saved)
+ }
+ } else if let raw = data as? Data, let img = UIImage(data: raw) {
+ if let saved = writeTempImage(img) {
+ sharedMedia.append(saved)
+ }
+ }
+
+ }
+
+ private func handleVideoItem(data: NSSecureCoding?, index: Int, total: Int) {
+ if let url = data as? URL {
+ let filename = getFileName(from: url, type: .video)
+ if let dst = containerURL()?.appendingPathComponent(filename) {
+ if copyFile(at: url, to: dst) {
+ if let m = getSharedMediaFile(forVideo: dst) {
+ sharedMedia.append(m)
+ }
+ }
+ }
+ }
+
+ }
+
+ private func handleFileItem(data: NSSecureCoding?, index: Int, total: Int) {
+ if let url = data as? URL {
+ let filename = getFileName(from: url, type: .file)
+ if let dst = containerURL()?.appendingPathComponent(filename) {
+ if copyFile(at: url, to: dst) {
+ sharedMedia.append(SharingFile(value: dst.absoluteString, mimeType: url.mimeType(), thumbnail: nil, duration: nil, type: .file))
+ }
+ }
+ }
+ else if let raw = data as? Data {
+ let filename = "File_\(UUID().uuidString)"
+ if let dst = containerURL()?.appendingPathComponent(filename) {
+ do {
+ try raw.write(to: dst)
+ sharedMedia.append(SharingFile(value: dst.absoluteString, mimeType: "application/octet-stream", thumbnail: nil, duration: nil, type: .file))
+ } catch {}
+ }
+ }
+
+
+ }
+
+ // MARK: - Helpers: write temp image
+ private func writeTempImage(_ image: UIImage) -> SharingFile? {
+ guard let container = containerURL() else { return nil }
+ let tempName = "TempImage_\(UUID().uuidString).png"
+ let dst = container.appendingPathComponent(tempName)
+ do {
+ if let d = image.pngData() {
+ try d.write(to: dst)
+ let decoded = dst.absoluteString.removingPercentEncoding ?? dst.absoluteString
+ return SharingFile(value: decoded, mimeType: "image/png", thumbnail: nil, duration: nil, type: .image)
+ }
+ } catch {
+ log("writeTempImage error: \(error)")
+ }
+ return nil
+ }
+
+
+ private func saveAndRedirect(message: String? = nil) {
+ let ud = UserDefaults(suiteName: appGroupId)
+ if !sharedMedia.isEmpty {
+ if let data = try? JSONEncoder().encode(sharedMedia) {
+ ud?.set(data, forKey: kUserDefaultsKey)
+ }
+ }
+ ud?.set(message, forKey: kUserDefaultsMessageKey)
+ ud?.synchronize()
+ redirectToHostApp()
+ }
+
+
+ private func redirectToHostApp() {
+ // kept for compatibility (RSI style)
+ loadIds()
+ // let raw = "\(kSchemePrefix)-\(hostAppBundleIdentifier):share"
+ let raw = "\(kSchemePrefix)-\(hostAppBundleIdentifier)://dataUrl=\(kUserDefaultsKey)"
+ guard let url = URL(string: raw.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? raw) else { completeAndExit(); return }
+
+ var responder: UIResponder? = self
+ if #available(iOS 18.0, *) {
+ while responder != nil {
+ if let app = responder as? UIApplication { app.open(url, options: [:], completionHandler: nil) }
+ responder = responder?.next
+ }
+ } else {
+ let sel = sel_registerName("openURL:")
+ while responder != nil {
+ if responder?.responds(to: sel) ?? false { _ = responder?.perform(sel, with: url) }
+ responder = responder?.next
+ }
+ }
+ extensionContext?.completeRequest(returningItems: [], completionHandler: nil)
+ }
+
+ // MARK: - File / thumbnail / metadata helpers
+ func getExtension(from url: URL, type: SharingFileType) -> String {
+ let parts = url.lastPathComponent.components(separatedBy: ".")
+ var ex: String? = nil
+ if parts.count > 1 { ex = parts.last }
+ if ex == nil {
+ switch type {
+ case .image: ex = "png"
+ case .video: ex = "mp4"
+ case .file: ex = "txt"
+ case .text: ex = "txt"
+ case .url: ex = "txt"
+ }
+ }
+ return ex ?? "bin"
+ }
+
+ func getFileName(from url: URL, type: SharingFileType) -> String {
+ var name = url.lastPathComponent
+ if name.isEmpty { name = UUID().uuidString + "." + getExtension(from: url, type: type) }
+ return name
+ }
+
+ func copyFile(at srcURL: URL, to dstURL: URL) -> Bool {
+ do {
+ if FileManager.default.fileExists(atPath: dstURL.path) { try FileManager.default.removeItem(at: dstURL) }
+ try FileManager.default.copyItem(at: srcURL, to: dstURL)
+ return true
+ } catch {
+ log("copyFile error: \(error)")
+ return false
+ }
+ }
+
+ private func getSharedMediaFile(forVideo: URL) -> SharingFile? {
+ let asset = AVAsset(url: forVideo)
+ let duration = (CMTimeGetSeconds(asset.duration) * 1000).rounded()
+ let thumbnailPath = getThumbnailPath(for: forVideo)
+
+ if FileManager.default.fileExists(atPath: thumbnailPath.path) {
+ return SharingFile(value: forVideo.absoluteString, mimeType: forVideo.mimeType(), thumbnail: thumbnailPath.absoluteString, duration: Int(duration), type: .video)
+ }
+
+ let gen = AVAssetImageGenerator(asset: asset)
+ gen.appliesPreferredTrackTransform = true
+ gen.maximumSize = CGSize(width: 360, height: 360)
+
+ // Use first second or zero
+ let time = CMTime(seconds: min(1.0, CMTimeGetSeconds(asset.duration)), preferredTimescale: 600)
+ do {
+ let cg = try gen.copyCGImage(at: time, actualTime: nil)
+ if let data = UIImage(cgImage: cg).jpegData(compressionQuality: 0.8) {
+ try data.write(to: thumbnailPath)
+ return SharingFile(value: forVideo.absoluteString, mimeType: forVideo.mimeType(), thumbnail: thumbnailPath.absoluteString, duration: Int(duration), type: .video)
+ }
+ } catch {
+ log("getSharedMediaFile thumbnail error: \(error)")
+ }
+
+ // fallback
+ return SharingFile(value: forVideo.absoluteString, mimeType: forVideo.mimeType(), thumbnail: nil, duration: Int(duration), type: .video)
+ }
+
+ private func getThumbnailPath(for url: URL) -> URL {
+ guard let container = containerURL() else { fatalError("App group not configured or missing") }
+ let fileName = Data(url.lastPathComponent.utf8).base64EncodedString().replacingOccurrences(of: "=", with: "")
+ return container.appendingPathComponent("\(fileName).jpg")
+ }
+
+ private func containerURL() -> URL? {
+ FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: appGroupId)
+ }
+
+ private func completeAndExit() {
+ extensionContext?.completeRequest(returningItems: [], completionHandler: nil)
+ }
+
+ private func dismissWithError() {
+ log("[ERROR] Error loading data!")
+ let alert = UIAlertController(title: "Error", message: "Error loading data", preferredStyle: .alert)
+ alert.addAction(UIAlertAction(title: "OK", style: .cancel) { _ in self.dismiss(animated: true, completion: nil) })
+ present(alert, animated: true, completion: nil)
+ extensionContext?.completeRequest(returningItems: [], completionHandler: nil)
+ }
+
+ private func writeTempFile(_ image: UIImage, to dstURL: URL) -> Bool {
+ do {
+ if FileManager.default.fileExists(atPath: dstURL.path) { try FileManager.default.removeItem(at: dstURL) }
+ let pngData = image.pngData()
+ try pngData?.write(to: dstURL)
+ return true
+ } catch (let error) {
+ log("writeTempFile error: \(error)")
+ return false
+ }
+ }
+
+ private func saveToUserDefaults(data: [SharingFile]) {
+ let ud = UserDefaults(suiteName: appGroupId)
+ if let enc = try? JSONEncoder().encode(data) { ud?.set(enc, forKey: kUserDefaultsKey); ud?.synchronize() }
+ }
+
+ // MARK: - Logging
+ private func log(_ s: String) { if debugLogs { print("[FSIShareVC] \(s)") } }
+
+}
+
+// MARK: - Extensions
+extension URL {
+ func mimeType() -> String {
+ if #available(iOS 14.0, *) {
+ if let ut = UTType(filenameExtension: self.pathExtension), let m = ut.preferredMIMEType { return m }
+ } else {
+ if let uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, self.pathExtension as NSString, nil)?.takeRetainedValue() {
+ if let mimetype = UTTypeCopyPreferredTagWithClass(uti, kUTTagClassMIMEType)?.takeRetainedValue() { return mimetype as String }
+ }
+ }
+ return "application/octet-stream"
+ }
+}
+
+extension NSItemProvider {
+ var isImage: Bool { return hasItemConformingToTypeIdentifier(UType.image) }
+ var isMovie: Bool { return hasItemConformingToTypeIdentifier(UType.movie) }
+ var isText: Bool {
+ hasItemConformingToTypeIdentifier(UType.plainText) || hasItemConformingToTypeIdentifier(UType.text)
+ }
+ var isURL: Bool { return hasItemConformingToTypeIdentifier(UType.url) }
+ var isFile: Bool { return hasItemConformingToTypeIdentifier(UType.fileURL) }
+ var isData:Bool { return hasItemConformingToTypeIdentifier(UType.data) }
+ var isItem: Bool { hasItemConformingToTypeIdentifier(UType.item) }
+
+}
+
+extension Array {
+ subscript(safe index: UInt) -> Element? { return Int(index) < count ? self[Int(index)] : nil }
+}
+
+
+class SharingFile: Codable {
+ var value: String
+ var mimeType: String?
+ var thumbnail: String?; // video thumbnail
+ var duration: Int?; // video duration in milliseconds
+ var type: SharingFileType;
+ var message: String? // post message
+
+ enum CodingKeys: String, CodingKey {
+ case value
+ case mimeType
+ case thumbnail
+ case duration
+ case type
+ case message
+ }
+
+ init(value: String, mimeType: String? = nil, thumbnail: String?, duration: Int?,
+ type: SharingFileType, message: String?=nil) {
+ self.value = value
+ self.mimeType = mimeType
+ self.thumbnail = thumbnail
+ self.duration = duration
+ self.type = type
+ self.message = message
+ }
+
+ // Debug method to print out SharedMediaFile details in the console
+ func toString() {
+ print("[SharingFile] \n\tvalue: \(self.value)\n\tthumbnail: \(self.thumbnail ?? "--" )\n\tduration: \(self.duration ?? 0)\n\ttype: \(self.type)\n\tmimeType: \(String(describing: self.mimeType))\n\tmessage: \(String(describing: self.message))")
+ }
+}
+
+
+enum SharingFileType: Int, Codable {
+ case text
+ case url
+ case image
+ case video
+ case file
+}
+
+// Unified UTType → works on iOS 11–18
+enum UType {
+ static var image: String {
+ if #available(iOS 14.0, *) {
+ return UTType.image.identifier
+ } else {
+ return kUTTypeImage as String // old API
+ }
+ }
+
+ static var movie: String {
+ if #available(iOS 14.0, *) {
+ return UTType.movie.identifier
+ } else {
+ return kUTTypeMovie as String
+ }
+ }
+
+
+ static var url: String {
+ if #available(iOS 14.0, *) {
+ return UTType.url.identifier
+ } else {
+ return kUTTypeURL as String
+ }
+ }
+
+ static var fileURL: String {
+ if #available(iOS 14.0, *) {
+ return UTType.fileURL.identifier
+ } else {
+ return kUTTypeFileURL as String
+ }
+ }
+
+ static var text: String {
+ if #available(iOS 14.0, *) {
+ return UTType.text.identifier
+ } else {
+ return kUTTypeText as String
+ }
+ }
+
+ static var plainText: String {
+ if #available(iOS 14.0, *) {
+ return UTType.plainText.identifier
+ } else {
+ return kUTTypePlainText as String
+ }
+ }
+
+ static var data: String {
+ if #available(iOS 14.0, *) {
+ return UTType.data.identifier
+ } else {
+ return kUTTypeData as String
+ }
+ }
+
+ static var item: String {
+ if #available(iOS 14.0, *) {
+ return UTType.item.identifier
+ } else {
+ return kUTTypeItem as String
+ }
+ }
+}
diff --git a/ios/ShareExtension/Info.plist b/ios/ShareExtension/Info.plist
new file mode 100644
index 0000000..3e8521b
--- /dev/null
+++ b/ios/ShareExtension/Info.plist
@@ -0,0 +1,35 @@
+
+
+
+
+ AppGroupId
+ $(CUSTOM_GROUP_ID)
+ CFBundleVersion
+ $(FLUTTER_BUILD_NUMBER)
+ NSExtension
+
+ NSExtensionMainStoryboard
+ MainInterface
+ NSExtensionPointIdentifier
+ com.apple.share-services
+ NSExtensionAttributes
+
+ PHSupportedMediaTypes
+
+ Video
+ Image
+
+
+ NSExtensionActivationRule
+
+ NSExtensionActivationSupportsWebURLWithMaxCount
+ 1
+ NSExtensionActivationSupportsImageWithMaxCount
+ 1
+ NSExtensionActivationSupportsMovieWithMaxCount
+ 1
+
+
+
+
+
diff --git a/ios/ShareExtension/ShareExtensionDebug.entitlements b/ios/ShareExtension/ShareExtensionDebug.entitlements
new file mode 100644
index 0000000..bb03fc7
--- /dev/null
+++ b/ios/ShareExtension/ShareExtensionDebug.entitlements
@@ -0,0 +1,10 @@
+
+
+
+
+ com.apple.security.application-groups
+
+ group.eu.twonly.shareIntent
+
+
+
diff --git a/ios/ShareExtension/ShareViewController.swift b/ios/ShareExtension/ShareViewController.swift
new file mode 100644
index 0000000..668bd61
--- /dev/null
+++ b/ios/ShareExtension/ShareViewController.swift
@@ -0,0 +1,3 @@
+class ShareViewController: FSIShareViewController {
+
+}
\ No newline at end of file
diff --git a/lib/src/services/intent/links.intent.dart b/lib/src/services/intent/links.intent.dart
new file mode 100644
index 0000000..f951695
--- /dev/null
+++ b/lib/src/services/intent/links.intent.dart
@@ -0,0 +1,180 @@
+import 'dart:async';
+import 'dart:convert';
+import 'dart:io';
+import 'dart:typed_data';
+import 'package:collection/collection.dart';
+import 'package:drift/drift.dart' show Value;
+import 'package:flutter/material.dart';
+import 'package:flutter_sharing_intent/model/sharing_file.dart';
+import 'package:twonly/globals.dart';
+import 'package:twonly/src/database/tables/mediafiles.table.dart';
+import 'package:twonly/src/database/twonly.db.dart';
+import 'package:twonly/src/services/api/mediafiles/upload.service.dart';
+import 'package:twonly/src/services/signal/session.signal.dart';
+import 'package:twonly/src/utils/log.dart';
+import 'package:twonly/src/utils/misc.dart';
+import 'package:twonly/src/views/camera/share_image_editor_view.dart';
+import 'package:twonly/src/views/chats/add_new_user.view.dart';
+import 'package:twonly/src/views/components/alert_dialog.dart';
+import 'package:twonly/src/views/contact/contact.view.dart';
+import 'package:twonly/src/views/public_profile.view.dart';
+
+Future handleIntentUrl(BuildContext context, Uri uri) async {
+ if (!uri.scheme.startsWith('http')) return;
+ if (uri.host != 'me.twonly.eu') return;
+ if (uri.hasEmptyPath) return;
+
+ final publicKey = uri.hasFragment ? uri.fragment : null;
+ final userPaths = uri.path.split('/');
+ if (userPaths.length != 2) return;
+ final username = userPaths[1];
+
+ if (!context.mounted) return;
+
+ if (username == gUser.username) {
+ await Navigator.push(
+ context,
+ MaterialPageRoute(
+ builder: (context) {
+ return const PublicProfileView();
+ },
+ ),
+ );
+ return;
+ }
+
+ Log.info(
+ 'Opened via deep link!: username = $username public_key = ${uri.fragment}',
+ );
+ final contacts = await twonlyDB.contactsDao.getContactsByUsername(username);
+ if (contacts.isEmpty) {
+ if (!context.mounted) return;
+ Uint8List? publicKeyBytes;
+ if (publicKey != null) {
+ publicKeyBytes = base64Url.decode(publicKey);
+ }
+ await Navigator.push(
+ context,
+ MaterialPageRoute(
+ builder: (context) {
+ return AddNewUserView(
+ username: username,
+ publicKey: publicKeyBytes,
+ );
+ },
+ ),
+ );
+ } else if (publicKey != null) {
+ try {
+ final contact = contacts.first;
+ final storedPublicKey = await getPublicKeyFromContact(contact.userId);
+ final receivedPublicKey = base64Url.decode(publicKey);
+ if (storedPublicKey == null ||
+ receivedPublicKey.isEmpty ||
+ !context.mounted) {
+ return;
+ }
+ if (storedPublicKey.equals(receivedPublicKey)) {
+ if (!contact.verified) {
+ final markAsVerified = await showAlertDialog(
+ context,
+ context.lang.linkFromUsername(contact.username),
+ context.lang.linkFromUsernameLong,
+ customOk: context.lang.gotLinkFromFriend,
+ );
+ if (markAsVerified) {
+ await twonlyDB.contactsDao.updateContact(
+ contact.userId,
+ const ContactsCompanion(
+ verified: Value(true),
+ ),
+ );
+ }
+ } else {
+ await Navigator.push(
+ context,
+ MaterialPageRoute(
+ builder: (context) {
+ return ContactView(contact.userId);
+ },
+ ),
+ );
+ }
+ } else {
+ await showAlertDialog(
+ context,
+ context.lang.couldNotVerifyUsername(contact.username),
+ context.lang.linkPubkeyDoesNotMatch,
+ customCancel: '',
+ );
+ }
+ } catch (e) {
+ Log.warn(e);
+ }
+ }
+}
+
+Future handleIntentMediaFile(
+ BuildContext context,
+ String filePath,
+ MediaType type,
+) async {
+ final file = File(filePath);
+ if (!file.existsSync()) {
+ Log.error('The shared intent file does not exits.');
+ return;
+ }
+
+ final newMediaService = await initializeMediaUpload(
+ type,
+ gUser.defaultShowTime,
+ );
+ if (newMediaService == null) {
+ Log.error('Could not create new media file for intent shared file');
+ return;
+ }
+
+ file.copySync(newMediaService.originalPath.path);
+ if (!context.mounted) return;
+
+ await Navigator.push(
+ context,
+ MaterialPageRoute(
+ builder: (context) => ShareImageEditorView(
+ mediaFileService: newMediaService,
+ sharedFromGallery: true,
+ ),
+ ),
+ );
+}
+
+Future handleIntentSharedFile(
+ BuildContext context,
+ List files,
+) async {
+ for (final file in files) {
+ if (file.value == null) {
+ Log.error(
+ 'Got shared media, but value is empty: getMediaStream ${file.mimeType}',
+ );
+ continue;
+ }
+ Log.info('got file via intent ${file.type} ${file.value}');
+
+ switch (file.type) {
+ case SharedMediaType.URL:
+ await handleIntentUrl(context, Uri.parse(file.value!));
+ case SharedMediaType.IMAGE:
+ var type = MediaType.image;
+ if (file.value!.endsWith('.gif')) {
+ type = MediaType.gif;
+ }
+ await handleIntentMediaFile(context, file.value!, type);
+ case SharedMediaType.VIDEO:
+ await handleIntentMediaFile(context, file.value!, MediaType.video);
+ // ignore: no_default_cases
+ default:
+ }
+ break; // only handle one file...
+ }
+}
diff --git a/lib/src/views/camera/camera_preview_components/main_camera_controller.dart b/lib/src/views/camera/camera_preview_components/main_camera_controller.dart
index 6c30d5a..c6543a7 100644
--- a/lib/src/views/camera/camera_preview_components/main_camera_controller.dart
+++ b/lib/src/views/camera/camera_preview_components/main_camera_controller.dart
@@ -227,7 +227,8 @@ class MainCameraController {
content: Text(
globalRootScaffoldMessengerKey.currentContext?.lang
.verifiedPublicKey(
- getContactDisplayName(contact)) ??
+ getContactDisplayName(contact),
+ ) ??
'',
),
duration: const Duration(seconds: 6),
diff --git a/lib/src/views/home.view.dart b/lib/src/views/home.view.dart
index bb065a4..b87ab11 100644
--- a/lib/src/views/home.view.dart
+++ b/lib/src/views/home.view.dart
@@ -1,29 +1,22 @@
import 'dart:async';
-import 'dart:convert';
-import 'dart:typed_data';
import 'package:app_links/app_links.dart';
-import 'package:collection/collection.dart';
-import 'package:drift/drift.dart' show Value;
import 'package:flutter/material.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
+import 'package:flutter_sharing_intent/flutter_sharing_intent.dart';
+import 'package:flutter_sharing_intent/model/sharing_file.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:twonly/globals.dart';
-import 'package:twonly/src/database/twonly.db.dart';
+import 'package:twonly/src/services/intent/links.intent.dart';
import 'package:twonly/src/services/mediafiles/mediafile.service.dart';
import 'package:twonly/src/services/notifications/setup.notifications.dart';
-import 'package:twonly/src/services/signal/session.signal.dart';
import 'package:twonly/src/utils/log.dart';
import 'package:twonly/src/utils/misc.dart';
import 'package:twonly/src/views/camera/camera_preview_components/camera_preview.dart';
import 'package:twonly/src/views/camera/camera_preview_components/camera_preview_controller_view.dart';
import 'package:twonly/src/views/camera/camera_preview_components/main_camera_controller.dart';
import 'package:twonly/src/views/camera/share_image_editor_view.dart';
-import 'package:twonly/src/views/chats/add_new_user.view.dart';
import 'package:twonly/src/views/chats/chat_list.view.dart';
-import 'package:twonly/src/views/components/alert_dialog.dart';
-import 'package:twonly/src/views/contact/contact.view.dart';
import 'package:twonly/src/views/memories/memories.view.dart';
-import 'package:twonly/src/views/public_profile.view.dart';
void Function(int) globalUpdateOfHomeViewPageIndex = (a) {};
@@ -61,6 +54,7 @@ class HomeViewState extends State {
final MainCameraController _mainCameraController = MainCameraController();
final PageController homeViewPageController = PageController(initialPage: 1);
+ late StreamSubscription> _intentStreamSub;
late StreamSubscription _deepLinkSub;
double buttonDiameter = 100;
@@ -121,99 +115,21 @@ class HomeViewState extends State {
// Subscribe to all events (initial link and further)
_deepLinkSub = AppLinks().uriLinkStream.listen((uri) async {
- if (!uri.scheme.startsWith('http')) return;
- if (uri.host != 'me.twonly.eu') return;
- if (uri.hasEmptyPath) return;
+ if (mounted) await handleIntentUrl(context, uri);
+ });
- final publicKey = uri.hasFragment ? uri.fragment : null;
- final userPaths = uri.path.split('/');
- if (userPaths.length != 2) return;
- final username = userPaths[1];
+ _intentStreamSub = FlutterSharingIntent.instance.getMediaStream().listen(
+ (f) {
+ if (mounted) handleIntentSharedFile(context, f);
+ },
+ // ignore: inference_failure_on_untyped_parameter
+ onError: (err) {
+ Log.error('getIntentDataStream error: $err');
+ },
+ );
- if (!mounted) return;
-
- if (username == gUser.username) {
- await Navigator.push(
- context,
- MaterialPageRoute(
- builder: (context) {
- return const PublicProfileView();
- },
- ),
- );
- return;
- }
-
- Log.info(
- 'Opened via deep link!: username = $username public_key = ${uri.fragment}',
- );
- final contacts =
- await twonlyDB.contactsDao.getContactsByUsername(username);
- if (contacts.isEmpty) {
- if (!mounted) return;
- Uint8List? publicKeyBytes;
- if (publicKey != null) {
- publicKeyBytes = base64Url.decode(publicKey);
- }
- await Navigator.push(
- context,
- MaterialPageRoute(
- builder: (context) {
- return AddNewUserView(
- username: username,
- publicKey: publicKeyBytes,
- );
- },
- ),
- );
- } else if (publicKey != null) {
- try {
- final contact = contacts.first;
- final storedPublicKey = await getPublicKeyFromContact(contact.userId);
- final receivedPublicKey = base64Url.decode(publicKey);
- if (storedPublicKey == null ||
- receivedPublicKey.isEmpty ||
- !mounted) {
- return;
- }
- if (storedPublicKey.equals(receivedPublicKey)) {
- if (!contact.verified) {
- final markAsVerified = await showAlertDialog(
- context,
- context.lang.linkFromUsername(contact.username),
- context.lang.linkFromUsernameLong,
- customOk: context.lang.gotLinkFromFriend,
- );
- if (markAsVerified) {
- await twonlyDB.contactsDao.updateContact(
- contact.userId,
- const ContactsCompanion(
- verified: Value(true),
- ),
- );
- }
- } else {
- await Navigator.push(
- context,
- MaterialPageRoute(
- builder: (context) {
- return ContactView(contact.userId);
- },
- ),
- );
- }
- } else {
- await showAlertDialog(
- context,
- context.lang.couldNotVerifyUsername(contact.username),
- context.lang.linkPubkeyDoesNotMatch,
- customCancel: '',
- );
- }
- } catch (e) {
- Log.warn(e);
- }
- }
+ FlutterSharingIntent.instance.getInitialSharing().then((f) {
+ if (mounted) handleIntentSharedFile(context, f);
});
}
@@ -222,6 +138,7 @@ class HomeViewState extends State {
unawaited(selectNotificationStream.close());
disableCameraTimer?.cancel();
_mainCameraController.closeCamera();
+ _intentStreamSub.cancel();
_deepLinkSub.cancel();
super.dispose();
}
diff --git a/pubspec.lock b/pubspec.lock
index f8a222b..ea1d1dc 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -742,29 +742,27 @@ packages:
flutter_secure_storage:
dependency: "direct main"
description:
- path: flutter_secure_storage
- ref: a06ead81809c900e7fc421a30db0adf3b5919139
- resolved-ref: a06ead81809c900e7fc421a30db0adf3b5919139
- url: "https://github.com/juliansteenbakker/flutter_secure_storage.git"
- source: git
- version: "10.0.0-beta.4"
+ name: flutter_secure_storage
+ sha256: da922f2aab2d733db7e011a6bcc4a825b844892d4edd6df83ff156b09a9b2e40
+ url: "https://pub.dev"
+ source: hosted
+ version: "10.0.0"
flutter_secure_storage_darwin:
- dependency: "direct overridden"
+ dependency: transitive
description:
- path: flutter_secure_storage_darwin
- ref: a06ead81809c900e7fc421a30db0adf3b5919139
- resolved-ref: a06ead81809c900e7fc421a30db0adf3b5919139
- url: "https://github.com/juliansteenbakker/flutter_secure_storage.git"
- source: git
- version: "0.1.0"
+ name: flutter_secure_storage_darwin
+ sha256: "8878c25136a79def1668c75985e8e193d9d7d095453ec28730da0315dc69aee3"
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.2.0"
flutter_secure_storage_linux:
dependency: transitive
description:
name: flutter_secure_storage_linux
- sha256: "9b4b73127e857cd3117d43a70fa3dddadb6e0b253be62e6a6ab85caa0742182c"
+ sha256: "2b5c76dce569ab752d55a1cee6a2242bcc11fdba927078fb88c503f150767cda"
url: "https://pub.dev"
source: hosted
- version: "2.0.1"
+ version: "3.0.0"
flutter_secure_storage_platform_interface:
dependency: transitive
description:
@@ -777,18 +775,25 @@ packages:
dependency: transitive
description:
name: flutter_secure_storage_web
- sha256: "4c3f233e739545c6cb09286eeec1cc4744138372b985113acc904f7263bef517"
+ sha256: "6a1137df62b84b54261dca582c1c09ea72f4f9a4b2fcee21b025964132d5d0c3"
url: "https://pub.dev"
source: hosted
- version: "2.0.0"
+ version: "2.1.0"
flutter_secure_storage_windows:
dependency: transitive
description:
name: flutter_secure_storage_windows
- sha256: ff32af20f70a8d0e59b2938fc92de35b54a74671041c814275afd80e27df9f21
+ sha256: "3b7c8e068875dfd46719ff57c90d8c459c87f2302ed6b00ff006b3c9fcad1613"
url: "https://pub.dev"
source: hosted
- version: "4.0.0"
+ version: "4.1.0"
+ flutter_sharing_intent:
+ dependency: "direct main"
+ description:
+ path: "dependencies/flutter_sharing_intent"
+ relative: true
+ source: path
+ version: "2.0.4"
flutter_svg:
dependency: "direct main"
description:
@@ -1243,11 +1248,10 @@ packages:
no_screenshot:
dependency: "direct main"
description:
- name: no_screenshot
- sha256: ec3d86d7ee89a09c3a3939c1003012536ba4b3fcb4f8cbd23d87ada595c99258
- url: "https://pub.dev"
- source: hosted
- version: "0.3.1"
+ path: "dependencies/no_screenshot"
+ relative: true
+ source: path
+ version: "0.3.2-beta.3"
objective_c:
dependency: transitive
description:
diff --git a/pubspec.yaml b/pubspec.yaml
index 8b16d26..d441e98 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -36,6 +36,7 @@ dependencies:
url_launcher: ^6.3.2
vector_graphics: ^1.1.19
video_player: ^2.10.1
+ in_app_purchase: ^3.2.3
# Trusted publisher fluttercommunity.dev
@@ -54,44 +55,50 @@ dependencies:
scrollable_positioned_list: ^0.3.8 # google.dev
+ # Flutter Favorite
+ provider: ^6.1.2
+ drift: ^2.25.1
+ drift_flutter: ^0.2.4
+ flutter_local_notifications: ^19.1.0
+ sentry_flutter: ^9.8.0
+
+
+ # With high download
+ app_links: ^7.0.0 # 1.6 mio
+ image: ^4.3.0 # 3.3 mio
+ archive: ^4.0.7 # 6.5 mio
+ file_picker: ^10.3.6 # 2 mio
+ get: ^4.7.2 # 740 k
+ flutter_secure_storage: ^10.0.0 # 1.85 mio
+ permission_handler: ^12.0.0+1 # 2 mio
+
+
# Not yet checked
- archive: ^4.0.7
audio_waveforms: ^2.0.0
avatar_maker: ^0.4.0
background_downloader: ^9.4.0
cached_network_image: ^3.4.1
cryptography_flutter_plus: ^2.3.4
cryptography_plus: ^2.7.0
- drift: ^2.25.1
- drift_flutter: ^0.2.4
ffmpeg_kit_flutter_new: ^4.1.0
- file_picker: ^10.3.6
flutter_android_volume_keydown: ^1.0.1
flutter_image_compress: ^2.4.0
- flutter_local_notifications: ^19.1.0
- flutter_secure_storage:
- git:
- url: https://github.com/juliansteenbakker/flutter_secure_storage.git
- ref: a06ead81809c900e7fc421a30db0adf3b5919139 # from develop
- path: flutter_secure_storage/
flutter_volume_controller: ^1.3.4
gal: ^2.3.1
- get: ^4.7.2
google_mlkit_barcode_scanning: ^0.14.1
- image: ^4.3.0
- no_screenshot: ^0.3.1
- permission_handler: ^12.0.0+1
- provider: ^6.1.2
- restart_app: ^1.3.2
- sentry_flutter: ^9.8.0
- app_links: ^7.0.0
- in_app_purchase: ^3.2.3
+
+ # flutter_secure_storage:
+ # git:
+ # url: https://github.com/juliansteenbakker/flutter_secure_storage.git
+ # ref: a06ead81809c900e7fc421a30db0adf3b5919139 # from develop
+ # path: flutter_secure_storage/
# Overwritten by self-controlled repository
emoji_picker_flutter: ^4.3.0
# Packages which got overwritten using the twonly-app-dependencies repository
+ restart_app: ^1.3.2
photo_view: ^0.15.0
hashlib: ^2.0.0
libsignal_protocol_dart: ^0.7.4
@@ -100,6 +107,8 @@ dependencies:
introduction_screen: ^4.0.0
qr_flutter: ^4.1.0
hand_signature: ^3.0.3
+ flutter_sharing_intent: ^2.0.4
+ no_screenshot: ^0.3.1
dependency_overrides:
dots_indicator:
@@ -110,6 +119,8 @@ dependency_overrides:
path: ./dependencies/introduction_screen
libsignal_protocol_dart:
path: ./dependencies/libsignal_protocol_dart
+ flutter_sharing_intent:
+ path: ./dependencies/flutter_sharing_intent
lottie:
path: ./dependencies/lottie
mutex:
@@ -134,6 +145,8 @@ dependency_overrides:
path: ./dependencies/x25519
qr_flutter:
path: ./dependencies/qr_flutter
+ no_screenshot:
+ path: ./dependencies/no_screenshot
camera_android_camerax:
# path: ../flutter-packages/packages/camera/camera_android_camerax
git:
@@ -149,11 +162,11 @@ dependency_overrides:
git:
url: https://github.com/yenchieh/flutter_android_volume_keydown.git
branch: fix/lStar-not-found-error
- flutter_secure_storage_darwin:
- git:
- url: https://github.com/juliansteenbakker/flutter_secure_storage.git
- ref: a06ead81809c900e7fc421a30db0adf3b5919139 # from develop
- path: flutter_secure_storage_darwin/
+ # flutter_secure_storage_darwin:
+ # git:
+ # url: https://github.com/juliansteenbakker/flutter_secure_storage.git
+ # ref: a06ead81809c900e7fc421a30db0adf3b5919139 # from develop
+ # path: flutter_secure_storage_darwin/
# hardcoding the mirror mode of the VideCapture to MIRROR_MODE_ON_FRONT_ONLY
dev_dependencies: