Instantly share code, notes, and snippets.
Created
October 17, 2022 02:51
-
Star
(0)
0
You must be signed in to star a gist -
Fork
(0)
0
You must be signed in to fork a gist
-
Save frankcalise/2baaf63d56160e2f3420ae3a7e27ae70 to your computer and use it in GitHub Desktop.
react-native-share-menu iOS Share without preview UI
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// ShareViewController.swift | |
// RNShareMenu | |
// | |
// DO NOT EDIT THIS FILE. IT WILL BE OVERRIDEN BY NPM OR YARN. | |
// | |
// Created by Gustavo Parreira on 26/07/2020. | |
// | |
// Modified by Veselin Stoyanov on 17/04/2021. | |
import Foundation | |
import MobileCoreServices | |
import UIKit | |
import Social | |
import RNShareMenu | |
class ShareViewController: SLComposeServiceViewController { | |
var hostAppId: String? | |
var hostAppUrlScheme: 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)") | |
} | |
guard let items = extensionContext?.inputItems as? [NSExtensionItem] else { | |
cancelRequest() | |
return | |
} | |
handlePost(items) | |
} | |
override func isContentValid() -> Bool { | |
// Do validation of contentText and/or NSExtensionContext attachments here | |
return true | |
} | |
override func didSelectPost() { | |
// This is called after the user selects Post. Do the upload of contentText and/or NSExtensionContext attachments. | |
//guard let items = extensionContext?.inputItems as? [NSExtensionItem] else { | |
// cancelRequest() | |
// return | |
//} | |
//handlePost(items) | |
} | |
override func configurationItems() -> [Any]! { | |
// To add configuration options via table cells at the bottom of the sheet, return an array of SLComposeSheetConfigurationItem here. | |
return [] | |
} | |
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) | |
return | |
} | |
guard let userDefaults = UserDefaults(suiteName: "group.\(hostAppId)") else { | |
self.exit(withError: NO_APP_GROUP_ERROR) | |
return | |
} | |
if let data = extraData { | |
self.storeExtraData(data) | |
} else { | |
self.removeExtraData() | |
} | |
let semaphore = DispatchSemaphore(value: 0) | |
var results: [Any] = [] | |
for item in items { | |
guard let attachments = item.attachments else { | |
self.cancelRequest() | |
return | |
} | |
for provider in attachments { | |
if provider.isText { | |
self.storeText(withProvider: provider, semaphore) | |
} else if provider.isURL { | |
self.storeUrl(withProvider: provider, semaphore) | |
} else { | |
self.storeFile(withProvider: provider, semaphore) | |
} | |
semaphore.wait() | |
} | |
} | |
userDefaults.set(self.sharedItems, | |
forKey: USER_DEFAULTS_KEY) | |
userDefaults.synchronize() | |
self.openHostApp() | |
} | |
} | |
func storeExtraData(_ data: [String:Any]) { | |
guard let hostAppId = self.hostAppId else { | |
print("Error: \(NO_INFO_PLIST_INDENTIFIER_ERROR)") | |
return | |
} | |
guard let userDefaults = UserDefaults(suiteName: "group.\(hostAppId)") else { | |
print("Error: \(NO_APP_GROUP_ERROR)") | |
return | |
} | |
userDefaults.set(data, forKey: USER_DEFAULTS_EXTRA_DATA_KEY) | |
userDefaults.synchronize() | |
} | |
func removeExtraData() { | |
guard let hostAppId = self.hostAppId else { | |
print("Error: \(NO_INFO_PLIST_INDENTIFIER_ERROR)") | |
return | |
} | |
guard let userDefaults = UserDefaults(suiteName: "group.\(hostAppId)") else { | |
print("Error: \(NO_APP_GROUP_ERROR)") | |
return | |
} | |
userDefaults.removeObject(forKey: USER_DEFAULTS_EXTRA_DATA_KEY) | |
userDefaults.synchronize() | |
} | |
func storeText(withProvider provider: NSItemProvider, _ semaphore: DispatchSemaphore) { | |
provider.loadItem(forTypeIdentifier: kUTTypeText as String, options: nil) { (data, error) in | |
guard (error == nil) else { | |
self.exit(withError: error.debugDescription) | |
return | |
} | |
guard let text = data as? String else { | |
self.exit(withError: COULD_NOT_FIND_STRING_ERROR) | |
return | |
} | |
self.sharedItems.append([DATA_KEY: text, MIME_TYPE_KEY: "text/plain"]) | |
semaphore.signal() | |
} | |
} | |
func storeUrl(withProvider provider: NSItemProvider, _ semaphore: DispatchSemaphore) { | |
provider.loadItem(forTypeIdentifier: kUTTypeURL as String, options: nil) { (data, error) in | |
guard (error == nil) else { | |
self.exit(withError: error.debugDescription) | |
return | |
} | |
guard let url = data as? URL else { | |
self.exit(withError: COULD_NOT_FIND_URL_ERROR) | |
return | |
} | |
self.sharedItems.append([DATA_KEY: url.absoluteString, MIME_TYPE_KEY: "text/plain"]) | |
semaphore.signal() | |
} | |
} | |
func storeFile(withProvider provider: NSItemProvider, _ semaphore: DispatchSemaphore) { | |
provider.loadItem(forTypeIdentifier: kUTTypeData as String, options: nil) { (data, error) in | |
guard (error == nil) else { | |
self.exit(withError: error.debugDescription) | |
return | |
} | |
guard let url = data as? URL else { | |
self.exit(withError: COULD_NOT_FIND_IMG_ERROR) | |
return | |
} | |
guard let hostAppId = self.hostAppId else { | |
self.exit(withError: NO_INFO_PLIST_INDENTIFIER_ERROR) | |
return | |
} | |
guard let groupFileManagerContainer = FileManager.default | |
.containerURL(forSecurityApplicationGroupIdentifier: "group.\(hostAppId)") | |
else { | |
self.exit(withError: NO_APP_GROUP_ERROR) | |
return | |
} | |
let mimeType = url.extractMimeType() | |
let fileExtension = url.pathExtension | |
let fileName = UUID().uuidString | |
let filePath = groupFileManagerContainer | |
.appendingPathComponent("\(fileName).\(fileExtension)") | |
guard self.moveFileToDisk(from: url, to: filePath) else { | |
self.exit(withError: COULD_NOT_SAVE_FILE_ERROR) | |
return | |
} | |
self.sharedItems.append([DATA_KEY: filePath.absoluteString, MIME_TYPE_KEY: mimeType]) | |
semaphore.signal() | |
} | |
} | |
func moveFileToDisk(from srcUrl: URL, to destUrl: URL) -> Bool { | |
do { | |
if FileManager.default.fileExists(atPath: destUrl.path) { | |
try FileManager.default.removeItem(at: destUrl) | |
} | |
try FileManager.default.copyItem(at: srcUrl, to: destUrl) | |
} catch (let error) { | |
print("Could not save file from \(srcUrl) to \(destUrl): \(error)") | |
return false | |
} | |
return true | |
} | |
func exit(withError error: String) { | |
print("Error: \(error)") | |
cancelRequest() | |
} | |
internal func openHostApp() { | |
guard let urlScheme = self.hostAppUrlScheme else { | |
exit(withError: NO_INFO_PLIST_URL_SCHEME_ERROR) | |
return | |
} | |
let url = URL(string: urlScheme) | |
let selectorOpenURL = sel_registerName("openURL:") | |
var responder: UIResponder? = self | |
while responder != nil { | |
if responder?.responds(to: selectorOpenURL) == true { | |
responder?.perform(selectorOpenURL, with: url) | |
} | |
responder = responder!.next | |
} | |
completeRequest() | |
} | |
func completeRequest() { | |
// 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. | |
extensionContext!.completeRequest(returningItems: [], completionHandler: nil) | |
} | |
func cancelRequest() { | |
extensionContext!.cancelRequest(withError: NSError()) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment