From a763f469e11a2d58697de113cb3f296611bc1898 Mon Sep 17 00:00:00 2001 From: Riley Testut Date: Tue, 11 Feb 2020 13:29:28 -0800 Subject: [PATCH] Adds support for sideloading unc0ver --- AltStore/Managing Apps/AppManager.swift | 2 + AltStore/My Apps/MyAppsViewController.swift | 54 +++++++++++++++++---- AltStore/Operations/OperationError.swift | 5 ++ 3 files changed, 51 insertions(+), 10 deletions(-) diff --git a/AltStore/Managing Apps/AppManager.swift b/AltStore/Managing Apps/AppManager.swift index 09db9c66..1f384bf3 100644 --- a/AltStore/Managing Apps/AppManager.swift +++ b/AltStore/Managing Apps/AppManager.swift @@ -21,6 +21,8 @@ extension AppManager static let didFetchSourceNotification = Notification.Name("com.altstore.AppManager.didFetchSource") static let expirationWarningNotificationID = "altstore-expiration-warning" + + static let whitelistedSideloadingBundleIDs: Set = ["science.xnu.undecimus"] } class AppManager diff --git a/AltStore/My Apps/MyAppsViewController.swift b/AltStore/My Apps/MyAppsViewController.swift index edddb94d..991ae1b9 100644 --- a/AltStore/My Apps/MyAppsViewController.swift +++ b/AltStore/My Apps/MyAppsViewController.swift @@ -67,6 +67,12 @@ class MyAppsViewController: UICollectionViewController { super.viewDidLoad() + #if !BETA + // Set leftBarButtonItem to invisible UIBarButtonItem so we can still use it + // to show an activity indicator while sideloading whitelisted apps. + self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil) + #endif + if #available(iOS 13.0, *) { self.navigationItem.leftBarButtonItem?.activityIndicatorView.style = .medium @@ -89,10 +95,6 @@ class MyAppsViewController: UICollectionViewController self.sideloadingProgressView.progressTintColor = .altPrimary self.sideloadingProgressView.progress = 0 - #if !BETA - self.navigationItem.leftBarButtonItem = nil - #endif - if let navigationBar = self.navigationController?.navigationBar { navigationBar.addSubview(self.sideloadingProgressView) @@ -646,7 +648,7 @@ private extension MyAppsViewController self.present(alertController, animated: true, completion: nil) } - func installApp(at fileURL: URL, completion: @escaping (Result) -> Void) + func sideloadApp(at fileURL: URL, completion: @escaping (Result) -> Void) { self.navigationItem.leftBarButtonItem?.isIndicatingActivity = true @@ -661,6 +663,10 @@ private extension MyAppsViewController guard let application = ALTApplication(fileURL: unzippedApplicationURL) else { throw OperationError.invalidApp } + #if !BETA + guard AppManager.whitelistedSideloadingBundleIDs.contains(application.bundleIdentifier) else { throw OperationError.sideloadingAppNotSupported(application) } + #endif + self.sideloadingProgress = AppManager.shared.install(application, presentingViewController: self) { (result) in try? FileManager.default.removeItem(at: temporaryDirectory) @@ -696,8 +702,27 @@ private extension MyAppsViewController DispatchQueue.main.async { self.navigationItem.leftBarButtonItem?.isIndicatingActivity = false - let toastView = ToastView(error: error) - toastView.show(in: self) + if let localizedError = error as? OperationError, case OperationError.sideloadingAppNotSupported = localizedError + { + let message = NSLocalizedString(""" + Sideloading apps is in beta, and is currently limited to a small number of apps. This restriction is temporary, and you will be able to sideload any app once the feature is finished. + + In the meantime, you can help us beta test sideloading apps by becoming a Patron. + """, comment: "") + + let alertController = UIAlertController(title: localizedError.localizedDescription, message: message, preferredStyle: .alert) + alertController.addAction(.cancel) + alertController.addAction(UIAlertAction(title: NSLocalizedString("Become a Patron", comment: ""), style: .default, handler: { (action) in + NotificationCenter.default.post(name: AppDelegate.openPatreonSettingsDeepLinkNotification, object: nil) + })) + + self.present(alertController, animated: true, completion: nil) + } + else + { + let toastView = ToastView(error: error) + toastView.show(in: self) + } } completion(.failure(error)) @@ -764,7 +789,8 @@ private extension MyAppsViewController @objc func importApp(_ notification: Notification) { - #if BETA + // Make sure left UIBarButtonItem has been set. + self.loadViewIfNeeded() guard let fileURL = notification.userInfo?[AppDelegate.importAppDeepLinkURLKey] as? URL else { return } guard self.presentedViewController == nil else { return } @@ -781,10 +807,12 @@ private extension MyAppsViewController } } + #if BETA + self.presentSideloadingAlert { (shouldContinue) in if shouldContinue { - self.installApp(at: fileURL) { (result) in + self.sideloadApp(at: fileURL) { (result) in finish() } } @@ -794,6 +822,12 @@ private extension MyAppsViewController } } + #else + + self.sideloadApp(at: fileURL) { (result) in + finish() + } + #endif } } @@ -1034,7 +1068,7 @@ extension MyAppsViewController: UIDocumentPickerDelegate { guard let fileURL = urls.first else { return } - self.installApp(at: fileURL) { (result) in + self.sideloadApp(at: fileURL) { (result) in print("Sideloaded app at \(fileURL) with result:", result) } } diff --git a/AltStore/Operations/OperationError.swift b/AltStore/Operations/OperationError.swift index 5637006d..998d7b20 100644 --- a/AltStore/Operations/OperationError.swift +++ b/AltStore/Operations/OperationError.swift @@ -24,6 +24,7 @@ enum OperationError: LocalizedError case invalidParameters case iOSVersionNotSupported(ALTApplication) + case sideloadingAppNotSupported(ALTApplication) case maximumAppIDLimitReached(application: ALTApplication, requiredAppIDs: Int, availableAppIDs: Int, nextExpirationDate: Date) case noSources @@ -51,6 +52,10 @@ enum OperationError: LocalizedError let localizedDescription = String(format: NSLocalizedString("%@ requires %@.", comment: ""), name, version) return localizedDescription + case .sideloadingAppNotSupported(let app): + let localizedDescription = String(format: NSLocalizedString("Sideloading “%@” Not Supported", comment: ""), app.name) + return localizedDescription + case .maximumAppIDLimitReached: return NSLocalizedString("Cannot register more than 10 App IDs.", comment: "") } }