首页 » 移动 » iOS下载zip文件并解压的例子

iOS下载zip文件并解压的例子

 

使用swift编写的iOS下载文件的例子,使用了Zip第三方库来解压文件。示例代码是从功能拷贝出来的,有些方法可能会没有。swift下载文件的方法是完整的,见class SapDown

//
//  UpdatingView.swift
//  CanonPixma
//
//  Created by huangyawei on 16/4/20.
//  Copyright © 2016年 forecepts. All rights reserved.
//

import UIKit
import Zip
import SwiftyJSON

class UpdatingView: UIView {

private var downloadTask: NSURLSessionDownloadTask?
private var urlString: String?

init(urlString: String) {
super.init(frame: CGRectZero)

self.urlString = urlString

loadUI()
}

required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

func startDownload() {
downloadFile()
}

// MARK: load ui
var titleLabel: UILabel?
var totalSizeLengthView: UIView?
var currentSizeLengthLabel: UILabel?
var sizeDescriptionLabel: UILabel?
func loadUI() {
let coverView = UIView()
coverView.backgroundColor = UIColor.blackColor()
coverView.alpha = 0.75
self.addSubview(coverView)
coverView.snp_makeConstraints{ (make) -> Void in
make.edges.equalTo(self)
}

let containerView = UIView()
containerView.layer.cornerRadius = 4.0
containerView.clipsToBounds = true
containerView.backgroundColor = UIColor.lightGrayColor()
coverView.addSubview(containerView)
containerView.snp_makeConstraints{ (make) -> Void in
make.centerX.equalTo(coverView.snp_centerX)
make.centerY.equalTo(coverView.snp_centerY)
make.width.equalTo(coverView).multipliedBy(0.6)
make.height.equalTo(containerView.snp_width)
}

titleLabel = UILabel()
titleLabel?.text = "Downloading"
containerView.addSubview(titleLabel!)
titleLabel?.snp_makeConstraints{ (make) -> Void in
make.centerX.equalTo(containerView.snp_centerX)
make.height.equalTo(20)
make.top.equalTo(containerView).offset(20)
}
totalSizeLengthView = UIView()
totalSizeLengthView?.backgroundColor = UIColor.whiteColor()
totalSizeLengthView?.layer.cornerRadius = 2
totalSizeLengthView?.clipsToBounds = true
containerView.addSubview(totalSizeLengthView!)
totalSizeLengthView?.snp_makeConstraints{ (make) -> Void in
make.left.equalTo(containerView).offset(10)
make.right.equalTo(containerView).offset(-10)
make.centerY.equalTo(containerView.snp_centerY)
make.height.equalTo(4)
}
currentSizeLengthLabel = UILabel()
currentSizeLengthLabel?.text = ""
currentSizeLengthLabel?.backgroundColor = UIColor.blueColor()
currentSizeLengthLabel?.layer.cornerRadius = 2
totalSizeLengthView?.addSubview(currentSizeLengthLabel!)
currentSizeLengthLabel?.snp_makeConstraints{ (make) -> Void in
make.left.equalTo(totalSizeLengthView!).offset(0)
make.centerY.equalTo(totalSizeLengthView!.snp_centerY)
make.height.equalTo(self.totalSizeLengthView!).multipliedBy(1)
make.width.equalTo(self.totalSizeLengthView!).multipliedBy(0).priorityLow()
}
sizeDescriptionLabel = UILabel()
sizeDescriptionLabel?.text = "0/0 M"
containerView.addSubview(sizeDescriptionLabel!)
sizeDescriptionLabel?.snp_makeConstraints{ (make) -> Void in
make.centerX.equalTo(containerView.snp_centerX)
make.top.equalTo(totalSizeLengthView!.snp_bottom).offset(20)
}
}

// MARK: download zip file
func downloadFile() {

let url = NSURL(string: urlString!)
var totalSize: Float = 0.00
guard let fileName = urlString!.componentsSeparatedByString("/").last else {
return
}

downloadTask = SapDownloader.download(fileName, downloadSource: url!, progressBlockCompletion: { (bytesWritten, bytesExpectedToWrite) -> () in
//                print("progress: \(bytesWritten) / \(bytesExpectedToWrite)")
let downloadedSize = Float(bytesWritten) / Float(1024 * 1024)
if totalSize == 0.00 {
totalSize = Float(bytesExpectedToWrite) / Float(1024 * 1024)
}
let percent = downloadedSize / totalSize
let csize = NSString(format: "%.2f", downloadedSize) as String
let tsize = NSString(format: "%.2f", totalSize) as String
dispatch_async(dispatch_get_main_queue(), {
self.sizeDescriptionLabel?.text = csize + "/" + tsize + " MB"
let totalFrameWidth = self.totalSizeLengthView!.frame.width
self.currentSizeLengthLabel?.frame.size.width = totalFrameWidth * CGFloat(percent)
})
}){ (error, fileDestination) -> () in
if error == nil {
dispatch_async(dispatch_get_main_queue(), {
self.unZipFile(fileDestination)
})
}
}
}

// MARK: unzip file
func unZipFile(filePathUrl: NSURL) {
do {
self.titleLabel?.text = "UnZiping..."
let unzipDirectory = try Zip.quickUnzipFile(filePathUrl, progress: { progress in
dispatch_async(dispatch_get_main_queue(), {
let totalFrameWidth = self.totalSizeLengthView!.frame.width
self.currentSizeLengthLabel?.frame.size.width = totalFrameWidth * CGFloat(progress)
})
})
reSetModelAndImages(unzipDirectory)
} catch {
UIAlertView(title: "Error", message: "Something went wrong.", delegate: nil, cancelButtonTitle: "OK").show()
}
}

// MARK: set file to Model and restore images
func reSetModelAndImages(unzipDirectory: NSURL) {
self.titleLabel?.text = "Restoring..."
let fileManager = NSFileManager.defaultManager()
let updatingFilesPath = unzipDirectory.absoluteString.stringByReplacingOccurrencesOfString("file://", withString: "")
let tempImagesPath = updatingFilesPath + "images"
var isDir: ObjCBool = false
let fileExists = fileManager.fileExistsAtPath(tempImagesPath, isDirectory: &isDir)
if fileExists && isDir  {
let path = fileManager.URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask).first
let imagePath = path!.URLByAppendingPathComponent("images")
do {
try fileManager.createDirectoryAtURL(imagePath, withIntermediateDirectories: true, attributes: nil)
} catch let error as NSError {
print(error)
}
//remove images to image filepath
do {
let imageArray = try fileManager.contentsOfDirectoryAtPath(tempImagesPath)
for image in imageArray {
let sourceFile = tempImagesPath.stringByReplacingOccurrencesOfString("file://", withString: "") + "/" + image
let destFile = imagePath.absoluteString.stringByReplacingOccurrencesOfString("file://", withString: "") + "/" + image
try fileManager.moveItemAtPath(sourceFile, toPath: destFile)
}
} catch {

}
//make json data to model
makeModels(updatingFilesPath + "AppSettings.txt") { json in
let appSettingModel = AppSettingModel(json: json)
var appSettingArray = [AppSettingModel]()
appSettingArray.append(appSettingModel)

CacheArchive.sharedInstance().save(appSettingArray, dataType: CacheArchive.ArchiveDataType.AppSetting)
}
makeModels(updatingFilesPath + "ProductCategories.txt") { json in
guard let categories = json.array else {
return
}
var productCategoryArray = [ProductCategoryModel]()
let parentCategories = categories.filter{ $0["ParentId"] == 0 }
for parentCategory in parentCategories {
let productCategoryModel = ProductCategoryModel(json: parentCategory)
//sub category
var subProductCategoryArray = [ProductCategoryModel]()
let subCategories = categories.filter{ $0["ParentId"] == parentCategory["Id"] }
for subCategory in subCategories {
let subProductCategoryModel = ProductCategoryModel(json: subCategory)
subProductCategoryArray.append(subProductCategoryModel)
}
subProductCategoryArray = subProductCategoryArray.sort{ $0.sortNo < $1.sortNo }
productCategoryModel.productCategoryModel = subProductCategoryArray
productCategoryArray.append(productCategoryModel)
}

CacheArchive.sharedInstance().save(productCategoryArray, dataType: CacheArchive.ArchiveDataType.ProductCategory)
}
makeModels(updatingFilesPath + "Products.txt") { json in
guard let products = json.array else {
return
}
var productArray = [ProductModel]()
for product in products {
let productModel = ProductModel(json: product)
productArray.append(productModel)
}

CacheArchive.sharedInstance().save(productArray, dataType: CacheArchive.ArchiveDataType.Product)
}
makeModels(updatingFilesPath + "VersionLogs.txt") { json in
let versionModel = VersionLogModel(json: json)
var versionArray = [VersionLogModel]()
versionArray.append(versionModel)

CacheArchive.sharedInstance().save(versionArray, dataType: CacheArchive.ArchiveDataType.VersionLog)
}
makeModels(updatingFilesPath + "Articles.txt") { json in
guard let articles = json.array else {
return
}
var articlesArray = [ArticleModel]()
for article in articles {
let articleModel = ArticleModel(json: article)
articlesArray.append(articleModel)
}

CacheArchive.sharedInstance().save(articlesArray, dataType: CacheArchive.ArchiveDataType.Article)
}
//remove temp files
Common.removeFiles(filePath: updatingFilesPath)
Common.removeFiles(download: "downloaded")
//set root window
let landingController = LandingController()
self.window?.rootViewController = landingController
self.window?.makeKeyAndVisible()
}
}

// MARK: make json do model
private func makeModels(filePath: String, model: (JSON) -> Void) {
if Common.fileManager.fileExistsAtPath(filePath) {
guard let data = NSData(contentsOfFile: filePath) else {
return
}
let jsonModels = JSON(data: data)
if jsonModels == nil {
return
}
model(jsonModels)
}
}
}

class SapDownloader: NSObject, NSURLSessionDelegate, NSURLSessionDownloadDelegate {

var downloads = Array<InfoDownload>()
var session: NSURLSession!
let identifierDownload = "com.SapDownloader"

let pathDirectory: NSURL? = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask).first

class InfoDownload: NSObject {
var fileTitle: String!
var downloadSource: NSURL!
var downloadTask: NSURLSessionDownloadTask!
var taskResumeData: NSData!
var isDownloading: Bool!
var downloadComplete: Bool!
var pathDestination: NSURL!
var progressBlockCompletion: ((bytesWritten: Int64, bytesExpectedToWrite: Int64) -> ())!
var responseBlockCompletion: ((error: NSError!, fileDestination: NSURL!) -> ())!

init(downloadTitle fileTitle: String, downloadSource source: NSURL) {
super.init()
self.fileTitle = fileTitle
self.downloadSource = source
self.pathDestination = nil
self.isDownloading = false
self.downloadComplete = false
}
}

class Singleton {
class var sharedInstance: SapDownloader {
struct Static {
static var instance: SapDownloader?
static var token: dispatch_once_t = 0
}
dispatch_once(&Static.token, { () -> Void in
Static.instance = SapDownloader()
Static.instance?.initSessionDownload()
})
return Static.instance!
}
}

private func initSessionDownload() {
let sessionConfiguration = NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier(self.identifierDownload)
sessionConfiguration.allowsCellularAccess = true
sessionConfiguration.HTTPMaximumConnectionsPerHost = 3
self.session = NSURLSession(configuration: sessionConfiguration, delegate: self, delegateQueue: nil)
let defaults = NSUserDefaults.standardUserDefaults()
if let sessionDownloads = defaults.valueForKey("downloadSession") {
self.downloads = sessionDownloads as! Array<InfoDownload>
}
}

private func saveDataTaskDownload(currentDownload: InfoDownload, location: NSURL) -> NSError? {
let fileManager = NSFileManager.defaultManager()
let pathData = currentDownload.pathDestination
var theError: NSError?

if fileManager.fileExistsAtPath(pathData!.path!) == true {
do {
try fileManager.replaceItemAtURL(pathData!, withItemAtURL: location, backupItemName: nil, options: .UsingNewMetadataOnly, resultingItemURL: nil)
} catch let error as NSError {
theError = error
}
} else {
do {
try fileManager.moveItemAtURL(location, toURL: pathData!)
} catch let error as NSError {
theError = error
}
}
return theError
}

class func setDestinationDownload(currentDownload: InfoDownload, urlDestination: NSURL?) -> NSError? {
let fileManager = NSFileManager.defaultManager()
var theError: NSError?

if urlDestination == nil {
currentDownload.pathDestination = fileManager.URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask).first
let path = currentDownload.pathDestination.URLByAppendingPathComponent("downloaded")
do {
try fileManager.createDirectoryAtURL(path, withIntermediateDirectories: true, attributes: nil)
currentDownload.pathDestination = path.URLByAppendingPathComponent("\(currentDownload.fileTitle)")
} catch let error as NSError {
theError = error
}
}else {
var path = fileManager.URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask).first
path = path?.URLByAppendingPathComponent(urlDestination!.path!)

do {
try fileManager.createDirectoryAtURL(path!, withIntermediateDirectories: true, attributes: nil)
currentDownload.pathDestination = path?.URLByAppendingPathComponent(currentDownload.fileTitle)
} catch let error as NSError {
theError = error
}
}
return theError
}

func URLSessionDidFinishEventsForBackgroundURLSession(session: NSURLSession) {
session.getTasksWithCompletionHandler{ (dataTask: [NSURLSessionDataTask]!, uploadTask: [NSURLSessionUploadTask]!, downloadTask: [NSURLSessionDownloadTask]!) in

}
}

func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didFinishDownloadingToURL location: NSURL) {
if let selectedDownloadTask = SapDownloader.getTaskByIdentifier(downloadTask.taskIdentifier) {
selectedDownloadTask.downloadTask.cancel()
self.saveDataTaskDownload(selectedDownloadTask, location: location)
selectedDownloadTask.responseBlockCompletion(error: nil, fileDestination: selectedDownloadTask.pathDestination)
if let index = Singleton.sharedInstance.downloads.indexOf(selectedDownloadTask) {
Singleton.sharedInstance.downloads.removeAtIndex(index)
}
}
}

func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
if let selectedDownloadTask = SapDownloader.getTaskByIdentifier(downloadTask.taskIdentifier) {
selectedDownloadTask.progressBlockCompletion?(bytesWritten: totalBytesWritten, bytesExpectedToWrite: totalBytesExpectedToWrite)
}
}

class func getTaskByIdentifier(identifier: Int) -> InfoDownload! {
var selectedDownload: InfoDownload! = nil
for currentDownload in Singleton.sharedInstance.downloads {
if currentDownload.downloadTask.taskIdentifier == identifier {
selectedDownload = currentDownload
return selectedDownload
}
}
return nil
}

private class func downloadFile(fileName: String, downloadSource sourceUrl: NSURL, destination: NSURL?, progressBlockCompletion progressBlock: ((bytesWritten: Int64, bytesExpectedToWrite: Int64)->())?, responseBlockCompletion responseBlock: ((error: NSError!, fileDestination: NSURL!) -> ())) -> NSURLSessionDownloadTask {

for infoDownload in Singleton.sharedInstance.downloads {
if infoDownload.downloadSource == sourceUrl {
infoDownload.isDownloading = true
infoDownload.downloadTask = Singleton.sharedInstance.session.downloadTaskWithResumeData(infoDownload.taskResumeData)
infoDownload.downloadTask.resume()
return infoDownload.downloadTask
}
}

let newDownload = InfoDownload(downloadTitle: fileName, downloadSource: sourceUrl)
newDownload.progressBlockCompletion = progressBlock
newDownload.responseBlockCompletion = responseBlock

if let errorDestination = self.setDestinationDownload(newDownload, urlDestination: destination) {
responseBlock(error: errorDestination, fileDestination: nil)
return newDownload.downloadTask
}

newDownload.downloadTask = Singleton.sharedInstance.session.downloadTaskWithURL(newDownload.downloadSource)
newDownload.downloadTask.resume()
newDownload.isDownloading = true
Singleton.sharedInstance.downloads.append(newDownload)

return newDownload.downloadTask
}

class func download(fileName: String, downloadSource sourceUrl: NSURL, progressBlockCompletion progressBlock: ((bytesWritten: Int64, bytesExpectedToWrite: Int64)->())?, responseBlockCompletion responseBlock: ((error: NSError!, fileDestination: NSURL!) -> ())) -> NSURLSessionDownloadTask {

return self.downloadFile(fileName, downloadSource: sourceUrl, destination: nil, progressBlockCompletion: progressBlock, responseBlockCompletion: responseBlock)

}

class func download(fileName: String, downloadSource sourceUrl: NSURL, pathDestination destination: NSURL,progressBlockCompletion progressBlock: ((bytesWritten: Int64, bytesExpectedToWrite: Int64)->())?, responseBlockCompletion responseBlock: ((error: NSError!, fileDestination: NSURL!) -> ())) -> NSURLSessionDownloadTask {

return self.downloadFile(fileName, downloadSource: sourceUrl, destination: destination, progressBlockCompletion: progressBlock, responseBlockCompletion: responseBlock)
}

class func pauseDownload(downloadTask task: NSURLSessionDownloadTask) {
if let selectedDownload = self.getTaskByIdentifier(task.taskIdentifier) {
selectedDownload.isDownloading = false

task.cancelByProducingResumeData{ (data: NSData?) -> Void in
selectedDownload.taskResumeData = data
selectedDownload.isDownloading = false
}
}
}

class func resumeDownload(downloadTask task: NSURLSessionDownloadTask) {
if let selectedDownload = self.getTaskByIdentifier(task.taskIdentifier) {
if selectedDownload.isDownloading == false {
selectedDownload.downloadTask = Singleton.sharedInstance.session.downloadTaskWithResumeData(selectedDownload.taskResumeData)
selectedDownload.isDownloading = true
selectedDownload.downloadTask.resume()
}
}
}

class func cancelDownload(downloadTask task: NSURLSessionDownloadTask) {
if let selectedDownload = self.getTaskByIdentifier(task.taskIdentifier) {
selectedDownload.downloadTask.cancel()
}
}

}

原文链接:iOS下载zip文件并解压的例子,转载请注明来源!