SWIFT - 将文件上传到 icloud 文档未完成

Posted

技术标签:

【中文标题】SWIFT - 将文件上传到 icloud 文档未完成【英文标题】:SWIFT - Uploading file to icloud documents does not finish 【发布时间】:2020-01-25 03:24:03 【问题描述】:

我使用了下面页面上的教程,由于某种原因,文件开始上传并在控制台上显示为 95%,但从未显示“备份上传完成”的消息。该应用仅用于测试sample.mp4文件的上传。

https://medium.com/swlh/backup-your-applications-data-with-icloud-and-track-progress-48a00ebd2891

//  BackupToIcloudController.swift


import Foundation

import UIKit

class BackupToIcloudController: UIViewController 

    override func viewDidLoad() 
        super.viewDidLoad()

        let button = UIButton(frame: CGRect(x: UIScreen.main.bounds.midX - 150, y: UIScreen.main.bounds.midY - 20, width: 300, height: 40))
        button.setTitle("Upload to iCloud", for: .normal)
        button.addTarget(self, action: #selector(self.uploadToCloud), for: .touchUpInside)
        button.backgroundColor = .blue
        view.addSubview(button)
    

    @objc func uploadToCloud() 
        let backup = Backup.init()
        try? backup.startBackup()
    

    @IBAction func back(_ sender: Any) 
        self.dismiss(animated: true, completion: nil)
    

//  Backup.swift


import Foundation

class Backup: NSObject 

   var query: NSMetadataQuery!

   override init() 
        super.init()
        initialiseQuery()
        addNotificationObservers()
    
    func initialiseQuery() 

        query = NSMetadataQuery.init()
        query.operationQueue = .main
        query.searchScopes = [NSMetadataQueryUbiquitousDataScope]
        query.predicate = NSPredicate(format: "%K LIKE %@", NSMetadataItemFSNameKey, "sample.mp4")
    

    func startBackup() throws 
        guard let fileURL = Bundle.main.url(forResource: "sample", withExtension: "mp4") else 
            return

        
        guard let containerURL = FileManager.default.url(forUbiquityContainerIdentifier: "iCloud.mylojastore.com.backup") else  return 

        if !FileManager.default.fileExists(atPath: containerURL.path) 
            try FileManager.default.createDirectory(at: containerURL, withIntermediateDirectories: true, attributes: nil)
        
        let backupFileURL = containerURL.appendingPathComponent("sample.mp4")
        if FileManager.default.fileExists(atPath: backupFileURL.path) 
           try FileManager.default.removeItem(at: backupFileURL)
            try FileManager.default.copyItem(at: fileURL, to: backupFileURL)
         else 
            try FileManager.default.copyItem(at: fileURL, to: backupFileURL)
        

        query.operationQueue?.addOperation( [weak self] in
            _ = self?.query.start()
            self?.query.enableUpdates()
        )
    
    func addNotificationObservers() 

        NotificationCenter.default.addObserver(forName: NSNotification.Name.NSMetadataQueryDidStartGathering, object: query, queue: query.operationQueue)  (notification) in
            self.processCloudFiles()
        

        NotificationCenter.default.addObserver(forName: NSNotification.Name.NSMetadataQueryDidUpdate, object: query, queue: query.operationQueue)  (notification) in
            self.processCloudFiles()
        
        NotificationCenter.default.addObserver(forName: NSNotification.Name.NSMetadataQueryDidFinishGathering, object: query, queue: query.operationQueue)  (notification) in
            self.processCloudFiles()
        
        NotificationCenter.default.addObserver(forName: NSNotification.Name.NSMetadataQueryGatheringProgress, object: query, queue: query.operationQueue)  (notification) in
                  print("progress")
               
    

    @objc func processCloudFiles() 

        if query.results.count == 0  return 
        var fileItem: NSMetadataItem?
        var fileURL: URL?

        for item in query.results 

            guard let item = item as? NSMetadataItem else  continue 
            guard let fileItemURL = item.value(forAttribute: NSMetadataItemURLKey) as? URL else  continue 
            if fileItemURL.lastPathComponent.contains("sample.mp4") 
                fileItem = item
                fileURL = fileItemURL
            
        

        let fileValues = try? fileURL!.resourceValues(forKeys: [URLResourceKey.ubiquitousItemIsUploadingKey])
        if let fileUploaded = fileItem?.value(forAttribute: NSMetadataUbiquitousItemIsUploadedKey) as? Bool, fileUploaded == true, fileValues?.ubiquitousItemIsUploading == false 
            print("backup upload complete")

         else if let error = fileValues?.ubiquitousItemUploadingError 
            print("upload error---", error.localizedDescription)

         else 
            if let fileProgress = fileItem?.value(forAttribute: NSMetadataUbiquitousItemPercentUploadedKey) as? Double 
                print("uploaded percent ---", fileProgress)
            
        
    

【问题讨论】:

【参考方案1】:

看来我们必须在 plist 中指定容器才能使其工作。

将以下内容添加到您的 plist 中。

<key>NSUbiquitousContainers</key>
<dict>
    <key>iCloud.iCloudBackup</key>
    <dict>
        <key>NSUbiquitousContainerIsDocumentScopePublic</key>
        <true/>
        <key>NSUbiquitousContainerName</key>
        <string>iCloudBackup</string>
        <key>NSUbiquitousContainerSupportedFolderLevels</key>
        <string>Any</string>
    </dict>
</dict>

你应该看到这个。

【讨论】:

直到今天我仍然无法解决这个问题......你提到的我已经提出......有时它可以工作,有时它会继续出现这个问题。它们没有交替,它工作了好几次,突然它开始几次超过 95%,然后又工作了。我什至暂时把我的应用程序的这个功能放在一边,但我真的需要一个解决方案。 NSUbiquitousContainerName 参数中输入的名称应该在哪里使用?我从来没有发现这个名字的用途 它将被用作Mac上iCloud驱动器文件夹中的文件夹名称,或ios上的文件应用程序中的文件夹名称。

以上是关于SWIFT - 将文件上传到 icloud 文档未完成的主要内容,如果未能解决你的问题,请参考以下文章

编程有点新 - 将大量与编程相关的文件上传到 iCloud [关闭]

强制 iOS 将文件上传到 iCloud

如何在 Swift 中以编程方式打开 icloud 应用程序(文件)

如何在 swift 2.0 中将 .pdf 文件转换为 base64 字符串?

如何在 iCloud 中搜索上传的文件

Swift - 无法连接到 iCloud 文档