[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) @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 guard
let returnURL = self.currentBackupReturnURL, let returnURL = self.currentBackupReturnURL,
let result = notification.userInfo?[AppDelegate.operationResultKey] as? Result<Void, Error> 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 switch result
{ {
@@ -112,6 +123,7 @@ private extension AppDelegate
guard let responseURL = components.url else { return } guard let responseURL = components.url else { return }
DispatchQueue.main.async { 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 UIApplication.shared.open(responseURL, options: [:]) { (success) in
print("Sent response to app with success:", success) print("Sent response to app with success:", success)
} }

View File

@@ -131,7 +131,9 @@ class BackupController: NSObject
guard guard
let altstoreAppGroup = Bundle.main.altstoreAppGroup, let altstoreAppGroup = Bundle.main.altstoreAppGroup,
let sharedDirectoryURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: 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") let backupsDirectory = sharedDirectoryURL.appendingPathComponent("Backups")

View File

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

View File

@@ -82,23 +82,25 @@ class ViewController: UIViewController
self.activityIndicatorView.color = .altstoreText self.activityIndicatorView.color = .altstoreText
self.activityIndicatorView.startAnimating() self.activityIndicatorView.startAnimating()
#if DEBUG // TODO: @mahee96: Disabled this buttons which were present for debugging purpose.
let button1 = UIButton(type: .system) // Can find something useful for these later, but these are not required by this backup/restore app
button1.setTitle("Backup", for: .normal) // #if DEBUG
button1.setTitleColor(.white, for: .normal) // let button1 = UIButton(type: .system)
button1.titleLabel?.font = UIFont.preferredFont(forTextStyle: .body) // button1.setTitle("Backup", for: .normal)
button1.addTarget(self, action: #selector(ViewController.backup), for: .primaryActionTriggered) // button1.setTitleColor(.white, for: .normal)
// button1.titleLabel?.font = UIFont.preferredFont(forTextStyle: .body)
let button2 = UIButton(type: .system) // button1.addTarget(self, action: #selector(ViewController.backup), for: .primaryActionTriggered)
button2.setTitle("Restore", for: .normal) //
button2.setTitleColor(.white, for: .normal) // let button2 = UIButton(type: .system)
button2.titleLabel?.font = UIFont.preferredFont(forTextStyle: .body) // button2.setTitle("Restore", for: .normal)
button2.addTarget(self, action: #selector(ViewController.restore), for: .primaryActionTriggered) // button2.setTitleColor(.white, for: .normal)
// button2.titleLabel?.font = UIFont.preferredFont(forTextStyle: .body)
let arrangedSubviews = [self.textLabel!, self.detailTextLabel!, self.activityIndicatorView!, button1, button2] // button2.addTarget(self, action: #selector(ViewController.restore), for: .primaryActionTriggered)
#else //
// let arrangedSubviews = [self.textLabel!, self.detailTextLabel!, self.activityIndicatorView!, button1, button2]
// #else
let arrangedSubviews = [self.textLabel!, self.detailTextLabel!, self.activityIndicatorView!] let arrangedSubviews = [self.textLabel!, self.detailTextLabel!, self.activityIndicatorView!]
#endif // #endif
let stackView = UIStackView(arrangedSubviews: arrangedSubviews) let stackView = UIStackView(arrangedSubviews: arrangedSubviews)
stackView.translatesAutoresizingMaskIntoConstraints = false stackView.translatesAutoresizingMaskIntoConstraints = false
@@ -155,7 +157,8 @@ private extension ViewController
self.textLabel.text = NSLocalizedString("Restoring app data…", comment: "") self.textLabel.text = NSLocalizedString("Restoring app data…", comment: "")
self.detailTextLabel.isHidden = true self.detailTextLabel.isHidden = true
self.activityIndicatorView.startAnimating() self.activityIndicatorView.startAnimating()
// TODO: @mahee96: This is pointless since, app going in bg/fg should still report its last operation properly
case .none: case .none:
self.textLabel.text = String(format: NSLocalizedString("%@ is inactive.", comment: ""), self.textLabel.text = String(format: NSLocalizedString("%@ is inactive.", comment: ""),
Bundle.main.appName ?? NSLocalizedString("App", 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) @objc func didEnterBackground(_ notification: Notification)
{ {
// Reset UI once we've left app (but not before). // Reset UI once we've left app (but not before).

View File

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

View File

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

View File

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

View File

@@ -11,7 +11,9 @@ import Foundation
public extension FileManager public extension FileManager
{ {
var altstoreSharedDirectory: URL? { 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) let sharedDirectoryURL = self.containerURL(forSecurityApplicationGroupIdentifier: appGroup)
return sharedDirectoryURL return sharedDirectoryURL

View File

@@ -343,14 +343,18 @@ public extension InstalledApp
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 { var openAppURL: URL {
let openAppURL = URL(string: "altstore-" + self.bundleIdentifier + "://")! let openAppURL = URL(string: "sidestore-" + self.bundleIdentifier + "://")!
return openAppURL 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 class func openAppURL(for app: AppProtocol) -> URL
{ {
let openAppURL = URL(string: "altstore-" + app.bundleIdentifier + "://")! let openAppURL = URL(string: "sidestore-" + app.bundleIdentifier + "://")!
return openAppURL return openAppURL
} }

View File

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