diff --git a/ios/OpenbookShareExtension/Base.lproj/MainInterface.storyboard b/ios/OpenbookShareExtension/Base.lproj/MainInterface.storyboard
new file mode 100644
index 000000000..589bdd9e7
--- /dev/null
+++ b/ios/OpenbookShareExtension/Base.lproj/MainInterface.storyboard
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ios/OpenbookShareExtension/Info.plist b/ios/OpenbookShareExtension/Info.plist
new file mode 100644
index 000000000..020e6504e
--- /dev/null
+++ b/ios/OpenbookShareExtension/Info.plist
@@ -0,0 +1,36 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ $(DEVELOPMENT_LANGUAGE)
+ CFBundleDisplayName
+ Openbook
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ $(PRODUCT_BUNDLE_IDENTIFIER)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ $(PRODUCT_NAME)
+ CFBundlePackageType
+ XPC!
+ CFBundleShortVersionString
+ 0.0.34
+ CFBundleVersion
+ 34
+ NSExtension
+
+ NSExtensionAttributes
+
+ NSExtensionActivationRule
+ TRUEPREDICATE
+
+ NSExtensionMainStoryboard
+ MainInterface
+ NSExtensionPointIdentifier
+ com.apple.share-services
+
+
+
diff --git a/ios/OpenbookShareExtension/OpenbookShareExtension.entitlements b/ios/OpenbookShareExtension/OpenbookShareExtension.entitlements
new file mode 100644
index 000000000..d98b46816
--- /dev/null
+++ b/ios/OpenbookShareExtension/OpenbookShareExtension.entitlements
@@ -0,0 +1,11 @@
+
+
+
+
+ com.apple.security.application-groups
+
+ group.social.openbook.app
+ group.social.openbook.app.onesignal
+
+
+
diff --git a/ios/OpenbookShareExtension/ShareViewController.h b/ios/OpenbookShareExtension/ShareViewController.h
new file mode 100644
index 000000000..715dcd7c8
--- /dev/null
+++ b/ios/OpenbookShareExtension/ShareViewController.h
@@ -0,0 +1,6 @@
+#import
+#import
+
+@interface ShareViewController : SLComposeServiceViewController
+
+@end
diff --git a/ios/OpenbookShareExtension/ShareViewController.m b/ios/OpenbookShareExtension/ShareViewController.m
new file mode 100644
index 000000000..003e7ed66
--- /dev/null
+++ b/ios/OpenbookShareExtension/ShareViewController.m
@@ -0,0 +1,125 @@
+#import "ShareViewController.h"
+
+const NSString* APP_GROUP_NAME = @"group.social.openbook.app";
+
+@interface ShareViewController ()
+
+@end
+
+@implementation ShareViewController
+
+- (BOOL)isContentValid {
+ // Do validation of contentText and/or NSExtensionContext attachments here
+ return YES;
+}
+
+- (NSString*)getTempDir {
+ NSFileManager* manager = [NSFileManager defaultManager];
+ NSString* tempDir = [[[manager containerURLForSecurityApplicationGroupIdentifier:APP_GROUP_NAME] path] stringByAppendingPathComponent:@"tmp"];
+
+ BOOL isDir;
+ NSError* error = nil;
+
+ if (![manager fileExistsAtPath:tempDir isDirectory:&isDir]) {
+ if (![manager createDirectoryAtPath:tempDir withIntermediateDirectories:YES attributes:nil error:&error]) {
+ // TODO: handle error
+ }
+ }
+
+ return tempDir;
+}
+
+- (NSString*) getTempFileWithExtension:(NSString*)extension {
+ NSString* fileName = [[NSUUID UUID] UUIDString];
+ NSString* tempFile = [fileName stringByAppendingPathExtension:extension];
+
+ return tempFile;
+}
+
+- (UIApplication*)getUIApplication {
+ UIResponder* responder = (UIResponder*)self;
+ while ((responder = [responder nextResponder]) != nil) {
+ if ([responder isKindOfClass:[UIApplication class]]) {
+ return (UIApplication*)responder;
+ }
+ }
+ return nil;
+}
+
+- (void)callOpenbookAppWithSharedFileName:(NSString*)fileName {
+ NSURL* url = [[NSURL URLWithString:@"openbook://share"] URLByAppendingPathComponent:fileName];
+ NSLog(@"Opening URL: %@", url);
+ UIApplication* application = [self getUIApplication];
+ if (application == nil) {
+ NSLog(@"Failed to get UIApplication, can't open URL!");
+ return;
+ }
+
+ [application performSelector:@selector(openURL:) withObject:url];
+}
+
+- (void)callOpenbookAppWithData:(NSDictionary*)data {
+ NSFileManager* manager = [NSFileManager defaultManager];
+ NSError* error;
+ NSData* jsonData = [NSJSONSerialization dataWithJSONObject:data options:0 error:&error];
+ // TODO: handle error
+ NSString* tempPath = [self getTempDir];
+ NSString* jsonFile = [self getTempFileWithExtension:@"json"];
+ if (![manager createFileAtPath:[tempPath stringByAppendingPathComponent:jsonFile] contents:jsonData attributes:nil]) {
+ // TODO: handle error
+ }
+ // call main app
+ [self callOpenbookAppWithSharedFileName:jsonFile];
+ // Inform the host that we're done, so it un-blocks its UI. Note: Alternatively you could call super's -didSelectPost, which will similarly complete the extension context.
+ [self.extensionContext completeRequestReturningItems:@[] completionHandler:nil];
+}
+
+- (void)didSelectPost {
+ // This is called after the user selects Post. Do the upload of contentText and/or NSExtensionContext attachments.
+ NSFileManager* manager = [NSFileManager defaultManager];
+ NSExtensionContext* context = self.extensionContext;
+ // As we have to communicate text and an image to the app, write everything to a file instead of putting everything in an URL.
+ NSMutableDictionary* args = [[NSMutableDictionary alloc] init];
+ args[@"text"] = self.contentText;
+ // Handle an image
+ BOOL hasCallback = NO;
+ NSArray* items = context.inputItems;
+ if ([items count] >= 1) {
+ NSExtensionItem* item = items[0];
+ if ([item.attachments count] >= 1) {
+ NSItemProvider* itemProvider = item.attachments[0];
+ if ([itemProvider hasItemConformingToTypeIdentifier:@"public.image"]) {
+ hasCallback = YES;
+ [itemProvider loadItemForTypeIdentifier:@"public.image" options:nil completionHandler:^void(UIImage* image, NSError* error) {
+ // TODO: handle error
+ NSData* imageData = UIImageJPEGRepresentation(image, 1.0);
+ if (imageData == nil){
+ // TODO: handle error
+ }
+ NSString* tempPath = [self getTempDir];
+ NSString* fileName = [self getTempFileWithExtension:@"jpg"];
+ if (![manager createFileAtPath:[tempPath stringByAppendingPathComponent:fileName] contents:imageData attributes:nil]) {
+ // TODO: handle error
+ }
+ args[@"path"] = [tempPath stringByAppendingPathComponent:fileName];
+ NSLog(@"image written to %@, opening app", args[@"path"]);
+ [self callOpenbookAppWithData:args];
+ }];
+ } else {
+ NSLog(@"No UTI public.image found, ignoring attachment");
+ }
+ }
+ }
+
+ // If we have a callback (when loading an image), do not immediately open the app, that will happen in the callback
+ if (!hasCallback) {
+ [self callOpenbookAppWithData:args];
+ }
+}
+
+- (NSArray *)configurationItems {
+ // To add configuration options via table cells at the bottom of the sheet, return an array of SLComposeSheetConfigurationItem here.
+ return @[];
+}
+
+@end
diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj
index 199bf340e..78cfe7dac 100644
--- a/ios/Runner.xcodeproj/project.pbxproj
+++ b/ios/Runner.xcodeproj/project.pbxproj
@@ -17,6 +17,20 @@
8902A1082236D5BF005F914D /* libintercom_flutter.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8902A1062236D5BF005F914D /* libintercom_flutter.a */; };
8902A1092236D5BF005F914D /* libsqflite.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8928E32022356450001DB32A /* libsqflite.a */; };
8925094F222F0E0900455D87 /* libdevice_info.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8925094A222F0E0900455D87 /* libdevice_info.a */; };
+ 89416F7A2257ECCB00896B34 /* libdevice_info.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8925094A222F0E0900455D87 /* libdevice_info.a */; };
+ 89416F7B2257ECCB00896B34 /* libflutter_exif_rotation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 89CF474422419BFD001BC50D /* libflutter_exif_rotation.a */; };
+ 89416F7C2257ECCB00896B34 /* libflutter_secure_storage.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8980539E22047AAF00E47AD9 /* libflutter_secure_storage.a */; };
+ 89416F7E2257ECCB00896B34 /* libimage_cropper.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 898053A022047AAF00E47AD9 /* libimage_cropper.a */; };
+ 89416F7F2257ECCB00896B34 /* libimage_picker.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 898053A222047AAF00E47AD9 /* libimage_picker.a */; };
+ 89416F802257ECCB00896B34 /* libintercom_flutter.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8902A1062236D5BF005F914D /* libintercom_flutter.a */; };
+ 89416F812257ECCB00896B34 /* libonesignal.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 898053A422047AAF00E47AD9 /* libonesignal.a */; };
+ 89416F822257ECCB00896B34 /* libpath_provider.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 898053A622047AAF00E47AD9 /* libpath_provider.a */; };
+ 89416F852257ECCB00896B34 /* libsqflite.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8928E32022356450001DB32A /* libsqflite.a */; };
+ 89416F862257ECCB00896B34 /* libTOCropViewController.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 898053AE22047AAF00E47AD9 /* libTOCropViewController.a */; };
+ 89416F872257ECCB00896B34 /* libuni_links.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 898053B222047AAF00E47AD9 /* libuni_links.a */; };
+ 89416F882257ECCB00896B34 /* liburl_launcher.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 898053B422047AAF00E47AD9 /* liburl_launcher.a */; };
+ 89416F892257ECCB00896B34 /* libvideo_player.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 898053B622047AAF00E47AD9 /* libvideo_player.a */; };
+ 89416F9F2257EE3C00896B34 /* libFMDB.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8928E31E22356450001DB32A /* libFMDB.a */; };
898053B722047AD000E47AD9 /* libflutter_secure_storage.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8980539E22047AAF00E47AD9 /* libflutter_secure_storage.a */; };
898053B822047AD000E47AD9 /* libimage_cropper.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 898053A022047AAF00E47AD9 /* libimage_cropper.a */; };
898053B922047AD000E47AD9 /* libimage_picker.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 898053A222047AAF00E47AD9 /* libimage_picker.a */; };
@@ -40,6 +54,10 @@
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 */; };
+ A647F8112257B18C00A31CF1 /* ShareViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = A647F8102257B18C00A31CF1 /* ShareViewController.m */; };
+ A647F8142257B18C00A31CF1 /* MainInterface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A647F8122257B18C00A31CF1 /* MainInterface.storyboard */; };
+ A647F8182257B18C00A31CF1 /* OpenbookSharingExtension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = A647F80D2257B18C00A31CF1 /* OpenbookSharingExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
+ A647F8362257BB7F00A31CF1 /* ReceiveShareStreamHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = A647F8352257BB7F00A31CF1 /* ReceiveShareStreamHandler.m */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@@ -169,6 +187,13 @@
remoteGlobalIDString = 1CE8375F5D12E4C085E8D4CF09BCD280;
remoteInfo = flutter_exif_rotation;
};
+ A647F8162257B18C00A31CF1 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 97C146E61CF9000F007C117D /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = A647F80C2257B18C00A31CF1;
+ remoteInfo = OpenbookShareExtension;
+ };
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
@@ -179,6 +204,7 @@
dstSubfolderSpec = 13;
files = (
89ABAE562203425900049DFB /* OneSignalNotificationServiceExtension.appex in Embed App Extensions */,
+ A647F8182257B18C00A31CF1 /* OpenbookSharingExtension.appex in Embed App Extensions */,
);
name = "Embed App Extensions";
runOnlyForDeploymentPostprocessing = 0;
@@ -222,6 +248,7 @@
89ABAE502203425900049DFB /* NotificationService.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NotificationService.h; sourceTree = ""; };
89ABAE512203425900049DFB /* NotificationService.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = NotificationService.m; sourceTree = ""; };
89ABAE532203425900049DFB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+ 89D66D132257E9C4005EA600 /* OpenbookShareExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = OpenbookShareExtension.entitlements; sourceTree = ""; };
89DBC2DD2203430700F80685 /* OneSignalNotificationServiceExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = OneSignalNotificationServiceExtension.entitlements; sourceTree = ""; };
970D6175355421F353EA64C9 /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; };
@@ -233,6 +260,13 @@
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 = ""; };
+ A647F80D2257B18C00A31CF1 /* OpenbookSharingExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = OpenbookSharingExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
+ A647F80F2257B18C00A31CF1 /* ShareViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ShareViewController.h; sourceTree = ""; };
+ A647F8102257B18C00A31CF1 /* ShareViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ShareViewController.m; sourceTree = ""; };
+ A647F8132257B18C00A31CF1 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/MainInterface.storyboard; sourceTree = ""; };
+ A647F8152257B18C00A31CF1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+ A647F8352257BB7F00A31CF1 /* ReceiveShareStreamHandler.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ReceiveShareStreamHandler.m; sourceTree = ""; };
+ A647F8372257BBA700A31CF1 /* ReceiveShareStreamHandler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ReceiveShareStreamHandler.h; sourceTree = ""; };
A6C34D3821BE816E00882F1E /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = ""; };
AAF4B8238CF43C30122544EF /* Pods-OneSignalNotificationServiceExtension.release-production.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-OneSignalNotificationServiceExtension.release-production.xcconfig"; path = "Pods/Target Support Files/Pods-OneSignalNotificationServiceExtension/Pods-OneSignalNotificationServiceExtension.release-production.xcconfig"; sourceTree = ""; };
B23196F4E53E7786037AC8B5 /* Pods-OneSignalNotificationServiceExtension.release-development.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-OneSignalNotificationServiceExtension.release-development.xcconfig"; path = "Pods/Target Support Files/Pods-OneSignalNotificationServiceExtension/Pods-OneSignalNotificationServiceExtension.release-development.xcconfig"; sourceTree = ""; };
@@ -278,6 +312,27 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
+ A647F80A2257B18C00A31CF1 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 89416F9F2257EE3C00896B34 /* libFMDB.a in Frameworks */,
+ 89416F7A2257ECCB00896B34 /* libdevice_info.a in Frameworks */,
+ 89416F7B2257ECCB00896B34 /* libflutter_exif_rotation.a in Frameworks */,
+ 89416F7C2257ECCB00896B34 /* libflutter_secure_storage.a in Frameworks */,
+ 89416F7E2257ECCB00896B34 /* libimage_cropper.a in Frameworks */,
+ 89416F7F2257ECCB00896B34 /* libimage_picker.a in Frameworks */,
+ 89416F802257ECCB00896B34 /* libintercom_flutter.a in Frameworks */,
+ 89416F812257ECCB00896B34 /* libonesignal.a in Frameworks */,
+ 89416F822257ECCB00896B34 /* libpath_provider.a in Frameworks */,
+ 89416F852257ECCB00896B34 /* libsqflite.a in Frameworks */,
+ 89416F862257ECCB00896B34 /* libTOCropViewController.a in Frameworks */,
+ 89416F872257ECCB00896B34 /* libuni_links.a in Frameworks */,
+ 89416F882257ECCB00896B34 /* liburl_launcher.a in Frameworks */,
+ 89416F892257ECCB00896B34 /* libvideo_player.a in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
@@ -373,6 +428,7 @@
9740EEB11CF90186004384FC /* Flutter */,
97C146F01CF9000F007C117D /* Runner */,
89ABAE4F2203425900049DFB /* OneSignalNotificationServiceExtension */,
+ A647F80E2257B18C00A31CF1 /* OpenbookShareExtension */,
97C146EF1CF9000F007C117D /* Products */,
0532A0D3A2BF06AB149735E4 /* Pods */,
5ABC6138995F2182C962F35D /* Frameworks */,
@@ -384,6 +440,7 @@
children = (
97C146EE1CF9000F007C117D /* Runner.app */,
89ABAE4E2203425900049DFB /* OneSignalNotificationServiceExtension.appex */,
+ A647F80D2257B18C00A31CF1 /* OpenbookSharingExtension.appex */,
);
name = Products;
sourceTree = "";
@@ -397,6 +454,8 @@
7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */,
97C147021CF9000F007C117D /* Info.plist */,
7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */,
+ A647F8372257BBA700A31CF1 /* ReceiveShareStreamHandler.h */,
+ A647F8352257BB7F00A31CF1 /* ReceiveShareStreamHandler.m */,
97C146FA1CF9000F007C117D /* Main.storyboard */,
97C146FD1CF9000F007C117D /* Assets.xcassets */,
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
@@ -415,6 +474,18 @@
name = "Supporting Files";
sourceTree = "";
};
+ A647F80E2257B18C00A31CF1 /* OpenbookShareExtension */ = {
+ isa = PBXGroup;
+ children = (
+ 89D66D132257E9C4005EA600 /* OpenbookShareExtension.entitlements */,
+ A647F80F2257B18C00A31CF1 /* ShareViewController.h */,
+ A647F8102257B18C00A31CF1 /* ShareViewController.m */,
+ A647F8122257B18C00A31CF1 /* MainInterface.storyboard */,
+ A647F8152257B18C00A31CF1 /* Info.plist */,
+ );
+ path = OpenbookShareExtension;
+ sourceTree = "";
+ };
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
@@ -455,12 +526,30 @@
);
dependencies = (
89ABAE552203425900049DFB /* PBXTargetDependency */,
+ A647F8172257B18C00A31CF1 /* PBXTargetDependency */,
);
name = Runner;
productName = Runner;
productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
productType = "com.apple.product-type.application";
};
+ A647F80C2257B18C00A31CF1 /* OpenbookSharingExtension */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = A647F8342257B18C00A31CF1 /* Build configuration list for PBXNativeTarget "OpenbookSharingExtension" */;
+ buildPhases = (
+ A647F8092257B18C00A31CF1 /* Sources */,
+ A647F80A2257B18C00A31CF1 /* Frameworks */,
+ A647F80B2257B18C00A31CF1 /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = OpenbookSharingExtension;
+ productName = OpenbookShareExtension;
+ productReference = A647F80D2257B18C00A31CF1 /* OpenbookSharingExtension.appex */;
+ productType = "com.apple.product-type.app-extension";
+ };
/* End PBXNativeTarget section */
/* Begin PBXProject section */
@@ -499,6 +588,16 @@
};
};
};
+ A647F80C2257B18C00A31CF1 = {
+ CreatedOnToolsVersion = 10.1;
+ DevelopmentTeam = GAR7B57RXU;
+ ProvisioningStyle = Automatic;
+ SystemCapabilities = {
+ com.apple.ApplicationGroups.iOS = {
+ enabled = 1;
+ };
+ };
+ };
};
};
buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
@@ -526,6 +625,7 @@
targets = (
97C146ED1CF9000F007C117D /* Runner */,
89ABAE4D2203425900049DFB /* OneSignalNotificationServiceExtension */,
+ A647F80C2257B18C00A31CF1 /* OpenbookSharingExtension */,
);
};
/* End PBXProject section */
@@ -671,6 +771,14 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
+ A647F80B2257B18C00A31CF1 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ A647F8142257B18C00A31CF1 /* MainInterface.storyboard in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
@@ -795,10 +903,19 @@
files = (
978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */,
97C146F31CF9000F007C117D /* main.m in Sources */,
+ A647F8362257BB7F00A31CF1 /* ReceiveShareStreamHandler.m in Sources */,
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
+ A647F8092257B18C00A31CF1 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ A647F8112257B18C00A31CF1 /* ShareViewController.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
@@ -807,6 +924,11 @@
target = 89ABAE4D2203425900049DFB /* OneSignalNotificationServiceExtension */;
targetProxy = 89ABAE542203425900049DFB /* PBXContainerItemProxy */;
};
+ A647F8172257B18C00A31CF1 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = A647F80C2257B18C00A31CF1 /* OpenbookSharingExtension */;
+ targetProxy = A647F8162257B18C00A31CF1 /* PBXContainerItemProxy */;
+ };
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
@@ -826,6 +948,14 @@
name = LaunchScreen.storyboard;
sourceTree = "";
};
+ A647F8122257B18C00A31CF1 /* MainInterface.storyboard */ = {
+ isa = PBXVariantGroup;
+ children = (
+ A647F8132257B18C00A31CF1 /* Base */,
+ );
+ name = MainInterface.storyboard;
+ sourceTree = "";
+ };
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
@@ -1606,6 +1736,191 @@
};
name = Release;
};
+ A647F8192257B18C00A31CF1 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CODE_SIGN_ENTITLEMENTS = OpenbookShareExtension/OpenbookShareExtension.entitlements;
+ CODE_SIGN_IDENTITY = "iPhone Developer";
+ CODE_SIGN_STYLE = Automatic;
+ DEVELOPMENT_TEAM = GAR7B57RXU;
+ ENABLE_BITCODE = NO;
+ GCC_C_LANGUAGE_STANDARD = gnu11;
+ INFOPLIST_FILE = OpenbookShareExtension/Info.plist;
+ IPHONEOS_DEPLOYMENT_TARGET = 10.2;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
+ MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
+ MTL_FAST_MATH = YES;
+ PRODUCT_BUNDLE_IDENTIFIER = social.openbook.app.OpenbookSharingExtension;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ PROVISIONING_PROFILE_SPECIFIER = "";
+ SKIP_INSTALL = YES;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Debug;
+ };
+ A647F81A2257B18C00A31CF1 /* Debug-production */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CODE_SIGN_ENTITLEMENTS = OpenbookShareExtension/OpenbookShareExtension.entitlements;
+ CODE_SIGN_IDENTITY = "iPhone Developer";
+ CODE_SIGN_STYLE = Automatic;
+ DEVELOPMENT_TEAM = GAR7B57RXU;
+ ENABLE_BITCODE = NO;
+ GCC_C_LANGUAGE_STANDARD = gnu11;
+ INFOPLIST_FILE = OpenbookShareExtension/Info.plist;
+ IPHONEOS_DEPLOYMENT_TARGET = 10.2;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
+ MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
+ MTL_FAST_MATH = YES;
+ PRODUCT_BUNDLE_IDENTIFIER = social.openbook.app.OpenbookSharingExtension;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ PROVISIONING_PROFILE_SPECIFIER = "";
+ SKIP_INSTALL = YES;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = "Debug-production";
+ };
+ A647F81B2257B18C00A31CF1 /* Debug-development */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CODE_SIGN_ENTITLEMENTS = OpenbookShareExtension/OpenbookShareExtension.entitlements;
+ CODE_SIGN_IDENTITY = "iPhone Developer";
+ CODE_SIGN_STYLE = Automatic;
+ DEVELOPMENT_TEAM = GAR7B57RXU;
+ ENABLE_BITCODE = NO;
+ GCC_C_LANGUAGE_STANDARD = gnu11;
+ INFOPLIST_FILE = OpenbookShareExtension/Info.plist;
+ IPHONEOS_DEPLOYMENT_TARGET = 10.2;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
+ MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
+ MTL_FAST_MATH = YES;
+ PRODUCT_BUNDLE_IDENTIFIER = social.openbook.app.OpenbookSharingExtension;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ PROVISIONING_PROFILE_SPECIFIER = "";
+ SKIP_INSTALL = YES;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = "Debug-development";
+ };
+ A647F81C2257B18C00A31CF1 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CODE_SIGN_ENTITLEMENTS = OpenbookShareExtension/OpenbookShareExtension.entitlements;
+ CODE_SIGN_IDENTITY = "iPhone Developer";
+ CODE_SIGN_STYLE = Automatic;
+ DEVELOPMENT_TEAM = GAR7B57RXU;
+ ENABLE_BITCODE = NO;
+ GCC_C_LANGUAGE_STANDARD = gnu11;
+ INFOPLIST_FILE = OpenbookShareExtension/Info.plist;
+ IPHONEOS_DEPLOYMENT_TARGET = 10.2;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
+ MTL_FAST_MATH = YES;
+ PRODUCT_BUNDLE_IDENTIFIER = social.openbook.app.OpenbookSharingExtension;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ PROVISIONING_PROFILE_SPECIFIER = "";
+ SKIP_INSTALL = YES;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Release;
+ };
+ A647F81D2257B18C00A31CF1 /* Profile */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CODE_SIGN_ENTITLEMENTS = OpenbookShareExtension/OpenbookShareExtension.entitlements;
+ CODE_SIGN_IDENTITY = "iPhone Developer";
+ CODE_SIGN_STYLE = Automatic;
+ DEVELOPMENT_TEAM = GAR7B57RXU;
+ ENABLE_BITCODE = NO;
+ GCC_C_LANGUAGE_STANDARD = gnu11;
+ INFOPLIST_FILE = OpenbookShareExtension/Info.plist;
+ IPHONEOS_DEPLOYMENT_TARGET = 10.2;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
+ MTL_FAST_MATH = YES;
+ PRODUCT_BUNDLE_IDENTIFIER = social.openbook.app.OpenbookSharingExtension;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ PROVISIONING_PROFILE_SPECIFIER = "";
+ SKIP_INSTALL = YES;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Profile;
+ };
+ A647F81E2257B18C00A31CF1 /* Release-production */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CODE_SIGN_ENTITLEMENTS = OpenbookShareExtension/OpenbookShareExtension.entitlements;
+ CODE_SIGN_IDENTITY = "iPhone Developer";
+ CODE_SIGN_STYLE = Automatic;
+ DEVELOPMENT_TEAM = GAR7B57RXU;
+ ENABLE_BITCODE = NO;
+ GCC_C_LANGUAGE_STANDARD = gnu11;
+ INFOPLIST_FILE = OpenbookShareExtension/Info.plist;
+ IPHONEOS_DEPLOYMENT_TARGET = 10.2;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
+ MTL_FAST_MATH = YES;
+ PRODUCT_BUNDLE_IDENTIFIER = social.openbook.app.OpenbookSharingExtension;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ PROVISIONING_PROFILE_SPECIFIER = "";
+ SKIP_INSTALL = YES;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = "Release-production";
+ };
+ A647F81F2257B18C00A31CF1 /* Release-development */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CODE_SIGN_ENTITLEMENTS = OpenbookShareExtension/OpenbookShareExtension.entitlements;
+ CODE_SIGN_IDENTITY = "iPhone Developer";
+ CODE_SIGN_STYLE = Automatic;
+ DEVELOPMENT_TEAM = GAR7B57RXU;
+ ENABLE_BITCODE = NO;
+ GCC_C_LANGUAGE_STANDARD = gnu11;
+ INFOPLIST_FILE = OpenbookShareExtension/Info.plist;
+ IPHONEOS_DEPLOYMENT_TARGET = 10.2;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
+ MTL_FAST_MATH = YES;
+ PRODUCT_BUNDLE_IDENTIFIER = social.openbook.app.OpenbookSharingExtension;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ PROVISIONING_PROFILE_SPECIFIER = "";
+ SKIP_INSTALL = YES;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = "Release-development";
+ };
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
@@ -1651,6 +1966,20 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
+ A647F8342257B18C00A31CF1 /* Build configuration list for PBXNativeTarget "OpenbookSharingExtension" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ A647F8192257B18C00A31CF1 /* Debug */,
+ A647F81A2257B18C00A31CF1 /* Debug-production */,
+ A647F81B2257B18C00A31CF1 /* Debug-development */,
+ A647F81C2257B18C00A31CF1 /* Release */,
+ A647F81D2257B18C00A31CF1 /* Profile */,
+ A647F81E2257B18C00A31CF1 /* Release-production */,
+ A647F81F2257B18C00A31CF1 /* Release-development */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
/* End XCConfigurationList section */
};
rootObject = 97C146E61CF9000F007C117D /* Project object */;
diff --git a/ios/Runner/AppDelegate.m b/ios/Runner/AppDelegate.m
index 00f589066..be5ddcaac 100644
--- a/ios/Runner/AppDelegate.m
+++ b/ios/Runner/AppDelegate.m
@@ -1,12 +1,19 @@
#include "AppDelegate.h"
#include "GeneratedPluginRegistrant.h"
+#import "ReceiveShareStreamHandler.h"
#import
+#import
-@implementation AppDelegate
+@implementation AppDelegate {
+ ReceiveShareStreamHandler* _receiveShareStreamHandler;
+}
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[GeneratedPluginRegistrant registerWithRegistry:self];
+
+ FlutterViewController* controller = (FlutterViewController*)self.window.rootViewController;
+ _receiveShareStreamHandler = [ReceiveShareStreamHandler receiveShareStreamHandlerWithController: controller];
// Override point for customization after application launch.
return [super application:application didFinishLaunchingWithOptions:launchOptions];
}
@@ -15,4 +22,16 @@ - (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserAct
return [[UniLinksPlugin sharedInstance] application:application continueUserActivity:userActivity restorationHandler:restorationHandler];
}
+- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary *)options {
+
+ if ([url.scheme isEqualToString:@"openbook"]) {
+ NSLog(@"Handling openURL: %@", [url absoluteString]);
+ if ([url.host isEqualToString:@"share"]) {
+ NSArray* components = [url pathComponents];
+ [_receiveShareStreamHandler sendShareFromFile:components[1]];
+ }
+ }
+ return [super application:app openURL:url options:options];
+}
+
@end
diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist
index 27fd7d079..aadd34b0f 100644
--- a/ios/Runner/Info.plist
+++ b/ios/Runner/Info.plist
@@ -22,6 +22,17 @@
????
CFBundleVersion
34
+ CFBundleURLTypes
+
+
+ CFBundleURLName
+ social.openbook.app.scheme.openbook
+ CFBundleURLSchemes
+
+ openbook
+
+
+
ITSAppUsesNonExemptEncryption
LSRequiresIPhoneOS
diff --git a/ios/Runner/ReceiveShareStreamHandler.h b/ios/Runner/ReceiveShareStreamHandler.h
new file mode 100644
index 000000000..9d3da7a7c
--- /dev/null
+++ b/ios/Runner/ReceiveShareStreamHandler.h
@@ -0,0 +1,6 @@
+#import
+
+@interface ReceiveShareStreamHandler : NSObject
++ (id)receiveShareStreamHandlerWithController:(FlutterViewController*)controller;
+- (void)sendShareFromFile:(NSString*)fileName;
+@end
diff --git a/ios/Runner/ReceiveShareStreamHandler.m b/ios/Runner/ReceiveShareStreamHandler.m
new file mode 100644
index 000000000..cd2962130
--- /dev/null
+++ b/ios/Runner/ReceiveShareStreamHandler.m
@@ -0,0 +1,64 @@
+#import "ReceiveShareStreamHandler.h"
+#import
+
+const NSString* CHANNEL_NAME = @"openbook.social/receive_share";
+const NSString* APP_GROUP_NAME = @"group.social.openbook.app";
+
+@implementation ReceiveShareStreamHandler {
+ FlutterEventChannel* _channel;
+ FlutterEventSink _eventSink;
+ BOOL _streamCanceled;
+ NSMutableArray* _shareBacklog;
+}
+
++ (id)receiveShareStreamHandlerWithController:(FlutterViewController *)controller {
+ FlutterEventChannel* sharingChannel = [FlutterEventChannel
+ eventChannelWithName: CHANNEL_NAME
+ binaryMessenger: controller];
+ return [[ReceiveShareStreamHandler alloc] initWithChannel:sharingChannel];
+}
+
+- (id)initWithChannel:(FlutterEventChannel*)channel {
+ self = [super init];
+ if (self) {
+ _channel = channel;
+ _shareBacklog = [NSMutableArray arrayWithCapacity:1];
+ [_channel setStreamHandler:self];
+ }
+ return self;
+}
+
+- (FlutterError*)onListenWithArguments:(id)arguments eventSink:(FlutterEventSink)events {
+ _eventSink = events;
+ _streamCanceled = NO;
+ while ([_shareBacklog count] > 0) {
+ NSString* shareFile = _shareBacklog[0];
+ [_shareBacklog removeObjectAtIndex:0];
+ [self sendShareFromFile:shareFile];
+ }
+ return nil;
+}
+
+- (FlutterError*)onCancelWithArguments:(id)arguments {
+ _eventSink = nil;
+ _streamCanceled = YES;
+ return nil;
+}
+
+- (void)sendShareFromFile:(NSString*)fileName {
+ if (_eventSink == nil) {
+ if (!_streamCanceled && ![_shareBacklog containsObject:fileName]) {
+ [_shareBacklog addObject:fileName];
+ }
+ return;
+ }
+
+ NSFileManager* manager = [NSFileManager defaultManager];
+ NSString* tempDir = [[[manager containerURLForSecurityApplicationGroupIdentifier:APP_GROUP_NAME] path] stringByAppendingPathComponent:@"tmp"];
+ NSString* fullFileName = [tempDir stringByAppendingPathComponent:fileName];
+ NSError* error;
+ NSDictionary* args = [NSJSONSerialization JSONObjectWithData:[manager contentsAtPath:fullFileName] options:0 error: &error];
+ // TODO: handle error
+ _eventSink(args);
+}
+@end
diff --git a/lib/plugins/share/receive_share_state.dart b/lib/plugins/share/receive_share_state.dart
index 5f5d5e817..cbc183e64 100644
--- a/lib/plugins/share/receive_share_state.dart
+++ b/lib/plugins/share/receive_share_state.dart
@@ -12,11 +12,9 @@ abstract class ReceiveShareState extends State {
StreamSubscription shareReceiveSubscription = null;
void enableSharing() {
- if(Platform.isAndroid){
- if (shareReceiveSubscription == null) {
- shareReceiveSubscription =
- stream.receiveBroadcastStream().listen(_onReceiveShare);
- }
+ if (shareReceiveSubscription == null) {
+ shareReceiveSubscription =
+ stream.receiveBroadcastStream().listen(_onReceiveShare);
}
}