Closed itsminh99 closed 3 years ago
After I select the text file(.txt, .csv, .tsv) it doesn't redirect to the host app and doesn't receive any files in my app.
I solved using handleFiles function. The reason is because .txt, .csv, .tsv
run handleText function case.
@itsminh99 could you provide your solution, please?
` import UIKit import Social import MobileCoreServices import Photos
class ShareViewController: SLComposeServiceViewController {
let shareProtocol = "hostAppBundleIdentifier"//share url protocol (must be unique to your app, suggest using your apple bundle id, ie:
hostAppBundleIdentifier
) 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;}
}
private func handleUrl (content: NSExtensionItem, attachment: NSItemProvider, index: Int) { attachment.loadItem(forTypeIdentifier: urlContentType, options: nil) { [weak self] data, error in
} }
private func handleImages (content: NSExtensionItem, attachment: NSItemProvider, index: Int) { attachment.loadItem(forTypeIdentifier: imageContentType, options: nil) { [weak self] data, error in
} }
private func handleVideos (content: NSExtensionItem, attachment: NSItemProvider, index: Int) { attachment.loadItem(forTypeIdentifier: videoContentType, options:nil) { [weak self] data, error in
} }
private func handleFiles (content: NSExtensionItem, attachment: NSItemProvider, index: Int) { attachment.loadItem(forTypeIdentifier: fileURLType, options: nil) { [weak self] data, error in
} }
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: "(shareProtocol)://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 } }
`