mirror of
https://github.com/SideStore/SideStore.git
synced 2026-02-09 06:43:25 +01:00
130 lines
4.3 KiB
Swift
130 lines
4.3 KiB
Swift
//
|
|
// DownloadAppOperation.swift
|
|
// AltStore
|
|
//
|
|
// Created by Riley Testut on 6/10/19.
|
|
// Copyright © 2019 Riley Testut. All rights reserved.
|
|
//
|
|
|
|
import Foundation
|
|
import Roxas
|
|
|
|
import AltSign
|
|
|
|
@objc(DownloadAppOperation)
|
|
class DownloadAppOperation: ResultOperation<InstalledApp>
|
|
{
|
|
let app: App
|
|
|
|
var useCachedAppIfAvailable = false
|
|
lazy var context = DatabaseManager.shared.persistentContainer.newBackgroundContext()
|
|
|
|
private let appIdentifier: String
|
|
private let sourceURL: URL
|
|
private let destinationURL: URL
|
|
|
|
private let session = URLSession(configuration: .default)
|
|
|
|
init(app: App)
|
|
{
|
|
self.app = app
|
|
self.appIdentifier = app.identifier
|
|
self.sourceURL = app.downloadURL
|
|
self.destinationURL = InstalledApp.fileURL(for: app)
|
|
|
|
super.init()
|
|
|
|
self.progress.totalUnitCount = 1
|
|
}
|
|
|
|
override func main()
|
|
{
|
|
super.main()
|
|
|
|
print("Downloading App:", self.appIdentifier)
|
|
|
|
func finishOperation(_ result: Result<URL, Error>)
|
|
{
|
|
do
|
|
{
|
|
let fileURL = try result.get()
|
|
|
|
var isDirectory: ObjCBool = false
|
|
guard FileManager.default.fileExists(atPath: fileURL.path, isDirectory: &isDirectory) else { throw OperationError.appNotFound }
|
|
|
|
let temporaryDirectory = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString)
|
|
try FileManager.default.createDirectory(at: temporaryDirectory, withIntermediateDirectories: true, attributes: nil)
|
|
defer { try? FileManager.default.removeItem(at: temporaryDirectory) }
|
|
|
|
let appBundleURL: URL
|
|
|
|
if isDirectory.boolValue
|
|
{
|
|
// Directory, so assuming this is .app bundle.
|
|
guard Bundle(url: fileURL) != nil else { throw OperationError.invalidApp }
|
|
|
|
appBundleURL = fileURL
|
|
}
|
|
else
|
|
{
|
|
// File, so assuming this is a .ipa file.
|
|
appBundleURL = try FileManager.default.unzipAppBundle(at: fileURL, toDirectory: temporaryDirectory)
|
|
}
|
|
|
|
guard let application = ALTApplication(fileURL: appBundleURL) else { throw OperationError.invalidApp }
|
|
|
|
guard ProcessInfo.processInfo.isOperatingSystemAtLeast(application.minimumiOSVersion) else { throw OperationError.iOSVersionNotSupported(application) }
|
|
|
|
try FileManager.default.copyItem(at: appBundleURL, to: self.destinationURL, shouldReplace: true)
|
|
|
|
self.context.perform {
|
|
let app = self.context.object(with: self.app.objectID) as! App
|
|
|
|
let installedApp: InstalledApp
|
|
|
|
if let app = app.installedApp
|
|
{
|
|
installedApp = app
|
|
|
|
}
|
|
else
|
|
{
|
|
installedApp = InstalledApp(app: app, bundleIdentifier: app.identifier, context: self.context)
|
|
}
|
|
|
|
installedApp.version = app.version
|
|
self.finish(.success(installedApp))
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
self.finish(.failure(error))
|
|
}
|
|
}
|
|
|
|
if self.sourceURL.isFileURL
|
|
{
|
|
finishOperation(.success(self.sourceURL))
|
|
|
|
self.progress.completedUnitCount += 1
|
|
}
|
|
else
|
|
{
|
|
let downloadTask = self.session.downloadTask(with: self.sourceURL) { (fileURL, response, error) in
|
|
do
|
|
{
|
|
let (fileURL, _) = try Result((fileURL, response), error).get()
|
|
finishOperation(.success(fileURL))
|
|
}
|
|
catch
|
|
{
|
|
finishOperation(.failure(error))
|
|
}
|
|
}
|
|
self.progress.addChild(downloadTask.progress, withPendingUnitCount: 1)
|
|
|
|
downloadTask.resume()
|
|
}
|
|
}
|
|
}
|