Xcode 10 beta 6のiOS12シミュレータで検証しました。
ダウンロードを再開するためのplistの内容
下記のコードはAlamofireでファイルをダウンロードするリクエストです。
request.cancel()を呼ぶとエラーを返します。そのエラーの中にダウンロードを再開するためのplistが含まれています。
let request = self.manager
.download(String(format : DownloadService.requestFormat, url, id), to: destination)
.downloadProgress(closure: {[weak self] progress in
guard let wself = self else {
return
}
if let progressClosure = wself.progressClosure {
progressClosure(id, progress.fractionCompleted)
}
})
.response(completionHandler: {[weak self] response in
guard let wself = self else {
return
}
guard let error = response.error else {
if let completedClosure = wself.completedClosure {
let cacheURL = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask)[0]
let fileUrl = cacheURL.appendingPathComponent(String(format : DownloadService.resumeFileFormat, id))
if FileManager.default.fileExists(atPath: fileUrl.path) {
do {
try FileManager.default.removeItem(at: fileUrl)
} catch {
print("file delete error")
}
}
completedClosure(id)
}
return
}
//キャンセルの場合もエラーが返ってくる
guard let resumeData = response.resumeData else {
if let errorClosure = wself.errorClosure {
errorClosure(error)
}
return
}
do {
//plistを保存する
let cacheURL = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask)[0]
let fileUrl = cacheURL.appendingPathComponent(String(format : DownloadService.resumeFileFormat, id))
try resumeData.write(to: fileUrl)
if let pauseClosure = wself.pauseClosure {
pauseClosure(id)
}
} catch {
print("plist write error")
return
}
return
})
今回調査したところ、下図のようにiOS11とiOS12でplistの内容が変更されていました。
以前まではplistを保存する方法としてPropertyListSerialization propertyList(from:options:format:)でNSDictionaryに変換してからwrite(to:atomically:)で保存していました。
//plistを保存する
let plist = try PropertyListSerialization.propertyList(from: resumeData, options: [.mutableContainersAndLeaves], format: nil)
let cacheURL = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask)[0]
let fileUrl = cacheURL.appendingPathComponent(String(format : DownloadService.resumeFileFormat, id))
if !(plist as! NSDictionary).write(to: fileUrl, atomically: true) {
print("plist write error")
return
}
iOS12では保存できなくなっていたので、Data write(to:options:)で保存するように変更しました。
バグ
ダウンロード中にアプリを閉じて、再起動すると未完了のURLSessionTaskがSessionManager.sessionの中に残っています。キャンセルしたときと同様にURLSessionTask.errorの中にplistがあります。このplistを使うことでアプリを再起動してもダウンロードを継続することができます。
このplistでダウンロードを再開してから、もう1回アプリの再起動を行うとURLSessionTaskのoriginalRequestが消失します...。