diff --git a/ios/Ecency.xcodeproj/project.pbxproj b/ios/Ecency.xcodeproj/project.pbxproj index 4e98dc211..f381a915f 100644 --- a/ios/Ecency.xcodeproj/project.pbxproj +++ b/ios/Ecency.xcodeproj/project.pbxproj @@ -39,11 +39,14 @@ 05B6C4AF24C306CE00B7FA60 /* SimpleLineIcons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 34E88D888DD444F8B285363C /* SimpleLineIcons.ttf */; }; 05B6C4B024C306CE00B7FA60 /* Zocial.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 980BC9BC0D3B4AC69645C842 /* Zocial.ttf */; }; 0A1D279E0D3CD306C889592E /* libPods-Ecency-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7093E51BBC0EE2F41AB19EBA /* libPods-Ecency-tvOS.a */; }; - 2B3CF3607B7CB9B7296FD5EF /* BuildFile in Frameworks */ = {isa = PBXBuildFile; }; + 2B3CF3607B7CB9B7296FD5EF /* (null) in Frameworks */ = {isa = PBXBuildFile; }; 2D02E4BC1E0B4A80006451C7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; }; 2D02E4BD1E0B4A84006451C7 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; }; 2D02E4BF1E0B4AB3006451C7 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; }; 2DCD954D1E0B4F2C00145EB5 /* EcencyTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* EcencyTests.m */; }; + 58C9F4FD24CE017800A026DD /* ShareViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58C9F4FC24CE017800A026DD /* ShareViewController.swift */; }; + 58C9F50024CE017800A026DD /* MainInterface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 58C9F4FE24CE017800A026DD /* MainInterface.storyboard */; }; + 58C9F50424CE017800A026DD /* EcencyShare.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 58C9F4FA24CE017800A026DD /* EcencyShare.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 58F9BCC624793C61004F0790 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 58F9BCC224793C61004F0790 /* GoogleService-Info.plist */; }; 58F9BCC724793C61004F0790 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 58F9BCC224793C61004F0790 /* GoogleService-Info.plist */; }; 58F9BCC824793C61004F0790 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 58F9BCC224793C61004F0790 /* GoogleService-Info.plist */; }; @@ -51,7 +54,7 @@ CFAA2A599FD65F360D9B3E1E /* libPods-EcencyTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B344CAA24725C973F48BE81E /* libPods-EcencyTests.a */; }; D71EB20EDB9B987C0574BAFE /* libPods-EcencyTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C97456BE898C00B5EDA21C2E /* libPods-EcencyTests.a */; }; DC0E25610BB5F49AFF4514AD /* libPods-Ecency.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 388DF3FF85F08109F722083B /* libPods-Ecency.a */; }; - F77F6C7E54F3C783A2773E9D /* BuildFile in Frameworks */ = {isa = PBXBuildFile; }; + F77F6C7E54F3C783A2773E9D /* (null) in Frameworks */ = {isa = PBXBuildFile; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -76,8 +79,29 @@ remoteGlobalIDString = 3DF7F6AC203AA09B00D0EAB7; remoteInfo = "ReactNativeConfig-tvOS"; }; + 58C9F50224CE017800A026DD /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 58C9F4F924CE017800A026DD; + remoteInfo = EcencyShare; + }; /* End PBXContainerItemProxy section */ +/* Begin PBXCopyFilesBuildPhase section */ + 58C9F50524CE017800A026DD /* Embed App Extensions */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 13; + files = ( + 58C9F50424CE017800A026DD /* EcencyShare.appex in Embed App Extensions */, + ); + name = "Embed App Extensions"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + /* Begin PBXFileReference section */ 000EE3558E824DA88770325D /* Octicons.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = Octicons.ttf; path = "../node_modules/react-native-vector-icons/Fonts/Octicons.ttf"; sourceTree = ""; }; 008F07F21AC5B25A0029DE68 /* main.jsbundle */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = main.jsbundle; sourceTree = ""; }; @@ -115,6 +139,12 @@ 588A5053232A3A4C00FC1361 /* Roboto.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = Roboto.ttf; path = ../src/assets/Fonts/Roboto.ttf; sourceTree = ""; }; 588A5054232A3A4C00FC1361 /* Roboto-medium.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = "Roboto-medium.ttf"; path = "../src/assets/Fonts/Roboto-medium.ttf"; sourceTree = ""; }; 588A5064232A497100FC1361 /* ReactNativeConfig.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = ReactNativeConfig.xcodeproj; path = "../node_modules/react-native-config/ios/ReactNativeConfig.xcodeproj"; sourceTree = ""; }; + 58C9F4FA24CE017800A026DD /* EcencyShare.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = EcencyShare.appex; sourceTree = BUILT_PRODUCTS_DIR; }; + 58C9F4FC24CE017800A026DD /* ShareViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareViewController.swift; sourceTree = ""; }; + 58C9F4FF24CE017800A026DD /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/MainInterface.storyboard; sourceTree = ""; }; + 58C9F50124CE017800A026DD /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 58C9F50B24CE084600A026DD /* EcencyDebug.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; name = EcencyDebug.entitlements; path = Ecency/EcencyDebug.entitlements; sourceTree = ""; }; + 58C9F50C24CE0B9800A026DD /* EcencyShareDebug.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = EcencyShareDebug.entitlements; sourceTree = ""; }; 58F6300F2350580B0017C953 /* libRealmJS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libRealmJS.a; sourceTree = BUILT_PRODUCTS_DIR; }; 58F9BCC224793C61004F0790 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; 5D41D0DE754DA8627FF2545C /* Pods-Ecency2.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Ecency2.release.xcconfig"; path = "Target Support Files/Pods-Ecency2/Pods-Ecency2.release.xcconfig"; sourceTree = ""; }; @@ -165,8 +195,8 @@ buildActionMask = 2147483647; files = ( 05B6C49424C306CE00B7FA60 /* StoreKit.framework in Frameworks */, - F77F6C7E54F3C783A2773E9D /* BuildFile in Frameworks */, - 2B3CF3607B7CB9B7296FD5EF /* BuildFile in Frameworks */, + F77F6C7E54F3C783A2773E9D /* (null) in Frameworks */, + 2B3CF3607B7CB9B7296FD5EF /* (null) in Frameworks */, DC0E25610BB5F49AFF4514AD /* libPods-Ecency.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -187,6 +217,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 58C9F4F724CE017800A026DD /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ @@ -210,6 +247,7 @@ 13B07FAE1A68108700A75B9A /* Ecency */ = { isa = PBXGroup; children = ( + 58C9F50B24CE084600A026DD /* EcencyDebug.entitlements */, 58F9BCC224793C61004F0790 /* GoogleService-Info.plist */, 58190B3D23294823000EA0E1 /* Ecency.entitlements */, 008F07F21AC5B25A0029DE68 /* main.jsbundle */, @@ -312,6 +350,17 @@ name = "Recovered References"; sourceTree = ""; }; + 58C9F4FB24CE017800A026DD /* EcencyShare */ = { + isa = PBXGroup; + children = ( + 58C9F50C24CE0B9800A026DD /* EcencyShareDebug.entitlements */, + 58C9F4FC24CE017800A026DD /* ShareViewController.swift */, + 58C9F4FE24CE017800A026DD /* MainInterface.storyboard */, + 58C9F50124CE017800A026DD /* Info.plist */, + ); + path = EcencyShare; + sourceTree = ""; + }; 832341AE1AAA6A7D00B99B32 /* Libraries */ = { isa = PBXGroup; children = ( @@ -327,6 +376,7 @@ 13B07FAE1A68108700A75B9A /* Ecency */, 832341AE1AAA6A7D00B99B32 /* Libraries */, 00E356EF1AD99517003FC87E /* EcencyTests */, + 58C9F4FB24CE017800A026DD /* EcencyShare */, 83CBBA001A601CBA00E9B192 /* Products */, 2D16E6871FA4F8E400B85C8A /* Frameworks */, 258E34A3BDFFFBF80D598187 /* Pods */, @@ -345,6 +395,7 @@ 2D02E47B1E0B4A5D006451C7 /* Ecency-tvOS.app */, 2D02E4901E0B4A5D006451C7 /* Ecency-tvOSTests.xctest */, 05B6C4B724C306CE00B7FA60 /* Ecency.app */, + 58C9F4FA24CE017800A026DD /* EcencyShare.appex */, ); name = Products; sourceTree = ""; @@ -382,10 +433,12 @@ 05B6C4B124C306CE00B7FA60 /* Bundle React Native code and images */, 53FB8F8B28F502EE3B240FD6 /* [CP] Copy Pods Resources */, 4436D72554B718932B21C9FD /* [CP-User] [RNFB] Core Configuration */, + 58C9F50524CE017800A026DD /* Embed App Extensions */, ); buildRules = ( ); dependencies = ( + 58C9F50324CE017800A026DD /* PBXTargetDependency */, ); name = Ecency; productName = Ecency; @@ -432,12 +485,31 @@ productReference = 2D02E4901E0B4A5D006451C7 /* Ecency-tvOSTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; + 58C9F4F924CE017800A026DD /* EcencyShare */ = { + isa = PBXNativeTarget; + buildConfigurationList = 58C9F50A24CE017800A026DD /* Build configuration list for PBXNativeTarget "EcencyShare" */; + buildPhases = ( + 58C9F4F624CE017800A026DD /* Sources */, + 58C9F4F724CE017800A026DD /* Frameworks */, + 58C9F4F824CE017800A026DD /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = EcencyShare; + productName = EcencyShare; + productReference = 58C9F4FA24CE017800A026DD /* EcencyShare.appex */; + productType = "com.apple.product-type.app-extension"; + }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 83CBB9F71A601CBA00E9B192 /* Project object */ = { isa = PBXProject; attributes = { + DefaultBuildSystemTypeForWorkspace = Original; + LastSwiftUpdateCheck = 1150; LastUpgradeCheck = 940; ORGANIZATIONNAME = Facebook; TargetAttributes = { @@ -459,6 +531,11 @@ ProvisioningStyle = Automatic; TestTargetID = 2D02E47A1E0B4A5D006451C7; }; + 58C9F4F924CE017800A026DD = { + CreatedOnToolsVersion = 11.5; + DevelopmentTeam = N97V3LMBX2; + ProvisioningStyle = Automatic; + }; }; }; buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "Ecency" */; @@ -485,6 +562,7 @@ 00E356ED1AD99517003FC87E /* EcencyTests */, 2D02E47A1E0B4A5D006451C7 /* Ecency-tvOS */, 2D02E48F1E0B4A5D006451C7 /* Ecency-tvOSTests */, + 58C9F4F924CE017800A026DD /* EcencyShare */, ); }; /* End PBXProject section */ @@ -565,6 +643,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 58C9F4F824CE017800A026DD /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 58C9F50024CE017800A026DD /* MainInterface.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ @@ -843,6 +929,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 58C9F4F624CE017800A026DD /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 58C9F4FD24CE017800A026DD /* ShareViewController.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ @@ -851,6 +945,11 @@ target = 2D02E47A1E0B4A5D006451C7 /* Ecency-tvOS */; targetProxy = 2D02E4911E0B4A5D006451C7 /* PBXContainerItemProxy */; }; + 58C9F50324CE017800A026DD /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 58C9F4F924CE017800A026DD /* EcencyShare */; + targetProxy = 58C9F50224CE017800A026DD /* PBXContainerItemProxy */; + }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ @@ -863,6 +962,14 @@ path = Ecency; sourceTree = ""; }; + 58C9F4FE24CE017800A026DD /* MainInterface.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 58C9F4FF24CE017800A026DD /* Base */, + ); + name = MainInterface.storyboard; + sourceTree = ""; + }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ @@ -921,10 +1028,11 @@ isa = XCBuildConfiguration; baseConfigurationReference = B7EDBB6386C14AA3E928B720 /* Pods-Ecency.debug.xcconfig */; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; - CODE_SIGN_ENTITLEMENTS = Ecency/Ecency.entitlements; - CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_ENTITLEMENTS = Ecency/EcencyDebug.entitlements; + CODE_SIGN_IDENTITY = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Manual; CURRENT_PROJECT_VERSION = 2523; @@ -993,6 +1101,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = D474B74D640F78620A926D96 /* Pods-Ecency.release.xcconfig */; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Ecency/Ecency.entitlements; @@ -1170,6 +1279,65 @@ }; name = Release; }; + 58C9F50624CE017800A026DD /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + 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 = EcencyShare/EcencyShareDebug.entitlements; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; + DEBUG_INFORMATION_FORMAT = dwarf; + DEVELOPMENT_TEAM = N97V3LMBX2; + GCC_C_LANGUAGE_STANDARD = gnu11; + INFOPLIST_FILE = EcencyShare/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 13.5; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = app.esteem.mobile.ios.EcencyShare; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 58C9F50724CE017800A026DD /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + 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_IDENTITY = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEVELOPMENT_TEAM = 75B6RXTKGT; + GCC_C_LANGUAGE_STANDARD = gnu11; + INFOPLIST_FILE = EcencyShare/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 13.5; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = app.esteem.mobile.ios.EcencyShare; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; 83CBBA201A601CBA00E9B192 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -1312,6 +1480,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + 58C9F50A24CE017800A026DD /* Build configuration list for PBXNativeTarget "EcencyShare" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 58C9F50624CE017800A026DD /* Debug */, + 58C9F50724CE017800A026DD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "Ecency" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/ios/Ecency/EcencyDebug.entitlements b/ios/Ecency/EcencyDebug.entitlements new file mode 100644 index 000000000..903def2af --- /dev/null +++ b/ios/Ecency/EcencyDebug.entitlements @@ -0,0 +1,8 @@ + + + + + aps-environment + development + + diff --git a/ios/EcencyShare/Base.lproj/MainInterface.storyboard b/ios/EcencyShare/Base.lproj/MainInterface.storyboard new file mode 100644 index 000000000..286a50894 --- /dev/null +++ b/ios/EcencyShare/Base.lproj/MainInterface.storyboard @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/EcencyShare/EcencyShareDebug.entitlements b/ios/EcencyShare/EcencyShareDebug.entitlements new file mode 100644 index 000000000..0c67376eb --- /dev/null +++ b/ios/EcencyShare/EcencyShareDebug.entitlements @@ -0,0 +1,5 @@ + + + + + diff --git a/ios/EcencyShare/Info.plist b/ios/EcencyShare/Info.plist new file mode 100644 index 000000000..48d180112 --- /dev/null +++ b/ios/EcencyShare/Info.plist @@ -0,0 +1,52 @@ + + + + + PHSupportedMediaTypes + + Video + Image + + NSExtensionActivationRule + + NSExtensionActivationSupportsText + + NSExtensionActivationSupportsWebURLWithMaxCount + 1 + NSExtensionActivationSupportsImageWithMaxCount + 100 + NSExtensionActivationSupportsMovieWithMaxCount + 100 + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Ecency + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + NSExtension + + NSExtensionAttributes + + NSExtensionActivationRule + TRUEPREDICATE + + NSExtensionMainStoryboard + MainInterface + NSExtensionPointIdentifier + com.apple.share-services + + + diff --git a/ios/EcencyShare/ShareViewController.swift b/ios/EcencyShare/ShareViewController.swift new file mode 100644 index 000000000..688f7a2f4 --- /dev/null +++ b/ios/EcencyShare/ShareViewController.swift @@ -0,0 +1,337 @@ +// +// ShareViewController.swift +// Example Share +// +// Created by Ajith A B on 30/05/20. +// +import UIKit +import Social +import MobileCoreServices +import Photos + +class ShareViewController: SLComposeServiceViewController { + let hostAppBundleIdentifier = "app.esteem.mobile.ios" + let sharedKey = "ShareKey" + var sharedMedia: [SharedMediaFile] = [] + var sharedText: [String] = [] + let imageContentType = kUTTypeImage as String + let videoContentType = kUTTypeMovie as String + let textContentType = kUTTypeText as String + let urlContentType = kUTTypeURL as String + let fileURLType = kUTTypeFileURL as String; + + override func isContentValid() -> Bool { + return true + } + + override func didSelectPost() { + // This is called after the user selects Post. Do the upload of contentText and/or NSExtensionContext attachments. + if let content = extensionContext!.inputItems[0] as? NSExtensionItem { + if let contents = content.attachments { + for (index, attachment) in (contents).enumerated() { + if attachment.hasItemConformingToTypeIdentifier(imageContentType) { + handleImages(content: content, attachment: attachment, index: index) + } else if attachment.hasItemConformingToTypeIdentifier(textContentType) { + handleText(content: content, attachment: attachment, index: index) + } else if attachment.hasItemConformingToTypeIdentifier(fileURLType) { + handleFiles(content: content, attachment: attachment, index: index) + } else if attachment.hasItemConformingToTypeIdentifier(urlContentType) { + handleUrl(content: content, attachment: attachment, index: index) + } else if attachment.hasItemConformingToTypeIdentifier(videoContentType) { + handleVideos(content: content, attachment: attachment, index: index) + } + } + } + } + } + + override func configurationItems() -> [Any]! { + // To add configuration options via table cells at the bottom of the sheet, return an array of SLComposeSheetConfigurationItem here. + return [] + } + + private func handleText (content: NSExtensionItem, attachment: NSItemProvider, index: Int) { + attachment.loadItem(forTypeIdentifier: textContentType, options: nil) { [weak self] data, error in + + if error == nil, let item = data as? String, let this = self { + + this.sharedText.append(item) + + // If this is the last item, save imagesData in userDefaults and redirect to host app + if index == (content.attachments?.count)! - 1 { + let userDefaults = UserDefaults(suiteName: "group.\(this.hostAppBundleIdentifier)") + userDefaults?.set(this.sharedText, forKey: this.sharedKey) + userDefaults?.synchronize() + self?.didSelectPost(); + this.redirectToHostApp(type: .text) + } + + } else { + self?.dismissWithError() + } + } + } + + private func handleUrl (content: NSExtensionItem, attachment: NSItemProvider, index: Int) { + attachment.loadItem(forTypeIdentifier: urlContentType, options: nil) { [weak self] data, error in + + if error == nil, let item = data as? URL, let this = self { + + this.sharedText.append(item.absoluteString) + + // If this is the last item, save imagesData in userDefaults and redirect to host app + if index == (content.attachments?.count)! - 1 { + let userDefaults = UserDefaults(suiteName: "group.\(this.hostAppBundleIdentifier)") + userDefaults?.set(this.sharedText, forKey: this.sharedKey) + userDefaults?.synchronize() + self?.didSelectPost(); + this.redirectToHostApp(type: .text) + } + + } else { + self?.dismissWithError() + } + } + } + + private func handleImages (content: NSExtensionItem, attachment: NSItemProvider, index: Int) { + attachment.loadItem(forTypeIdentifier: imageContentType, options: nil) { [weak self] data, error in + + if error == nil, let url = data as? URL, let this = self { + // this.redirectToHostApp(type: .media) + // Always copy + let fileExtension = this.getExtension(from: url, type: .video) + let newName = UUID().uuidString + let newPath = FileManager.default + .containerURL(forSecurityApplicationGroupIdentifier: "group.\(this.hostAppBundleIdentifier)")! + .appendingPathComponent("\(newName).\(fileExtension)") + let copied = this.copyFile(at: url, to: newPath) + if(copied) { + this.sharedMedia.append(SharedMediaFile(path: newPath.absoluteString, thumbnail: nil, duration: nil, type: .image)) + } + + // If this is the last item, save imagesData in userDefaults and redirect to host app + if index == (content.attachments?.count)! - 1 { + let userDefaults = UserDefaults(suiteName: "group.\(this.hostAppBundleIdentifier)") + userDefaults?.set(this.toData(data: this.sharedMedia), forKey: this.sharedKey) + userDefaults?.synchronize() + self?.didSelectPost(); + this.redirectToHostApp(type: .media) + } + + } else { + self?.dismissWithError() + } + } + } + + private func handleVideos (content: NSExtensionItem, attachment: NSItemProvider, index: Int) { + attachment.loadItem(forTypeIdentifier: videoContentType, options:nil) { [weak self] data, error in + + if error == nil, let url = data as? URL, let this = self { + + // Always copy + let fileExtension = this.getExtension(from: url, type: .video) + let newName = UUID().uuidString + let newPath = FileManager.default + .containerURL(forSecurityApplicationGroupIdentifier: "group.\(this.hostAppBundleIdentifier)")! + .appendingPathComponent("\(newName).\(fileExtension)") + let copied = this.copyFile(at: url, to: newPath) + if(copied) { + guard let sharedFile = this.getSharedMediaFile(forVideo: newPath) else { + return + } + this.sharedMedia.append(sharedFile) + } + + // If this is the last item, save imagesData in userDefaults and redirect to host app + if index == (content.attachments?.count)! - 1 { + let userDefaults = UserDefaults(suiteName: "group.\(this.hostAppBundleIdentifier)") + userDefaults?.set(this.toData(data: this.sharedMedia), forKey: this.sharedKey) + userDefaults?.synchronize() + self?.didSelectPost(); + this.redirectToHostApp(type: .media) + } + + } else { + self?.dismissWithError() + } + } + } + + private func handleFiles (content: NSExtensionItem, attachment: NSItemProvider, index: Int) { + attachment.loadItem(forTypeIdentifier: fileURLType, options: nil) { [weak self] data, error in + + if error == nil, let url = data as? URL, let this = self { + + // Always copy + let newName = this.getFileName(from :url) + let newPath = FileManager.default + .containerURL(forSecurityApplicationGroupIdentifier: "group.\(this.hostAppBundleIdentifier)")! + .appendingPathComponent("\(newName)") + let copied = this.copyFile(at: url, to: newPath) + if (copied) { + this.sharedMedia.append(SharedMediaFile(path: newPath.absoluteString, thumbnail: nil, duration: nil, type: .file)) + } + + if index == (content.attachments?.count)! - 1 { + let userDefaults = UserDefaults(suiteName: "group.\(this.hostAppBundleIdentifier)") + userDefaults?.set(this.toData(data: this.sharedMedia), forKey: this.sharedKey) + userDefaults?.synchronize() + self?.didSelectPost(); + this.redirectToHostApp(type: .file) + } + + } else { + self?.dismissWithError() + } + } + } + + private func dismissWithError() { + print("[ERROR] Error loading data!") + let alert = UIAlertController(title: "Error", message: "Error loading data", preferredStyle: .alert) + + let action = UIAlertAction(title: "Error", style: .cancel) { _ in + self.dismiss(animated: true, completion: nil) + } + + alert.addAction(action) + present(alert, animated: true, completion: nil) + extensionContext!.completeRequest(returningItems: [], completionHandler: nil) + } + + private func redirectToHostApp(type: RedirectType) { + let url = URL(string: "ShareMedia://dataUrl=\(sharedKey)#\(type)") + var responder = self as UIResponder? + let selectorOpenURL = sel_registerName("openURL:") + + while (responder != nil) { + if (responder?.responds(to: selectorOpenURL))! { + let _ = responder?.perform(selectorOpenURL, with: url) + } + responder = responder!.next + } + extensionContext!.completeRequest(returningItems: [], completionHandler: nil) + } + + enum RedirectType { + case media + case text + case file + } + + func getExtension(from url: URL, type: SharedMediaType) -> 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" + } + } + return ex ?? "Unknown" + } + + func getFileName(from url: URL) -> String { + var name = url.lastPathComponent + + if (name == "") { + name = UUID().uuidString + "." + getExtension(from: url, type: .file) + } + + 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) + } catch (let error) { + print("Cannot copy item at \(srcURL) to \(dstURL): \(error)") + return false + } + return true + } + + private func getSharedMediaFile(forVideo: URL) -> SharedMediaFile? { + 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 SharedMediaFile(path: forVideo.absoluteString, thumbnail: thumbnailPath.absoluteString, duration: duration, type: .video) + } + + var saved = false + let assetImgGenerate = AVAssetImageGenerator(asset: asset) + assetImgGenerate.appliesPreferredTrackTransform = true + // let scale = UIScreen.main.scale + assetImgGenerate.maximumSize = CGSize(width: 360, height: 360) + do { + let img = try assetImgGenerate.copyCGImage(at: CMTimeMakeWithSeconds(600, preferredTimescale: Int32(1.0)), actualTime: nil) + try UIImage.pngData(UIImage(cgImage: img))()?.write(to: thumbnailPath) + saved = true + } catch { + saved = false + } + + return saved ? SharedMediaFile(path: forVideo.absoluteString, thumbnail: thumbnailPath.absoluteString, duration: duration, type: .video) : nil + + } + + private func getThumbnailPath(for url: URL) -> URL { + let fileName = Data(url.lastPathComponent.utf8).base64EncodedString().replacingOccurrences(of: "==", with: "") + let path = FileManager.default + .containerURL(forSecurityApplicationGroupIdentifier: "group.\(hostAppBundleIdentifier)")! + .appendingPathComponent("\(fileName).jpg") + return path + } + + class SharedMediaFile: Codable { + var path: String; // can be image, video or url path. It can also be text content + var thumbnail: String?; // video thumbnail + var duration: Double?; // video duration in milliseconds + var type: SharedMediaType; + + + init(path: String, thumbnail: String?, duration: Double?, type: SharedMediaType) { + self.path = path + self.thumbnail = thumbnail + self.duration = duration + self.type = type + } + + // Debug method to print out SharedMediaFile details in the console + func toString() { + print("[SharedMediaFile] \n\tpath: \(self.path)\n\tthumbnail: \(self.thumbnail)\n\tduration: \(self.duration)\n\ttype: \(self.type)") + } + } + + enum SharedMediaType: Int, Codable { + case image + case video + case file + } + + func toData(data: [SharedMediaFile]) -> Data { + let encodedData = try? JSONEncoder().encode(data) + return encodedData! + } +} + +extension Array { + subscript (safe index: UInt) -> Element? { + return Int(index) < count ? self[Int(index)] : nil + } +} diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 63f0df1a0..c96c0d446 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -307,6 +307,8 @@ PODS: - React - react-native-netinfo (5.9.5): - React + - react-native-receive-sharing-intent (1.0.4): + - React - react-native-splash-screen (3.2.0): - React - react-native-version-number (0.3.6): @@ -427,6 +429,7 @@ DEPENDENCIES: - "react-native-cameraroll (from `../node_modules/@react-native-community/cameraroll`)" - react-native-config (from `../node_modules/react-native-config`) - "react-native-netinfo (from `../node_modules/@react-native-community/netinfo`)" + - react-native-receive-sharing-intent (from `../node_modules/react-native-receive-sharing-intent`) - react-native-splash-screen (from `../node_modules/react-native-splash-screen`) - react-native-version-number (from `../node_modules/react-native-version-number`) - react-native-webview (from `../node_modules/react-native-webview`) @@ -532,6 +535,8 @@ EXTERNAL SOURCES: :path: "../node_modules/react-native-config" react-native-netinfo: :path: "../node_modules/@react-native-community/netinfo" + react-native-receive-sharing-intent: + :path: "../node_modules/react-native-receive-sharing-intent" react-native-splash-screen: :path: "../node_modules/react-native-splash-screen" react-native-version-number: @@ -636,6 +641,7 @@ SPEC CHECKSUMS: react-native-cameraroll: e2917a5e62da9f10c3d525e157e25e694d2d6dfa react-native-config: 54f023214af396f21ff0a9e0fed22620d676c8a1 react-native-netinfo: a53b00d949b6456913aaf507d9dba90c4008c611 + react-native-receive-sharing-intent: feba0a332a07977549a85aa58b496eb44368366a react-native-splash-screen: 200d11d188e2e78cea3ad319964f6142b6384865 react-native-version-number: b415bbec6a13f2df62bf978e85bc0d699462f37f react-native-webview: 160ac8d6bb974e2933f2de6bb7464a8e934ff31d @@ -672,4 +678,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 84e32ce5543427579b8c72d77fd175fe29268d92 -COCOAPODS: 1.9.3 +COCOAPODS: 1.8.4 diff --git a/package.json b/package.json index 4225885be..f6102b455 100644 --- a/package.json +++ b/package.json @@ -80,6 +80,7 @@ "react-native-push-notification": "^3.5.1", "react-native-qrcode-svg": "^6.0.3", "react-native-reanimated": "^1.3.0", + "react-native-receive-sharing-intent": "^1.0.4", "react-native-screens": "^2.9.0", "react-native-scrollable-tab-view": "esteemapp/react-native-scrollable-tab-view", "react-native-snap-carousel": "^3.8.0", diff --git a/src/screens/application/container/applicationContainer.js b/src/screens/application/container/applicationContainer.js index 1e8d4a8d9..1626144b8 100644 --- a/src/screens/application/container/applicationContainer.js +++ b/src/screens/application/container/applicationContainer.js @@ -17,6 +17,7 @@ import { import messaging from '@react-native-firebase/messaging'; import PushNotification from 'react-native-push-notification'; import VersionNumber from 'react-native-version-number'; +import ReceiveSharingIntent from 'react-native-receive-sharing-intent'; // Constants import AUTH_TYPE from '../../../constants/authType'; @@ -146,6 +147,17 @@ class ApplicationContainer extends Component { }); } }); + + ReceiveSharingIntent.getReceivedFiles( + (files) => { + console.log('files :>> ', files); + // files returns as JSON Array example + //[{ filePath: null, text: null, weblink: null, mimeType: null, contentUri: null, fileName: null, extension: null }] + }, + (error) => { + console.log('error :>> ', error); + }, + ); }; componentDidUpdate(prevProps, prevState) { diff --git a/yarn.lock b/yarn.lock index d94a4eb7f..65215a019 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7580,6 +7580,11 @@ react-native-reanimated@^1.3.0: dependencies: fbjs "^1.0.0" +react-native-receive-sharing-intent@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/react-native-receive-sharing-intent/-/react-native-receive-sharing-intent-1.0.4.tgz#9b2ad2f46b7d301e8091da25f41a9a0d52d162a2" + integrity sha512-y2LF/IcmcB3DBPtjqKN80qg814xwWOZw1e1yw5jnppzMVQVmU4bPQWaGgWqr2wppq/PdWiw3shgc5oRCZC5bSg== + react-native-safe-area-view@^0.14.9: version "0.14.9" resolved "https://registry.yarnpkg.com/react-native-safe-area-view/-/react-native-safe-area-view-0.14.9.tgz#90ee8383037010d9a5055a97cf97e4c1da1f0c3d"