[AltBackup+Schemes]: Fixes for URL schemes throughout both AltBackup and SideStore apps

This commit is contained in:
Magesh K
2024-12-14 05:51:11 +05:30
parent 976f4e1041
commit f542a52bda
10 changed files with 62 additions and 44 deletions

View File

@@ -88,14 +88,25 @@ private extension AppDelegate
@objc func operationDidFinish(_ notification: Notification)
{
defer { self.currentBackupReturnURL = nil }
defer {
self.currentBackupReturnURL = nil
}
// TODO: @mahee96: This doesn't account cases where backup is too long and user switched to other apps
// The check for self.currentBackupReturnURL when backup/restore was still in progress but app switched
// between FG/BG is improper, since it will ignore(eat up) the response(success/failure) to parent
//
// This leaves the backup/restore to show dummy animation forever
guard
let returnURL = self.currentBackupReturnURL,
let result = notification.userInfo?[AppDelegate.operationResultKey] as? Result<Void, Error>
else { return }
else {
return // This is bad (Needs fixing - never eat up response like this unless there is no context to post response to!)
}
guard var components = URLComponents(url: returnURL, resolvingAgainstBaseURL: false) else { return }
guard var components = URLComponents(url: returnURL, resolvingAgainstBaseURL: false) else {
return // This is ASSERTION Failure, ie RETURN URL needs to be valid. So ignoring (eating up) response is not the solution
}
switch result
{
@@ -112,6 +123,7 @@ private extension AppDelegate
guard let responseURL = components.url else { return }
DispatchQueue.main.async {
// Response to the caller/parent app is posted here (url is provided by caller in incoming query params)
UIApplication.shared.open(responseURL, options: [:]) { (success) in
print("Sent response to app with success:", success)
}

View File

@@ -131,7 +131,9 @@ class BackupController: NSObject
guard
let altstoreAppGroup = Bundle.main.altstoreAppGroup,
let sharedDirectoryURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: altstoreAppGroup)
else { throw BackupError(.appGroupNotFound(nil), description: NSLocalizedString("Unable to create backup directory.", comment: "")) }
else {
throw BackupError(.appGroupNotFound(nil), description: NSLocalizedString("Unable to create backup directory.", comment: ""))
}
let backupsDirectory = sharedDirectoryURL.appendingPathComponent("Backups")

View File

@@ -28,10 +28,10 @@
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>AltBackup General</string>
<string>SideBackup General</string>
<key>CFBundleURLSchemes</key>
<array>
<string>altbackup</string>
<string>sidebackup</string>
</array>
</dict>
</array>

View File

@@ -82,23 +82,25 @@ class ViewController: UIViewController
self.activityIndicatorView.color = .altstoreText
self.activityIndicatorView.startAnimating()
#if DEBUG
let button1 = UIButton(type: .system)
button1.setTitle("Backup", for: .normal)
button1.setTitleColor(.white, for: .normal)
button1.titleLabel?.font = UIFont.preferredFont(forTextStyle: .body)
button1.addTarget(self, action: #selector(ViewController.backup), for: .primaryActionTriggered)
let button2 = UIButton(type: .system)
button2.setTitle("Restore", for: .normal)
button2.setTitleColor(.white, for: .normal)
button2.titleLabel?.font = UIFont.preferredFont(forTextStyle: .body)
button2.addTarget(self, action: #selector(ViewController.restore), for: .primaryActionTriggered)
let arrangedSubviews = [self.textLabel!, self.detailTextLabel!, self.activityIndicatorView!, button1, button2]
#else
// TODO: @mahee96: Disabled this buttons which were present for debugging purpose.
// Can find something useful for these later, but these are not required by this backup/restore app
// #if DEBUG
// let button1 = UIButton(type: .system)
// button1.setTitle("Backup", for: .normal)
// button1.setTitleColor(.white, for: .normal)
// button1.titleLabel?.font = UIFont.preferredFont(forTextStyle: .body)
// button1.addTarget(self, action: #selector(ViewController.backup), for: .primaryActionTriggered)
//
// let button2 = UIButton(type: .system)
// button2.setTitle("Restore", for: .normal)
// button2.setTitleColor(.white, for: .normal)
// button2.titleLabel?.font = UIFont.preferredFont(forTextStyle: .body)
// button2.addTarget(self, action: #selector(ViewController.restore), for: .primaryActionTriggered)
//
// let arrangedSubviews = [self.textLabel!, self.detailTextLabel!, self.activityIndicatorView!, button1, button2]
// #else
let arrangedSubviews = [self.textLabel!, self.detailTextLabel!, self.activityIndicatorView!]
#endif
// #endif
let stackView = UIStackView(arrangedSubviews: arrangedSubviews)
stackView.translatesAutoresizingMaskIntoConstraints = false
@@ -155,7 +157,8 @@ private extension ViewController
self.textLabel.text = NSLocalizedString("Restoring app data…", comment: "")
self.detailTextLabel.isHidden = true
self.activityIndicatorView.startAnimating()
// TODO: @mahee96: This is pointless since, app going in bg/fg should still report its last operation properly
case .none:
self.textLabel.text = String(format: NSLocalizedString("%@ is inactive.", comment: ""),
Bundle.main.appName ?? NSLocalizedString("App", comment: ""))
@@ -198,6 +201,9 @@ private extension ViewController
}
}
// TODO: @mahee96: This doesn't account cases where backup is too long and user switched to other apps
// Now the user has lost his progress since current operation was cancelled due to switch between FG and BG
// if this just the reset for enum such that UI stops showing progress circle, then this is fine!
@objc func didEnterBackground(_ notification: Notification)
{
// Reset UI once we've left app (but not before).

View File

@@ -7,7 +7,6 @@
<key>ALTAppGroups</key>
<array>
<string>group.$(APP_GROUP_IDENTIFIER)</string>
<string>group.com.SideStore.SideStore</string>
</array>
<key>ALTDeviceID</key>
<string>00008120-001270DA119B401E</string>
@@ -63,10 +62,9 @@
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>AltStore General</string>
<string>SideStore General</string>
<key>CFBundleURLSchemes</key>
<array>
<string>altstore</string>
<string>sidestore</string>
</array>
</dict>
@@ -74,10 +72,9 @@
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>AltStore Backup</string>
<string>SideStore Backup</string>
<key>CFBundleURLSchemes</key>
<array>
<string>altstore-com.rileytestut.AltStore</string>
<string>sidestore-com.SideStore.SideStore</string>
</array>
</dict>
@@ -91,14 +88,8 @@
</array>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>altstore-com.rileytestut.AltStore</string>
<string>altstore-com.rileytestut.AltStore.Beta</string>
<string>altstore-com.rileytestut.Delta</string>
<string>altstore-com.rileytestut.Delta.Beta</string>
<string>altstore-com.rileytestut.Delta.Lite</string>
<string>altstore-com.rileytestut.Delta.Lite.Beta</string>
<string>altstore-com.rileytestut.Clip</string>
<string>altstore-com.rileytestut.Clip.Beta</string>
<string>sidestore-com.SideStore.SideStore</string>
<string>sidestore-com.SideStore.SideStore.Beta</string>
</array>
<key>LSRequiresIPhoneOS</key>
<true/>
@@ -122,7 +113,7 @@
</array>
<key>OSLogPreferences</key>
<dict>
<key>com.rileytestut.AltStore</key>
<key>com.SideStore.SideStore</key>
<dict>
<key>AltJIT</key>
<dict>

View File

@@ -28,8 +28,8 @@ extension AppManager
static let didRemoveSourceNotification = Notification.Name("io.sidestore.AppManager.didRemoveSource")
static let willInstallAppFromNewSourceNotification = Notification.Name("io.sidestore.AppManager.willInstallAppFromNewSource")
static let expirationWarningNotificationID = "altstore-expiration-warning"
static let enableJITResultNotificationID = "altstore-enable-jit"
static let expirationWarningNotificationID = "sidestore-expiration-warning"
static let enableJITResultNotificationID = "sidestore-enable-jit"
}
@available(iOS 13, *)

View File

@@ -162,7 +162,9 @@ private extension BackupAppOperation
self?.applicationWillReturnObserver.map { NotificationCenter.default.removeObserver($0) }
}
guard let self = self, !self.isFinished else { return }
guard let self = self, !self.isFinished else {
return
}
self.timeoutTimer = Timer.scheduledTimer(withTimeInterval: 5, repeats: false) { [weak self] (timer) in
// Final delay to ensure we don't prematurely return failure

View File

@@ -11,7 +11,9 @@ import Foundation
public extension FileManager
{
var altstoreSharedDirectory: URL? {
guard let appGroup = Bundle.main.altstoreAppGroup else { return nil }
guard let appGroup = Bundle.main.altstoreAppGroup else {
return nil
}
let sharedDirectoryURL = self.containerURL(forSecurityApplicationGroupIdentifier: appGroup)
return sharedDirectoryURL

View File

@@ -343,14 +343,18 @@ public extension InstalledApp
public extension InstalledApp
{
// TODO: @mahee96: Do NOT hardcode app's url scheme prefixes as in here
// Need to get it dynamically from the Info.plist of other means
var openAppURL: URL {
let openAppURL = URL(string: "altstore-" + self.bundleIdentifier + "://")!
let openAppURL = URL(string: "sidestore-" + self.bundleIdentifier + "://")!
return openAppURL
}
// TODO: @mahee96: Do NOT hardcode app's url scheme prefixes as in here
// Need to get it dynamically from the Info.plist of other means
class func openAppURL(for app: AppProtocol) -> URL
{
let openAppURL = URL(string: "altstore-" + app.bundleIdentifier + "://")!
let openAppURL = URL(string: "sidestore-" + app.bundleIdentifier + "://")!
return openAppURL
}

View File

@@ -5,7 +5,6 @@
<key>ALTAppGroups</key>
<array>
<string>group.$(APP_GROUP_IDENTIFIER)</string>
<string>group.com.SideStore.SideStore</string>
</array>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>