TUSKit 3.3

TUSKit 3.3

测试测试
语言编程语言 Obj-CObjective C
许可协议 MIT
发布最新发布2024年3月

Kevin van ZonneveldTjeerd in t VeenDonny Wals 维护。



TUSKit 3.3

  • Transloadit

TUSKit

使用 Swift 编写的 iOS 客户端,用于 TUS 分段上传协议

Protocol Version SwiftPM compatible License Platform

通过此客户端,您可以上传常规原始 Data 或文件路径。

使用方法

您可以通过查看示例项目来了解如何实现 TUSKit。

作为起点,请参考 SceneDelegate

以下是如何实例化 TUSClient 实例的方式。

务必在某个地方存储对客户端的引用。然后像平常一样初始化。

final class MyClass {
  let tusClient: TUSClient
  
  init() {
      tusClient = TUSClient(server: URL(string: "https://tusd.tusdemo.net/files")!, sessionIdentifier: "TUS DEMO", storageDirectory: URL(string: "TUS")!)
      tusClient.delegate = self
  }
}

请注意,您可以将自己注册为代表以检索上传的 URL 和可能出现的任何错误。

请注意,您可以向初始化函数传递自己的 URLSession 实例。

您可以通过符合 TUSClientDelegate 接收来自 TUSClient 的更新。

extension MyClass: TUSClientDelegate {
    func didStartUpload(id: UUID, client: TUSClient) {
        print("TUSClient started upload, id is \(id)")
        print("TUSClient remaining is \(client.remainingUploads)")
    }
    
    func didFinishUpload(id: UUID, url: URL, client: TUSClient) {
        print("TUSClient finished upload, id is \(id) url is \(url)")
        print("TUSClient remaining is \(client.remainingUploads)")
        if client.remainingUploads == 0 {
            print("Finished uploading")
        }
    }
    
    func uploadFailed(id: UUID, error: Error, client: TUSClient) {
        print("TUSClient upload failed for \(id) error \(error)")
    }
    
    func fileError(error: TUSClientError, client: TUSClient) {
        print("TUSClient File error \(error)")
    }
    
    
    func totalProgress(bytesUploaded: Int, totalBytes: Int, client: TUSClient) {
    }
    
    
    func progressFor(id: UUID, bytesUploaded: Int, totalBytes: Int, client: TUSClient) {

    }
    
}

开始上传

一个 TUSClient 可以上传 Data 或文件路径(URL格式)。

要上传数据,请使用 upload(data:) 方法。

let data = Data("I am some data".utf8)
let uploadId = try tusClient.upload(data: data)

要一次性上传多个数据文件,请使用 uploadMultiple(dataFiles:) 方法。

要上传单个已存储文件,请获取文件路径并将其传递给客户端。

let pathToFile:URL = ...
let uploadId = try tusClient.uploadFileAt(filePath: pathToFile)

要一次性上传多个文件,您可以使用 uploadFiles(filePaths:) 方法。

自定义上传URL和自定义头部

要指定自定义上传URL(例如,用于TransloadIt)或要添加到文件上传的自定义头部,请参阅与上传相关的 uploadURLcustomHeaders 属性。例如:uploaduploadFileAtuploadFilesuploadMultiple(dataFiles:)

测量上传进度

要了解还有多少文件尚未上传,请参阅 remainingUploads 属性。

请注意,没有提供百分比,因为这取决于您定义上传的起点。例如,如果您上传了10个文件,其中3个已完成,那么您处于3/10的状态。但是,如果在这次上传期间添加了2个新文件,这应该计入3/12吗?还是应该考虑为新的上传?因此是0/9。关于添加新上传时已完成上传的计数方式,这取决于您。

对于字节级别的进度,请实现 TUSClientDelegate 协议并将其设置为 TUSClientdelegate 属性。

上传ID和上下文

通过开始上传,您将收到一个ID。这些ID也可以通过实现 TUSClientDelegate 时传递给您。您可以使用这些ID来识别哪个文件已经完成或失败(但您也可以使用上下文来做这个,详见下文)。如果您想的话,也可以在失败时删除这些文件。您还可以使用这些ID来重试失败的上传。

请注意,TUSClient 将自动尝试上传几次,但如果最终失败,它将放弃并报告错误。在此之后,您可以调用 retry 方法并再次尝试。

上下文

您可以使用 ID 来监控进度并执行其他任务,例如停止上传。但您也可以使用更丰富的信息传递上下文。TUSKit 将通过各种委托调用来返回此上下文。这样,您就无需跟踪上传 ID 的状态。您可以传递一个小对象包含信息,并且您将从这个对象中收到 TUSKit。

安全通知:TUSKit 将此上下文存储在磁盘上,与文件元数据一起。这是为了在会话之间保持信息。

启动新会话

上传可以在任何时候失败。即使在应用处于后台时。

因此,在启动新应用会话后,我们建议您检查可能出现的任何失败的上传,并相应地采取行动。例如,您可以决定对失败的上传进行一些操作,例如重试、删除或向用户报告。

For instance, here is how you can initialize the client and check its failed uploads. Note that we first fetch the id's, after which retry the uploads.
  
tusClient = TUSClient(server: URL(string: "https://tusd.tusdemo.net/files")!, sessionIdentifier: "TUS DEMO", storageDirectory: URL(string: "/TUS")!)
tusClient.delegate = self
tusClient.start()
        
do {
  // When starting, you can retrieve the locally stored uploads that are marked as failure, and handle those.
  // E.g. Maybe some uploads failed from a last session, or failed from a background upload.
  let ids = try tusClient.failedUploadIds()
  for id in ids {
    // You can either retry a failed upload...
    try tusClient.retry(id: id)
    // ...alternatively, you can delete them too
    // tusClient.removeCacheFor(id: id)
  }
} catch {
  // Could not fetch failed id's from disk
}

后台上传

当您集成后台上传时,我们强烈建议您检查后台可能发生的任何失败的上传。请参阅 [启动新会话](#Starting a new Session) 获取更多信息。

iOS 可以利用后台 URLSession 来启用后台上传,以便在用户离开您的应用或锁定设备时继续上传。更多详细信息,请参阅 Apple 的文档 background URLSession。文档主要关注下载,但上传遵循大致相同的原理。

为了使集成后台上传尽可能简单,TUSKit 处理了管理 URLSession 及其委托调用等所有复杂细节。作为 TUSKit 的消费者,您只需像下面展示的那样利用 TUSClient 上的新初始化器

do {
    tusClient = try TUSClient(
        server: URL(string: "https://tusd.tusdemo.net/files")!,
        sessionIdentifier: "TUS DEMO",
        sessionConfiguration: .background(withIdentifier: "com.TUSKit.sample"),
        storageDirectory: URL(string: "/TUS")!,
        chunkSize: 0
    )
} catch {
    // ...
}

设置一切的最简单方法是向 TUSClient 传递一个 URLSession.background 配置。如果您需要不同的配置或不希望有任何后台支持,您可以传递不同的配置。

由于 TUSKit 现在可以在应用程序不再活跃驻留在内存中时运行上传,因此您应该在应用程序启动时始终在 TUSClient 上调用 getStoredUpload 方法来检索所有存储的上传并提取有关哪些上传当前已完成的信息。之后,您可以调用 cleanup 以允许 TUSClient 删除已完成项目的元数据。请参阅示例应用以获取更多详细信息。

重要
当您想支持后台上传时,必须为您的 AppDelegateapplication(_: handleEventsForBackgroundURLSession:completionHandler:) 方法调用 TUSClient.registerBackgroundHandler(_:)。此方法接收一个回调,该回调应始终调用传递给 handleEventsForBackgroundURLSessioncompletionHandler。直接传递完成处理程序是完全可以的。

以下是一个示例

警告:以下信息在 TUSKit 3.1.8 中已弃用。

从 iOS 13 开始,您可以使用 TUSClientscheduleBackgroundTasks() 方法安排后台执行的上传。

安排的任务由 iOS 处理。这意味着每个设备将决定何时在后台上传最佳,例如,当它具有 Wi-Fi 连接并且在夜间较晚的时候。

以示例应用中找到的 SceneDelegate 中的示例为例,您可以相应地安排它们。

class SceneDelegate: UIResponder, UIWindowSceneDelegate {

    // ... snip
    
    func sceneDidEnterBackground(_ scene: UIScene) {
        // Called as the scene transitions from the foreground to the background.
        tusClient.scheduleBackgroundTasks()
    }
}

TUS 协议扩展

客户端默认假定服务器执行了 创建 TUS 协议扩展。如果您的服务器不支持该功能,请确保在客户端初始化器中为 supportedExtensions 参数提供一个空数组。

示例应用

请参考项目内的示例应用了解如何使用 SwiftUI 从 PHPicker 添加照片。您也可以为 UIKit 使用 PHPicker 机制。

并行处理

撰写本文时,此客户端不支持 TUS 的连接选项,但它自动支持单个客户端中的并行上传。它也支持多个客户端。

底层机制

TUSClient 将在报告错误之前重试失败的传输两次(总共三次尝试)。

TUSClient 将尝试完整地上传文件;如果传输中断(例如,连接中断或应用被杀死),它将继续从上次中断的地方继续传输。

TUSClient 将本地存储文件以供上传。它将使用初始化器中传入的 storageDirectory 路径。或者在 documentsdir 内部创建默认目录 /TUS。

TUSClient 将在传输完成后自动移除本地存储的文件。

多个实例

TUSClient 支持多个实例以进行同时无关的上传。

警告:多个客户端不应共享相同的 storageDirectory。请为每个客户端提供一个单独的目录以进行操作,否则可能会出现错误。

请注意,从版本 3.0.0 开始的 TUSClient 已不再是单例。

如果您强烈希望拥有单例,您仍然可以使用静态关键字来创建一个。

final class MyClass {
  static let tusClient: TUSClient = ...
}

但我们不鼓励这样做,因为这会使测试间的重置变得更加困难,并且在多线程环境中会变得有问题。