Skip to content

Commit 175a4e5

Browse files
committed
added resign option in my apps screen
1 parent 722eb00 commit 175a4e5

3 files changed

Lines changed: 91 additions & 4 deletions

File tree

AltStore/Managing Apps/AppManager.swift

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -923,6 +923,34 @@ extension AppManager
923923
}
924924
}
925925

926+
@discardableResult
927+
func resign(_ installedApp: InstalledApp, presentingViewController: UIViewController?, completionHandler: @escaping (Result<InstalledApp, Error>) -> Void) -> RefreshGroup
928+
{
929+
let group = RefreshGroup()
930+
group.completionHandler = { (results) in
931+
do
932+
{
933+
guard let result = results.values.first else { throw group.context.error ?? OperationError.unknown() }
934+
let installedApp = try result.get()
935+
completionHandler(.success(installedApp))
936+
}
937+
catch
938+
{
939+
completionHandler(.failure(error))
940+
}
941+
}
942+
943+
Task {
944+
do {
945+
try await self.perform([.resign(installedApp)], presentingViewController: presentingViewController, group: group)
946+
} catch {
947+
completionHandler(.failure(error))
948+
}
949+
}
950+
951+
return group
952+
}
953+
926954
func backup(_ installedApp: InstalledApp, presentingViewController: UIViewController?, completionHandler: @escaping (Result<InstalledApp, Error>) -> Void)
927955
{
928956
let group = RefreshGroup()
@@ -1103,13 +1131,15 @@ private extension AppManager
11031131
case deactivate(InstalledApp)
11041132
case backup(InstalledApp)
11051133
case restore(InstalledApp)
1134+
case resign(InstalledApp)
11061135

11071136
var app: AppProtocol {
11081137
switch self
11091138
{
11101139
case .install(let app), .update(let app), .refresh(let app as AppProtocol),
11111140
.activate(let app as AppProtocol), .deactivate(let app as AppProtocol),
1112-
.backup(let app as AppProtocol), .restore(let app as AppProtocol):
1141+
.backup(let app as AppProtocol), .restore(let app as AppProtocol),
1142+
.resign(let app as AppProtocol):
11131143
return app
11141144
}
11151145
}
@@ -1139,6 +1169,7 @@ private extension AppManager
11391169
case .deactivate: return .deactivate
11401170
case .backup: return .backup
11411171
case .restore: return .restore
1172+
case .resign: return .install
11421173
}
11431174
}
11441175
}
@@ -1208,6 +1239,12 @@ private extension AppManager
12081239
}
12091240
progress?.addChild(updateProgress, withPendingUnitCount: 80)
12101241

1242+
case .resign(let app):
1243+
let resignProgress = self._install(app, operation: operation, group: group, reviewPermissions: .none) { (result) in
1244+
self.finish(operation, result: result, group: group, progress: progress)
1245+
}
1246+
progress?.addChild(resignProgress, withPendingUnitCount: 80)
1247+
12111248
case .activate(let app) where UserDefaults.standard.isLegacyDeactivationSupported: fallthrough
12121249
case .refresh(let app):
12131250
let refreshProgress = self._refresh(app, operation: operation, group: group) { (result) in
@@ -1295,7 +1332,11 @@ private extension AppManager
12951332

12961333
if let installedApp = app as? InstalledApp
12971334
{
1298-
if let storeApp = installedApp.storeApp, !FileManager.default.fileExists(atPath: installedApp.fileURL.path)
1335+
if case .resign = appOperation {
1336+
// For resign, we MUST use the cached app bundle and not download from the store/web
1337+
downloadingApp = installedApp
1338+
}
1339+
else if let storeApp = installedApp.storeApp, !FileManager.default.fileExists(atPath: installedApp.fileURL.path)
12991340
{
13001341
// Cached app has been deleted, so we need to redownload it.
13011342
downloadingApp = storeApp
@@ -2206,7 +2247,7 @@ private extension AppManager
22062247
switch operation
22072248
{
22082249
case .install, .update: return self.installationProgress[bundleID]
2209-
case .refresh, .activate, .deactivate, .backup, .restore: return self.refreshProgress[bundleID]
2250+
case .refresh, .activate, .deactivate, .backup, .restore, .resign: return self.refreshProgress[bundleID]
22102251
}
22112252
}
22122253

@@ -2221,7 +2262,7 @@ private extension AppManager
22212262
switch operation
22222263
{
22232264
case .install, .update: self.installationProgress[bundleID] = progress
2224-
case .refresh, .activate, .deactivate, .backup, .restore: self.refreshProgress[bundleID] = progress
2265+
case .refresh, .activate, .deactivate, .backup, .restore, .resign: self.refreshProgress[bundleID] = progress
22252266
}
22262267
}
22272268
}

AltStore/My Apps/MyAppsViewController.swift

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1165,6 +1165,34 @@ private extension MyAppsViewController
11651165
}
11661166
}
11671167

1168+
func resign(_ installedApp: InstalledApp)
1169+
{
1170+
guard isMinimuxerReady else { return }
1171+
1172+
let previousProgress = AppManager.shared.refreshProgress(for: installedApp)
1173+
guard previousProgress == nil else {
1174+
previousProgress?.cancel()
1175+
return
1176+
}
1177+
1178+
AppManager.shared.resign(installedApp, presentingViewController: self) { (result) in
1179+
DispatchQueue.main.async {
1180+
self.collectionView.reloadSections([Section.activeApps.rawValue, Section.inactiveApps.rawValue])
1181+
}
1182+
1183+
switch result
1184+
{
1185+
case .failure(let error):
1186+
print("Failed to resign app:", error)
1187+
DispatchQueue.main.async {
1188+
ToastView(error: error, opensLog: true).show(in: self)
1189+
}
1190+
case .success(let app):
1191+
print("Successfully resigned app:", app.name)
1192+
}
1193+
}
1194+
}
1195+
11681196
func activate(_ installedApp: InstalledApp)
11691197
{
11701198
guard isMinimuxerReady else { return }
@@ -1786,6 +1814,10 @@ extension MyAppsViewController
17861814
self.refresh(installedApp)
17871815
}
17881816

1817+
let resignAction = UIAction(title: NSLocalizedString("Resign", comment: ""), image: UIImage(systemName: "signature")) { (action) in
1818+
self.resign(installedApp)
1819+
}
1820+
17891821
let activateAction = UIAction(title: NSLocalizedString("Activate", comment: ""), image: UIImage(systemName: "checkmark.circle")) { (action) in
17901822
self.activate(installedApp)
17911823
}
@@ -1852,10 +1884,12 @@ extension MyAppsViewController
18521884
{
18531885
actions.append(openMenu)
18541886
actions.append(refreshAction)
1887+
actions.append(resignAction)
18551888
}
18561889
else
18571890
{
18581891
actions.append(activateAction)
1892+
actions.append(resignAction)
18591893
}
18601894

18611895
if installedApp.isActive
@@ -1948,6 +1982,7 @@ extension MyAppsViewController
19481982
let orderedActions = [
19491983
openMenu,
19501984
refreshAction,
1985+
resignAction,
19511986
activateAction,
19521987
jitAction,
19531988
changeIconMenu,

AltStore/Operations/InstallAppOperation.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,17 @@ final class InstallAppOperation: ResultOperation<InstalledApp>
246246
try installIPA(installedApp.bundleIdentifier)
247247
installing = false
248248
installedApp.refreshedDate = Date()
249+
250+
if let resignedAppURL = self.context.resignedApp?.fileURL {
251+
let cachedAppURL = InstalledApp.fileURL(for: installedApp)
252+
do {
253+
try FileManager.default.copyItem(at: resignedAppURL, to: cachedAppURL, shouldReplace: true)
254+
self.debugLog("Successfully overwrote cached app with resigned app at \(cachedAppURL.path)")
255+
} catch {
256+
self.debugLog("Failed to overwrite cached app with resigned app: \(error)")
257+
}
258+
}
259+
249260
self.finish(.success(installedApp))
250261
} catch let error {
251262
installing = false

0 commit comments

Comments
 (0)