From e18978d4ba5e769f9b1d33a4d2a7d1b2989ecfc0 Mon Sep 17 00:00:00 2001 From: Aman Harwara Date: Tue, 25 Jul 2023 00:23:25 +0530 Subject: [PATCH] chore: fix file cleanup on ios when sharing files into sn --- .../ReceiveSharingIntent.swift | 13 ++- .../ios/Share To SN/ShareViewController.swift | 89 +++++++------------ .../mobile/src/ReceivedSharedItemsHandler.ts | 22 +++-- 3 files changed, 60 insertions(+), 64 deletions(-) diff --git a/packages/mobile/ios/ReceiveSharingIntent/ReceiveSharingIntent.swift b/packages/mobile/ios/ReceiveSharingIntent/ReceiveSharingIntent.swift index 6d7e5d83f..9b3091319 100644 --- a/packages/mobile/ios/ReceiveSharingIntent/ReceiveSharingIntent.swift +++ b/packages/mobile/ios/ReceiveSharingIntent/ReceiveSharingIntent.swift @@ -118,7 +118,18 @@ class ReceiveSharingIntent: NSObject { @objc func clearFileNames(){ - print("clearFileNames"); + let containerURL = FileManager.default + .containerURL(forSecurityApplicationGroupIdentifier: "group.\(Bundle.main.bundleIdentifier!)")! + let shareTempDirPath = containerURL.appendingPathComponent("ShareTemp", isDirectory: true) + do { + let fileNames = try FileManager.default.contentsOfDirectory(atPath: shareTempDirPath.relativePath) + for fileName in fileNames { + let filePath = shareTempDirPath.appendingPathComponent(fileName) + try FileManager.default.removeItem(at: filePath) + } + } catch { + print(error) + } } diff --git a/packages/mobile/ios/Share To SN/ShareViewController.swift b/packages/mobile/ios/Share To SN/ShareViewController.swift index 296e8c69b..837c28b53 100644 --- a/packages/mobile/ios/Share To SN/ShareViewController.swift +++ b/packages/mobile/ios/Share To SN/ShareViewController.swift @@ -95,16 +95,11 @@ class ShareViewController: SLComposeServiceViewController { 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.\(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 let copiedPath = this.copyToTemporaryPath(url: url, name: "\(newName).\(fileExtension)") { + this.sharedMedia.append(SharedMediaFile(path: copiedPath, thumbnail: nil, duration: nil, type: .image)) } if index == (content.attachments?.count)! - 1 { @@ -125,15 +120,8 @@ class ShareViewController: SLComposeServiceViewController { // Always copy let fileExtension = this.getExtension(from: url, type: .video) let newName = UUID().uuidString - let newPath = FileManager.default - .containerURL(forSecurityApplicationGroupIdentifier: "group.\(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 let copiedPath = this.copyToTemporaryPath(url: url, name: "\(newName).\(fileExtension)") { + this.sharedMedia.append(SharedMediaFile(path: copiedPath, thumbnail: nil, duration: nil, type: .video)) } if index == (content.attachments?.count)! - 1 { @@ -151,14 +139,9 @@ class ShareViewController: SLComposeServiceViewController { 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.\(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 let copiedPath = this.copyToTemporaryPath(url: url, name: newName) { + this.sharedMedia.append(SharedMediaFile(path: copiedPath, thumbnail: nil, duration: nil, type: .file)) } if index == (content.attachments?.count)! - 1 { @@ -171,6 +154,32 @@ class ShareViewController: SLComposeServiceViewController { } } + private func directoryExistsAtPath(_ path: String) -> Bool { + var isDirectory = ObjCBool(true) + let exists = FileManager.default.fileExists(atPath: path, isDirectory: &isDirectory) + return exists && isDirectory.boolValue + } + + private func copyToTemporaryPath(url: URL, name: String) -> String? { + let containerURL = FileManager.default + .containerURL(forSecurityApplicationGroupIdentifier: "group.\(hostAppBundleIdentifier)")! + let shareTempDirPath = containerURL.appendingPathComponent("ShareTemp", isDirectory: true) + if !directoryExistsAtPath(shareTempDirPath.absoluteString) { + do { + try FileManager.default.createDirectory(atPath: shareTempDirPath.relativePath, withIntermediateDirectories: true, attributes: nil) + } catch { + return nil + } + } + let newPath = shareTempDirPath + .appendingPathComponent("\(name)") + let copied = self.copyFile(at: url, to: newPath) + if (copied) { + return newPath.absoluteString + } + return nil + } + private func redirectToHostApp() { let userDefaults = UserDefaults(suiteName: "group.\(hostAppBundleIdentifier)") userDefaults?.set(self.toData(data: self.sharedMedia), forKey: "\(self.sharedKey).media") @@ -263,40 +272,6 @@ class ShareViewController: SLComposeServiceViewController { 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 diff --git a/packages/mobile/src/ReceivedSharedItemsHandler.ts b/packages/mobile/src/ReceivedSharedItemsHandler.ts index 169a7bb6a..dbddc60d8 100644 --- a/packages/mobile/src/ReceivedSharedItemsHandler.ts +++ b/packages/mobile/src/ReceivedSharedItemsHandler.ts @@ -71,6 +71,7 @@ export class ReceivedSharedItemsHandler { } deinit() { + ReceiveSharingIntent.clearFileNames() this.receivedItemsQueue = [] this.eventSub?.remove() } @@ -100,17 +101,13 @@ export class ReceivedSharedItemsHandler { } handleItemsQueue = async () => { - if (!this.receivedItemsQueue.length) { - return - } - const item = this.receivedItemsQueue.shift() if (!item) { return } if (isReceivedAndroidFile(item) || isReceivedIosFile(item)) { - this.sendFileToWebView(item).catch(console.error) + await this.sendFileToWebView(item).catch(console.error) } else if (isReceivedWeblink(item)) { this.webViewRef.current?.postMessage( JSON.stringify({ @@ -134,6 +131,14 @@ export class ReceivedSharedItemsHandler { ) } + if (!this.receivedItemsQueue.length) { + if (Platform.OS === 'ios') { + ReceiveSharingIntent.clearFileNames() + } + + return + } + this.handleItemsQueue().catch(console.error) } @@ -157,7 +162,12 @@ export class ReceivedSharedItemsHandler { private addSharedItemsToQueue = async (url?: string) => { const received = Platform.OS === 'ios' ? await ReceiveSharingIntent.getFileNames(url) : await ReceiveSharingIntent.getFileNames() - ReceiveSharingIntent.clearFileNames() + + // On iOS, we need to wait for the whole queue + // to finish before clearing + if (Platform.OS === 'android') { + ReceiveSharingIntent.clearFileNames() + } if (!received) { return