Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions ios/Constants.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ public let DISMISS_SHARE_EXTENSION_WITH_ERROR_CODE = 1
public let NO_URL_TYPES_ERROR_MESSAGE = "You have not defined CFBundleURLTypes in your Info.plist"
public let NO_URL_SCHEMES_ERROR_MESSAGE = "You have not defined CFBundleURLSchemes in your Info.plist"
public let NO_SCHEME_ERROR_MESSAGE = "You have not defined a scheme under CFBundleURLSchemes in your Info.plist"
public let NO_APP_GROUP_PLIST_ERROR = "Failed to get App Group. Did you set up App Group ID in your Share Extension Info.plist?"
public let NO_APP_GROUP_ERROR = "Failed to get App Group User Defaults. Did you set up an App Group on your App and Share Extension?"
public let NO_INFO_PLIST_INDENTIFIER_ERROR = "You haven't defined \(HOST_APP_IDENTIFIER_INFO_PLIST_KEY) in your Share Extension's Info.plist"
public let NO_INFO_PLIST_URL_SCHEME_ERROR = "You haven't defined \(HOST_URL_SCHEME_INFO_PLIST_KEY) in your Share Extension's Info.plist"
public let COULD_NOT_FIND_STRING_ERROR = "Couldn't find string"
public let COULD_NOT_FIND_URL_ERROR = "Couldn't find url"
Expand All @@ -24,14 +24,18 @@ public let COULD_NOT_SAVE_FILE_ERROR = "Couldn't save file on disk"
public let NO_EXTENSION_CONTEXT_ERROR = "No extension context attached"
public let NO_DELEGATE_ERROR = "No ReactShareViewDelegate attached"
public let COULD_NOT_FIND_ITEMS_ERROR = "Couldn't find items attached to this share"
public let COULD_NOT_GET_IMAGE_FILE_LOCATION = "Couldn't get image url file location to write to"
public let COULD_NOT_WRITE_IMAGE_DATA =
"Couldn't write image data"
public let COULD_NOT_TURN_DATA_TO_URL = "Couldn't turn data into url"

// MARK: Keys

public let USER_DEFAULTS_KEY = "ShareMenuUserDefaults"
public let USER_DEFAULTS_EXTRA_DATA_KEY = "ShareMenuUserDefaultsExtraData"
public let URL_SCHEME_INFO_PLIST_KEY = "AppURLScheme"
public let HOST_APP_IDENTIFIER_INFO_PLIST_KEY = "HostAppBundleIdentifier"
public let HOST_URL_SCHEME_INFO_PLIST_KEY = "HostAppURLScheme"
public let GROUP_INFO_PLIST_KEY = "GroupID"

public let REACT_SHARE_VIEW_BACKGROUND_COLOR_KEY = "ReactShareViewBackgroundColor"
public let COLOR_RED_KEY = "Red"
Expand Down
14 changes: 11 additions & 3 deletions ios/Modules/ShareMenu.swift
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,11 @@ class ShareMenu: RCTEventEmitter {
}

guard let scheme = url.scheme, scheme == targetUrlScheme else { return }
guard let bundleId = Bundle.main.bundleIdentifier else { return }
guard let userDefaults = UserDefaults(suiteName: "group.\(bundleId)") else {
guard let groupId = Bundle.main.object(forInfoDictionaryKey: GROUP_INFO_PLIST_KEY) as? String else {
print("Error: \(NO_APP_GROUP_PLIST_ERROR)")
return
}
guard let userDefaults = UserDefaults(suiteName: groupId) else {
print("Error: \(NO_APP_GROUP_ERROR)")
return
}
Expand All @@ -102,7 +105,12 @@ class ShareMenu: RCTEventEmitter {
func getSharedText(callback: RCTResponseSenderBlock) {
var data = [DATA_KEY: sharedData] as [String: Any]

if let bundleId = Bundle.main.bundleIdentifier, let userDefaults = UserDefaults(suiteName: "group.\(bundleId)") {
guard let groupId = Bundle.main.object(forInfoDictionaryKey: GROUP_INFO_PLIST_KEY) as? String else {
print("Error: \(NO_APP_GROUP_PLIST_ERROR)")
return
}

if let userDefaults = UserDefaults(suiteName: groupId) {
data[EXTRA_DATA_KEY] = userDefaults.object(forKey: USER_DEFAULTS_EXTRA_DATA_KEY) as? [String: Any]
} else {
print("Error: \(NO_APP_GROUP_ERROR)")
Expand Down
74 changes: 45 additions & 29 deletions ios/Modules/ShareMenuReactView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// RNShareMenu
//
// Created by Gustavo Parreira on 28/07/2020.
// Modified by Veselin Stoyanov on 17/04/2021.
// Modified by Veselin Stoyanov on 03/07/2021.

import Foundation
import MobileCoreServices
Expand Down Expand Up @@ -126,40 +126,16 @@ public class ShareMenuReactView: NSObject {
semaphore.wait()
} else if provider.hasItemConformingToTypeIdentifier(kUTTypeImage as String) {
provider.loadItem(forTypeIdentifier: kUTTypeImage as String, options: nil) { (item, error) in
let imageUrl: URL! = item as? URL

if (imageUrl != nil) {
if let imageData = try? Data(contentsOf: imageUrl) {
results.append([DATA_KEY: imageUrl.absoluteString, MIME_TYPE_KEY: self.extractMimeType(from: imageUrl)])
}
} else {
let image: UIImage! = item as? UIImage

if (image != nil) {
let imageData: Data! = image.pngData();

// Creating temporary URL for image data (UIImage)
guard let imageURL = NSURL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("TemporaryScreenshot.png") else {
return
}

do {
// Writing the image to the URL
try imageData.write(to: imageURL)

results.append([DATA_KEY: imageUrl.absoluteString, MIME_TYPE_KEY: imageURL.extractMimeType()])
} catch {
callback(nil, NSException(name: NSExceptionName(rawValue: "Error"), reason:"Can't load image", userInfo:nil))
}
}
}
let url: URL! = self.getFileUrl(from: item as Any, withCallback: callback) as? URL

results.append([DATA_KEY: url.absoluteString, MIME_TYPE_KEY: self.extractMimeType(from: url)])

semaphore.signal()
}
semaphore.wait()
} else if provider.hasItemConformingToTypeIdentifier(kUTTypeData as String) {
provider.loadItem(forTypeIdentifier: kUTTypeData as String, options: nil) { (item, error) in
let url: URL! = item as? URL
let url: URL! = self.getFileUrl(from: item as Any, withCallback: callback) as? URL

results.append([DATA_KEY: url.absoluteString, MIME_TYPE_KEY: self.extractMimeType(from: url)])

Expand All @@ -176,6 +152,46 @@ public class ShareMenuReactView: NSObject {
}
}

func getFileUrl(from data: Any, withCallback callback: @escaping ([Any]?, NSException?) -> Void) -> Any {
var url: URL! = nil
var image: UIImage! = nil

if data is UIImage {
image = data as? UIImage
}

if data is Data {
image = UIImage(data: data as! Data)!
}

if (image != nil) {
let imageData: Data! = image.pngData()

// Creating temporary URL for image data (UIImage)
guard let imageURL = NSURL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("TemporaryImage.png") else {
callback(nil, NSException(name: NSExceptionName(rawValue: "Error"), reason:"Can't save image in temp file", userInfo:nil))
return ""
}

do {
// Writing the image to the URL
try imageData.write(to: imageURL)
url = imageURL
} catch {
callback(nil, NSException(name: NSExceptionName(rawValue: "Error"), reason:"Can't write image to URL", userInfo:nil))
}
} else {
guard let toUrl = data as? URL else {
callback(nil, NSException(name: NSExceptionName(rawValue: "Error"), reason:"Can't turn data into URL", userInfo:nil))
return ""
}

url = toUrl;
}

return url!
}

func extractMimeType(from url: URL) -> String {
let fileExtension: CFString = url.pathExtension as CFString
guard let extUTI = UTTypeCreatePreferredIdentifierForTag(
Expand Down
78 changes: 55 additions & 23 deletions ios/ShareViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,24 @@ import Social
import RNShareMenu

class ShareViewController: SLComposeServiceViewController {
var hostAppId: String?
var hostAppUrlScheme: String?
var groupId: String?
var sharedItems: [Any] = []

override func viewDidLoad() {
super.viewDidLoad()

if let hostAppId = Bundle.main.object(forInfoDictionaryKey: HOST_APP_IDENTIFIER_INFO_PLIST_KEY) as? String {
self.hostAppId = hostAppId
} else {
print("Error: \(NO_INFO_PLIST_INDENTIFIER_ERROR)")
}

if let hostAppUrlScheme = Bundle.main.object(forInfoDictionaryKey: HOST_URL_SCHEME_INFO_PLIST_KEY) as? String {
self.hostAppUrlScheme = hostAppUrlScheme
} else {
print("Error: \(NO_INFO_PLIST_URL_SCHEME_ERROR)")
}

if let groupId = Bundle.main.object(forInfoDictionaryKey: GROUP_INFO_PLIST_KEY) as? String {
self.groupId = groupId
} else {
print("Error: \(NO_APP_GROUP_PLIST_ERROR)")
}
}

override func isContentValid() -> Bool {
Expand All @@ -57,11 +57,11 @@ class ShareViewController: SLComposeServiceViewController {

func handlePost(_ items: [NSExtensionItem], extraData: [String:Any]? = nil) {
DispatchQueue.global().async {
guard let hostAppId = self.hostAppId else {
self.exit(withError: NO_INFO_PLIST_INDENTIFIER_ERROR)
guard let groupId = self.groupId else {
self.exit(withError: NO_APP_GROUP_PLIST_ERROR)
return
}
guard let userDefaults = UserDefaults(suiteName: "group.\(hostAppId)") else {
guard let userDefaults = UserDefaults(suiteName: groupId) else {
self.exit(withError: NO_APP_GROUP_ERROR)
return
}
Expand All @@ -73,7 +73,6 @@ class ShareViewController: SLComposeServiceViewController {
}

let semaphore = DispatchSemaphore(value: 0)
var results: [Any] = []

for item in items {
guard let attachments = item.attachments else {
Expand Down Expand Up @@ -103,11 +102,11 @@ class ShareViewController: SLComposeServiceViewController {
}

func storeExtraData(_ data: [String:Any]) {
guard let hostAppId = self.hostAppId else {
print("Error: \(NO_INFO_PLIST_INDENTIFIER_ERROR)")
guard let groupId = self.groupId else {
print("Error: \(NO_APP_GROUP_PLIST_ERROR)")
return
}
guard let userDefaults = UserDefaults(suiteName: "group.\(hostAppId)") else {
guard let userDefaults = UserDefaults(suiteName: groupId) else {
print("Error: \(NO_APP_GROUP_ERROR)")
return
}
Expand All @@ -116,11 +115,11 @@ class ShareViewController: SLComposeServiceViewController {
}

func removeExtraData() {
guard let hostAppId = self.hostAppId else {
print("Error: \(NO_INFO_PLIST_INDENTIFIER_ERROR)")
guard let groupId = self.groupId else {
print("Error: \(NO_APP_GROUP_PLIST_ERROR)")
return
}
guard let userDefaults = UserDefaults(suiteName: "group.\(hostAppId)") else {
guard let userDefaults = UserDefaults(suiteName: groupId) else {
print("Error: \(NO_APP_GROUP_ERROR)")
return
}
Expand Down Expand Up @@ -166,16 +165,48 @@ class ShareViewController: SLComposeServiceViewController {
self.exit(withError: error.debugDescription)
return
}
guard let url = data as? URL else {
self.exit(withError: COULD_NOT_FIND_IMG_ERROR)
return

var url: URL! = nil
var image: UIImage! = nil

if data is UIImage {
image = data as? UIImage
}

if data is Data {
image = UIImage(data: data as! Data)!
}
guard let hostAppId = self.hostAppId else {
self.exit(withError: NO_INFO_PLIST_INDENTIFIER_ERROR)

if (image != nil) {
let imageData: Data! = image.pngData()

// Creating temporary URL for image data (UIImage)
guard let imageURL = NSURL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("TemporaryScreenshot.png") else {
self.exit(withError: COULD_NOT_GET_IMAGE_FILE_LOCATION)
return
}

do {
// Writing the image to the URL
try imageData.write(to: imageURL)
url = imageURL
} catch {
self.exit(withError: COULD_NOT_WRITE_IMAGE_DATA)
}
} else {
guard let toUrl = data as? URL else {
self.exit(withError: COULD_NOT_TURN_DATA_TO_URL)
return
}
url = toUrl;
}

guard let groupId = self.groupId else {
self.exit(withError: NO_APP_GROUP_PLIST_ERROR)
return
}
guard let groupFileManagerContainer = FileManager.default
.containerURL(forSecurityApplicationGroupIdentifier: "group.\(hostAppId)")
.containerURL(forSecurityApplicationGroupIdentifier: groupId)
else {
self.exit(withError: NO_APP_GROUP_ERROR)
return
Expand All @@ -193,6 +224,7 @@ class ShareViewController: SLComposeServiceViewController {
}

self.sharedItems.append([DATA_KEY: filePath.absoluteString, MIME_TYPE_KEY: mimeType])

semaphore.signal()
}
}
Expand Down