Adds altstore://source?url=[link] deep link to add sources

This commit is contained in:
Riley Testut
2020-08-28 12:15:15 -07:00
parent 4c3d33efdc
commit 70a475ff5f
3 changed files with 169 additions and 21 deletions

View File

@@ -54,11 +54,13 @@ extension AppDelegate
{
static let openPatreonSettingsDeepLinkNotification = Notification.Name("com.rileytestut.AltStore.OpenPatreonSettingsDeepLinkNotification")
static let importAppDeepLinkNotification = Notification.Name("com.rileytestut.AltStore.ImportAppDeepLinkNotification")
static let addSourceDeepLinkNotification = Notification.Name("com.rileytestut.AltStore.AddSourceDeepLinkNotification")
static let appBackupDidFinish = Notification.Name("com.rileytestut.AltStore.AppBackupDidFinish")
static let importAppDeepLinkURLKey = "fileURL"
static let appBackupResultKey = "result"
static let addSourceDeepLinkURLKey = "sourceURL"
}
@UIApplicationMain
@@ -183,6 +185,16 @@ private extension AppDelegate
}
return true
case "source":
let queryItems = components.queryItems?.reduce(into: [String: String]()) { $0[$1.name.lowercased()] = $1.value } ?? [:]
guard let sourceURLString = queryItems["url"], let sourceURL = URL(string: sourceURLString) else { return false }
DispatchQueue.main.async {
NotificationCenter.default.post(name: AppDelegate.addSourceDeepLinkNotification, object: nil, userInfo: [AppDelegate.addSourceDeepLinkURLKey: sourceURL])
}
return true
default: return false
}

View File

@@ -13,6 +13,13 @@ import Roxas
class SourcesViewController: UICollectionViewController
{
var deepLinkSourceURL: URL? {
didSet {
guard let sourceURL = self.deepLinkSourceURL else { return }
self.addSource(url: sourceURL)
}
}
private lazy var dataSource = self.makeDataSource()
override func viewDidLoad()
@@ -21,6 +28,27 @@ class SourcesViewController: UICollectionViewController
self.collectionView.dataSource = self.dataSource
}
override func viewWillAppear(_ animated: Bool)
{
super.viewWillAppear(animated)
if self.deepLinkSourceURL != nil
{
self.navigationItem.leftBarButtonItem?.isIndicatingActivity = true
}
}
override func viewDidAppear(_ animated: Bool)
{
super.viewDidAppear(animated)
if let sourceURL = self.deepLinkSourceURL
{
self.addSource(url: sourceURL)
self.deepLinkSourceURL = nil
}
}
}
private extension SourcesViewController
@@ -67,26 +95,6 @@ private extension SourcesViewController
{
@IBAction func addSource()
{
func addSource(url: URL)
{
AppManager.shared.fetchSource(sourceURL: url) { (result) in
do
{
let source = try result.get()
try source.managedObjectContext?.save()
}
catch let error as NSError
{
let error = error.withLocalizedFailure(NSLocalizedString("Could not add source.", comment: ""))
DispatchQueue.main.async {
let toastView = ToastView(error: error)
toastView.show(in: self)
}
}
}
}
let alertController = UIAlertController(title: NSLocalizedString("Add Source", comment: ""), message: nil, preferredStyle: .alert)
alertController.addTextField { (textField) in
textField.placeholder = "https://apps.altstore.io"
@@ -95,14 +103,77 @@ private extension SourcesViewController
alertController.addAction(.cancel)
alertController.addAction(UIAlertAction(title: NSLocalizedString("Add", comment: ""), style: .default) { (action) in
guard let text = alertController.textFields![0].text, let sourceURL = URL(string: text) else { return }
addSource(url: sourceURL)
self.addSource(url: sourceURL)
})
self.present(alertController, animated: true, completion: nil)
}
func addSource(url: URL)
{
guard self.view.window != nil else { return }
self.navigationItem.leftBarButtonItem?.isIndicatingActivity = true
func finish(error: Error?)
{
DispatchQueue.main.async {
if let error = error
{
self.present(error)
}
self.navigationItem.leftBarButtonItem?.isIndicatingActivity = false
}
}
AppManager.shared.fetchSource(sourceURL: url) { (result) in
do
{
let source = try result.get()
let sourceName = source.name
let managedObjectContext = source.managedObjectContext
DispatchQueue.main.async {
let alertController = UIAlertController(title: String(format: NSLocalizedString("Would you like to add the source “%@”?", comment: ""), sourceName),
message: NSLocalizedString("Sources control what apps appear in AltStore. Make sure to only add sources that you trust.", comment: ""), preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: UIAlertAction.cancel.title, style: UIAlertAction.cancel.style) { _ in
finish(error: nil)
})
alertController.addAction(UIAlertAction(title: UIAlertAction.ok.title, style: UIAlertAction.ok.style) { _ in
managedObjectContext?.perform {
do
{
try managedObjectContext?.save()
finish(error: nil)
}
catch
{
finish(error: error)
}
}
})
self.present(alertController, animated: true, completion: nil)
}
}
catch
{
finish(error: error)
}
}
}
func present(_ error: Error)
{
if let transitionCoordinator = self.transitionCoordinator
{
transitionCoordinator.animate(alongsideTransition: nil) { _ in
self.present(error)
}
return
}
let nsError = error as NSError
let message = nsError.userInfo[NSDebugDescriptionErrorKey] as? String ?? nsError.localizedRecoverySuggestion

View File

@@ -21,12 +21,52 @@ extension TabBarController
class TabBarController: UITabBarController
{
private var initialSegue: (identifier: String, sender: Any?)?
private var _viewDidAppear = false
required init?(coder aDecoder: NSCoder)
{
super.init(coder: aDecoder)
NotificationCenter.default.addObserver(self, selector: #selector(TabBarController.openPatreonSettings(_:)), name: AppDelegate.openPatreonSettingsDeepLinkNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(TabBarController.importApp(_:)), name: AppDelegate.importAppDeepLinkNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(TabBarController.presentSources(_:)), name: AppDelegate.addSourceDeepLinkNotification, object: nil)
}
override func viewDidAppear(_ animated: Bool)
{
super.viewDidAppear(animated)
_viewDidAppear = true
if let (identifier, sender) = self.initialSegue
{
self.initialSegue = nil
self.performSegue(withIdentifier: identifier, sender: sender)
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?)
{
guard segue.identifier == "presentSources",
let notification = sender as? Notification,
let sourceURL = notification.userInfo?[AppDelegate.addSourceDeepLinkURLKey] as? URL
else { return }
let navigationController = segue.destination as! UINavigationController
let sourcesViewController = navigationController.viewControllers.first as! SourcesViewController
sourcesViewController.deepLinkSourceURL = sourceURL
}
override func performSegue(withIdentifier identifier: String, sender: Any?)
{
guard _viewDidAppear else {
self.initialSegue = (identifier, sender)
return
}
super.performSegue(withIdentifier: identifier, sender: sender)
}
}
@@ -34,6 +74,31 @@ extension TabBarController
{
@objc func presentSources(_ sender: Any)
{
if let presentedViewController = self.presentedViewController
{
if let navigationController = presentedViewController as? UINavigationController,
let sourcesViewController = navigationController.viewControllers.first as? SourcesViewController
{
if let notification = (sender as? Notification),
let sourceURL = notification.userInfo?[AppDelegate.addSourceDeepLinkURLKey] as? URL
{
sourcesViewController.deepLinkSourceURL = sourceURL
}
else
{
// Don't dismiss SourcesViewController if it's already presented.
}
}
else
{
presentedViewController.dismiss(animated: true) {
self.presentSources(sender)
}
}
return
}
self.performSegue(withIdentifier: "presentSources", sender: sender)
}
}