mirror of
https://github.com/SideStore/SideStore.git
synced 2026-02-09 06:43:25 +01:00
[Refresh]: Remove install stuffs from refresh since in refresh should only renew provisioning profiles (#846)
This commit is contained in:
@@ -1146,27 +1146,28 @@ private extension AppManager
|
|||||||
case .activate(let app) where UserDefaults.standard.isLegacyDeactivationSupported: fallthrough
|
case .activate(let app) where UserDefaults.standard.isLegacyDeactivationSupported: fallthrough
|
||||||
case .refresh(let app):
|
case .refresh(let app):
|
||||||
// Check if backup app is installed in place of real app.
|
// Check if backup app is installed in place of real app.
|
||||||
let uti = UTTypeCopyDeclaration(app.installedBackupAppUTI as CFString)?.takeRetainedValue() as NSDictionary?
|
// let altBackupUti = UTTypeCopyDeclaration(app.installedBackupAppUTI as CFString)?.takeRetainedValue() as NSDictionary?
|
||||||
|
|
||||||
if app.certificateSerialNumber != group.context.certificate?.serialNumber ||
|
// if app.certificateSerialNumber != group.context.certificate?.serialNumber ||
|
||||||
uti != nil ||
|
// altBackupUti != nil || // why would altbackup requires reinstall? it shouldn't cause we are just renewing profiles
|
||||||
app.needsResign ||
|
// app.needsResign || // why would an app require resign during refresh? it shouldn't!
|
||||||
// We need to reinstall ourselves on refresh to ensure the new provisioning profile is used
|
// We need to reinstall ourselves on refresh to ensure the new provisioning profile is used
|
||||||
app.bundleIdentifier == StoreApp.altstoreAppID
|
// => mahee96: jkcoxson confirmed misagent manages profiles independently without requiring lockdownd or installd intervention, so sidestore profile renewal shouldn't require reinstall
|
||||||
{
|
// app.bundleIdentifier == StoreApp.altstoreAppID
|
||||||
|
// {
|
||||||
// Resign app instead of just refreshing profiles because either:
|
// Resign app instead of just refreshing profiles because either:
|
||||||
// * Refreshing using different certificate
|
// * Refreshing using different certificate // when can this happen?, lets assume, refreshing with different certificate, why not just ask user to re-install manually? (probably we need re-install button)
|
||||||
// * Backup app is still installed
|
// * Backup app is still installed // but why? I mean the AltBackup was put in place for a reason? ie during refresh just renew appIDs don't care about the app itself.
|
||||||
// * App explicitly needs resigning
|
// * App explicitly needs resigning // when can this happen?
|
||||||
// * Device is jailbroken and using AltDaemon on iOS 14.0 or later (b/c refreshing with provisioning profiles is broken)
|
// * Device is jailbroken and using AltDaemon on iOS 14.0 or later (b/c refreshing with provisioning profiles is broken)
|
||||||
|
|
||||||
let installProgress = self._install(app, operation: operation, group: group) { (result) in
|
// let installProgress = self._install(app, operation: operation, group: group) { (result) in
|
||||||
self.finish(operation, result: result, group: group, progress: progress)
|
// self.finish(operation, result: result, group: group, progress: progress)
|
||||||
}
|
// }
|
||||||
progress?.addChild(installProgress, withPendingUnitCount: 80)
|
// progress?.addChild(installProgress, withPendingUnitCount: 80)
|
||||||
}
|
// }
|
||||||
else
|
// else
|
||||||
{
|
// {
|
||||||
// Refreshing with same certificate as last time, and backup app isn't still installed,
|
// Refreshing with same certificate as last time, and backup app isn't still installed,
|
||||||
// so we can just refresh provisioning profiles.
|
// so we can just refresh provisioning profiles.
|
||||||
|
|
||||||
@@ -1174,7 +1175,7 @@ private extension AppManager
|
|||||||
self.finish(operation, result: result, group: group, progress: progress)
|
self.finish(operation, result: result, group: group, progress: progress)
|
||||||
}
|
}
|
||||||
progress?.addChild(refreshProgress, withPendingUnitCount: 80)
|
progress?.addChild(refreshProgress, withPendingUnitCount: 80)
|
||||||
}
|
// }
|
||||||
|
|
||||||
case .activate(let app):
|
case .activate(let app):
|
||||||
let activateProgress = self._activate(app, operation: operation, group: group) { (result) in
|
let activateProgress = self._activate(app, operation: operation, group: group) { (result) in
|
||||||
@@ -1371,7 +1372,7 @@ private extension AppManager
|
|||||||
|
|
||||||
|
|
||||||
/* Fetch Provisioning Profiles */
|
/* Fetch Provisioning Profiles */
|
||||||
let fetchProvisioningProfilesOperation = FetchProvisioningProfilesOperation(context: context)
|
let fetchProvisioningProfilesOperation = FetchProvisioningProfilesInstallOperation(context: context)
|
||||||
fetchProvisioningProfilesOperation.additionalEntitlements = additionalEntitlements
|
fetchProvisioningProfilesOperation.additionalEntitlements = additionalEntitlements
|
||||||
fetchProvisioningProfilesOperation.resultHandler = { (result) in
|
fetchProvisioningProfilesOperation.resultHandler = { (result) in
|
||||||
switch result
|
switch result
|
||||||
@@ -1657,26 +1658,27 @@ private extension AppManager
|
|||||||
let context = AppOperationContext(bundleIdentifier: app.bundleIdentifier, authenticatedContext: group.context)
|
let context = AppOperationContext(bundleIdentifier: app.bundleIdentifier, authenticatedContext: group.context)
|
||||||
context.app = ALTApplication(fileURL: app.fileURL)
|
context.app = ALTApplication(fileURL: app.fileURL)
|
||||||
|
|
||||||
//App-Extensions: Ensure DB data and disk state must match
|
// Since this doesn't involve modifying app bundle which will cause re-install, this is safe in refresh path
|
||||||
let dbAppEx: Set<InstalledExtension> = Set(app.appExtensions)
|
//App-Extensions: Ensure DB data and disk state must match
|
||||||
let diskAppEx: Set<ALTApplication> = Set(context.app!.appExtensions)
|
let dbAppEx: Set<InstalledExtension> = Set(app.appExtensions)
|
||||||
let diskAppExNames = diskAppEx.map { $0.bundleIdentifier }
|
let diskAppEx: Set<ALTApplication> = Set(context.app!.appExtensions)
|
||||||
let dbAppExNames = dbAppEx.map{ $0.bundleIdentifier }
|
let diskAppExNames = diskAppEx.map { $0.bundleIdentifier }
|
||||||
let isMatching = Set(dbAppExNames) == Set(diskAppExNames)
|
let dbAppExNames = dbAppEx.map{ $0.bundleIdentifier }
|
||||||
|
let isMatching = Set(dbAppExNames) == Set(diskAppExNames)
|
||||||
|
|
||||||
let validateAppExtensionsOperation = RSTAsyncBlockOperation { op in
|
let validateAppExtensionsOperation = RSTAsyncBlockOperation { op in
|
||||||
|
|
||||||
let errMessage = "AppManager.refresh: App Extensions in DB and Disk are matching: \(isMatching)\n"
|
let errMessage = "AppManager.refresh: App Extensions in DB and Disk are matching: \(isMatching)\n"
|
||||||
+ "AppManager.refresh: dbAppEx: \(dbAppExNames); diskAppEx: \(String(describing: diskAppExNames))\n"
|
+ "AppManager.refresh: dbAppEx: \(dbAppExNames); diskAppEx: \(String(describing: diskAppExNames))\n"
|
||||||
print(errMessage)
|
print(errMessage)
|
||||||
if(!isMatching){
|
if(!isMatching){
|
||||||
completionHandler(.failure(OperationError.refreshAppFailed(message: errMessage)))
|
completionHandler(.failure(OperationError.refreshAppFailed(message: errMessage)))
|
||||||
}
|
}
|
||||||
op.finish()
|
op.finish()
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fetch Provisioning Profiles */
|
/* Fetch Provisioning Profiles */
|
||||||
let fetchProvisioningProfilesOperation = FetchProvisioningProfilesOperation(context: context)
|
let fetchProvisioningProfilesOperation = FetchProvisioningProfilesRefreshOperation(context: context)
|
||||||
fetchProvisioningProfilesOperation.resultHandler = { (result) in
|
fetchProvisioningProfilesOperation.resultHandler = { (result) in
|
||||||
switch result
|
switch result
|
||||||
{
|
{
|
||||||
@@ -1686,7 +1688,7 @@ private extension AppManager
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
progress.addChild(fetchProvisioningProfilesOperation.progress, withPendingUnitCount: 60)
|
progress.addChild(fetchProvisioningProfilesOperation.progress, withPendingUnitCount: 60)
|
||||||
fetchProvisioningProfilesOperation.addDependency(validateAppExtensionsOperation)
|
// fetchProvisioningProfilesOperation.addDependency(validateAppExtensionsOperation)
|
||||||
|
|
||||||
/* Refresh */
|
/* Refresh */
|
||||||
let refreshAppOperation = RefreshAppOperation(context: context)
|
let refreshAppOperation = RefreshAppOperation(context: context)
|
||||||
@@ -1695,7 +1697,10 @@ private extension AppManager
|
|||||||
{
|
{
|
||||||
case .success(let installedApp):
|
case .success(let installedApp):
|
||||||
completionHandler(.success(installedApp))
|
completionHandler(.success(installedApp))
|
||||||
|
|
||||||
|
|
||||||
|
// refreshing local app's provisioning profile means talking to misagent daemon
|
||||||
|
// which requires loopback vpn
|
||||||
case .failure(MinimuxerError.ProfileInstall):
|
case .failure(MinimuxerError.ProfileInstall):
|
||||||
completionHandler(.failure(OperationError.noWiFi))
|
completionHandler(.failure(OperationError.noWiFi))
|
||||||
|
|
||||||
@@ -1720,7 +1725,8 @@ private extension AppManager
|
|||||||
progress.addChild(refreshAppOperation.progress, withPendingUnitCount: 40)
|
progress.addChild(refreshAppOperation.progress, withPendingUnitCount: 40)
|
||||||
refreshAppOperation.addDependency(fetchProvisioningProfilesOperation)
|
refreshAppOperation.addDependency(fetchProvisioningProfilesOperation)
|
||||||
|
|
||||||
let operations = [validateAppExtensionsOperation, fetchProvisioningProfilesOperation, refreshAppOperation]
|
// let operations = [validateAppExtensionsOperation, fetchProvisioningProfilesOperation, refreshAppOperation]
|
||||||
|
let operations = [fetchProvisioningProfilesOperation, refreshAppOperation]
|
||||||
group.add(operations)
|
group.add(operations)
|
||||||
self.run(operations, context: group.context)
|
self.run(operations, context: group.context)
|
||||||
|
|
||||||
|
|||||||
@@ -1151,7 +1151,9 @@ private extension MyAppsViewController
|
|||||||
|
|
||||||
func refresh(_ installedApp: InstalledApp)
|
func refresh(_ installedApp: InstalledApp)
|
||||||
{
|
{
|
||||||
guard minimuxerStatus else { return }
|
// we do need minimuxer, coz it needs to talk to misagent daemon which manages profiles
|
||||||
|
// so basically loopback vpn is still required
|
||||||
|
guard minimuxerStatus else { return } // we don't need minimuxer when renewing appIDs only do we, heck we can even do it on mobile internet
|
||||||
|
|
||||||
let previousProgress = AppManager.shared.refreshProgress(for: installedApp)
|
let previousProgress = AppManager.shared.refreshProgress(for: installedApp)
|
||||||
guard previousProgress == nil else {
|
guard previousProgress == nil else {
|
||||||
@@ -1467,7 +1469,10 @@ private extension MyAppsViewController
|
|||||||
do
|
do
|
||||||
{
|
{
|
||||||
let tempApp = context.object(with: installedApp.objectID) as! InstalledApp
|
let tempApp = context.object(with: installedApp.objectID) as! InstalledApp
|
||||||
tempApp.needsResign = true
|
tempApp.needsResign = true // why do we want to resign it during refresh ?!!!!
|
||||||
|
// I see now, so here we just mark that icon needs to be changed but leave it for refresh/install to do it
|
||||||
|
// this is bad, coz now the weight of installing goes to refresh step !!! which is not what we want
|
||||||
|
|
||||||
tempApp.hasAlternateIcon = (image != nil)
|
tempApp.hasAlternateIcon = (image != nil)
|
||||||
|
|
||||||
if let image = image
|
if let image = image
|
||||||
|
|||||||
@@ -13,15 +13,16 @@ import AltSign
|
|||||||
import Roxas
|
import Roxas
|
||||||
|
|
||||||
@objc(FetchProvisioningProfilesOperation)
|
@objc(FetchProvisioningProfilesOperation)
|
||||||
final class FetchProvisioningProfilesOperation: ResultOperation<[String: ALTProvisioningProfile]>
|
class FetchProvisioningProfilesOperation: ResultOperation<[String: ALTProvisioningProfile]>
|
||||||
{
|
{
|
||||||
let context: AppOperationContext
|
let context: AppOperationContext
|
||||||
|
|
||||||
var additionalEntitlements: [ALTEntitlement: Any]?
|
var additionalEntitlements: [ALTEntitlement: Any]?
|
||||||
|
|
||||||
private let appGroupsLock = NSLock()
|
internal let appGroupsLock = NSLock()
|
||||||
|
|
||||||
init(context: AppOperationContext)
|
// this class is abstract or shouldn't be instantiated outside, use the subclasses
|
||||||
|
fileprivate init(context: AppOperationContext)
|
||||||
{
|
{
|
||||||
self.context = context
|
self.context = context
|
||||||
|
|
||||||
@@ -40,11 +41,13 @@ final class FetchProvisioningProfilesOperation: ResultOperation<[String: ALTProv
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
guard
|
guard let team = self.context.team,
|
||||||
let team = self.context.team,
|
let session = self.context.session else {
|
||||||
let session = self.context.session
|
|
||||||
else {
|
return self.finish(.failure(
|
||||||
return self.finish(.failure(OperationError.invalidParameters("FetchProvisioningProfilesOperation.main: self.context.team or self.context.session is nil"))) }
|
OperationError.invalidParameters("FetchProvisioningProfilesOperation.main: self.context.team or self.context.session is nil"))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
guard let app = self.context.app else { return self.finish(.failure(OperationError.appNotFound(name: nil))) }
|
guard let app = self.context.app else { return self.finish(.failure(OperationError.appNotFound(name: nil))) }
|
||||||
|
|
||||||
@@ -120,7 +123,11 @@ final class FetchProvisioningProfilesOperation: ResultOperation<[String: ALTProv
|
|||||||
|
|
||||||
extension FetchProvisioningProfilesOperation
|
extension FetchProvisioningProfilesOperation
|
||||||
{
|
{
|
||||||
func prepareProvisioningProfile(for app: ALTApplication, parentApp: ALTApplication?, team: ALTTeam, session: ALTAppleAPISession, completionHandler: @escaping (Result<ALTProvisioningProfile, Error>) -> Void)
|
private func prepareProvisioningProfile(for app: ALTApplication,
|
||||||
|
parentApp: ALTApplication?,
|
||||||
|
team: ALTTeam,
|
||||||
|
session: ALTAppleAPISession, c
|
||||||
|
completionHandler: @escaping (Result<ALTProvisioningProfile, Error>) -> Void)
|
||||||
{
|
{
|
||||||
DatabaseManager.shared.persistentContainer.performBackgroundTask { (context) in
|
DatabaseManager.shared.persistentContainer.performBackgroundTask { (context) in
|
||||||
|
|
||||||
@@ -213,35 +220,22 @@ extension FetchProvisioningProfilesOperation
|
|||||||
{
|
{
|
||||||
case .failure(let error): completionHandler(.failure(error))
|
case .failure(let error): completionHandler(.failure(error))
|
||||||
case .success(let appID):
|
case .success(let appID):
|
||||||
|
|
||||||
// Update features
|
//process
|
||||||
self.updateFeatures(for: appID, app: app, team: team, session: session) { (result) in
|
self.fetchProvisioningProfile(
|
||||||
switch result
|
for: appID, team: team, session: session, completionHandler: completionHandler
|
||||||
{
|
)
|
||||||
case .failure(let error): completionHandler(.failure(error))
|
|
||||||
case .success(let appID):
|
|
||||||
|
|
||||||
// Update app groups
|
|
||||||
self.updateAppGroups(for: appID, app: app, team: team, session: session) { (result) in
|
|
||||||
switch result
|
|
||||||
{
|
|
||||||
case .failure(let error): completionHandler(.failure(error))
|
|
||||||
case .success(let appID):
|
|
||||||
|
|
||||||
// Fetch Provisioning Profile
|
|
||||||
self.fetchProvisioningProfile(for: appID, team: team, session: session) { (result) in
|
|
||||||
completionHandler(result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func registerAppID(for application: ALTApplication, name: String, bundleIdentifier: String, team: ALTTeam, session: ALTAppleAPISession, completionHandler: @escaping (Result<ALTAppID, Error>) -> Void)
|
private func registerAppID(for application: ALTApplication,
|
||||||
|
name: String,
|
||||||
|
bundleIdentifier: String,
|
||||||
|
team: ALTTeam,
|
||||||
|
session: ALTAppleAPISession,
|
||||||
|
completionHandler: @escaping (Result<ALTAppID, Error>) -> Void)
|
||||||
{
|
{
|
||||||
ALTAppleAPI.shared.fetchAppIDs(for: team, session: session) { (appIDs, error) in
|
ALTAppleAPI.shared.fetchAppIDs(for: team, session: session) { (appIDs, error) in
|
||||||
do
|
do
|
||||||
@@ -335,7 +329,81 @@ extension FetchProvisioningProfilesOperation
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateFeatures(for appID: ALTAppID, app: ALTApplication, team: ALTTeam, session: ALTAppleAPISession, completionHandler: @escaping (Result<ALTAppID, Error>) -> Void)
|
internal func fetchProvisioningProfile(for appID: ALTAppID, team: ALTTeam, session: ALTAppleAPISession, completionHandler: @escaping (Result<ALTProvisioningProfile, Error>) -> Void)
|
||||||
|
{
|
||||||
|
ALTAppleAPI.shared.fetchProvisioningProfile(for: appID, deviceType: .iphone, team: team, session: session) { (profile, error) in
|
||||||
|
switch Result(profile, error)
|
||||||
|
{
|
||||||
|
case .failure(let error): completionHandler(.failure(error))
|
||||||
|
case .success(let profile):
|
||||||
|
|
||||||
|
// Delete existing profile
|
||||||
|
ALTAppleAPI.shared.delete(profile, for: team, session: session) { (success, error) in
|
||||||
|
switch Result(success, error)
|
||||||
|
{
|
||||||
|
case .failure:
|
||||||
|
// As of March 20, 2023, the free provisioning profile is re-generated each fetch, and you can no longer delete it.
|
||||||
|
// So instead, we just return the fetched profile from above.
|
||||||
|
completionHandler(.success(profile))
|
||||||
|
|
||||||
|
case .success:
|
||||||
|
Logger.sideload.notice("Generating new free provisioning profile for App ID \(appID.bundleIdentifier, privacy: .public).")
|
||||||
|
|
||||||
|
// Fetch new provisioning profile
|
||||||
|
ALTAppleAPI.shared.fetchProvisioningProfile(for: appID, deviceType: .iphone, team: team, session: session) { (profile, error) in
|
||||||
|
completionHandler(Result(profile, error))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class FetchProvisioningProfilesRefreshOperation: FetchProvisioningProfilesOperation, @unchecked Sendable {
|
||||||
|
override init(context: AppOperationContext)
|
||||||
|
{
|
||||||
|
super.init(context: context)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class FetchProvisioningProfilesInstallOperation: FetchProvisioningProfilesOperation, @unchecked Sendable{
|
||||||
|
override init(context: AppOperationContext)
|
||||||
|
{
|
||||||
|
super.init(context: context)
|
||||||
|
}
|
||||||
|
|
||||||
|
// modify Operations are allowed for the app groups and other stuffs
|
||||||
|
func fetchProvisioningProfile(appID: ALTAppID,
|
||||||
|
for app: ALTApplication,
|
||||||
|
team: ALTTeam,
|
||||||
|
session: ALTAppleAPISession,
|
||||||
|
completionHandler: @escaping (Result<ALTProvisioningProfile, Error>) -> Void)
|
||||||
|
{
|
||||||
|
|
||||||
|
// Update features
|
||||||
|
self.updateFeatures(for: appID, app: app, team: team, session: session) { (result) in
|
||||||
|
switch result
|
||||||
|
{
|
||||||
|
case .failure(let error): completionHandler(.failure(error))
|
||||||
|
case .success(let appID):
|
||||||
|
|
||||||
|
// Update app groups
|
||||||
|
self.updateAppGroups(for: appID, app: app, team: team, session: session) { (result) in
|
||||||
|
switch result
|
||||||
|
{
|
||||||
|
case .failure(let error): completionHandler(.failure(error))
|
||||||
|
case .success(let appID):
|
||||||
|
|
||||||
|
// Fetch Provisioning Profile
|
||||||
|
super.fetchProvisioningProfile(for: appID, team: team, session: session, completionHandler: completionHandler)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func updateFeatures(for appID: ALTAppID, app: ALTApplication, team: ALTTeam, session: ALTAppleAPISession, completionHandler: @escaping (Result<ALTAppID, Error>) -> Void)
|
||||||
{
|
{
|
||||||
var entitlements = app.entitlements
|
var entitlements = app.entitlements
|
||||||
for (key, value) in additionalEntitlements ?? [:]
|
for (key, value) in additionalEntitlements ?? [:]
|
||||||
@@ -409,7 +477,7 @@ extension FetchProvisioningProfilesOperation
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateAppGroups(for appID: ALTAppID, app: ALTApplication, team: ALTTeam, session: ALTAppleAPISession, completionHandler: @escaping (Result<ALTAppID, Error>) -> Void)
|
private func updateAppGroups(for appID: ALTAppID, app: ALTApplication, team: ALTTeam, session: ALTAppleAPISession, completionHandler: @escaping (Result<ALTAppID, Error>) -> Void)
|
||||||
{
|
{
|
||||||
var entitlements = app.entitlements
|
var entitlements = app.entitlements
|
||||||
for (key, value) in additionalEntitlements ?? [:]
|
for (key, value) in additionalEntitlements ?? [:]
|
||||||
@@ -508,7 +576,7 @@ extension FetchProvisioningProfilesOperation
|
|||||||
Logger.sideload.notice("Created new App Group \(group.groupIdentifier, privacy: .public).")
|
Logger.sideload.notice("Created new App Group \(group.groupIdentifier, privacy: .public).")
|
||||||
groups.append(group)
|
groups.append(group)
|
||||||
|
|
||||||
case .failure(let error):
|
case .failure(let error):
|
||||||
Logger.sideload.notice("Failed to create new App Group \(adjustedGroupIdentifier, privacy: .public). \(error.localizedDescription, privacy: .public)")
|
Logger.sideload.notice("Failed to create new App Group \(adjustedGroupIdentifier, privacy: .public). \(error.localizedDescription, privacy: .public)")
|
||||||
errors.append(error)
|
errors.append(error)
|
||||||
}
|
}
|
||||||
@@ -544,34 +612,4 @@ extension FetchProvisioningProfilesOperation
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func fetchProvisioningProfile(for appID: ALTAppID, team: ALTTeam, session: ALTAppleAPISession, completionHandler: @escaping (Result<ALTProvisioningProfile, Error>) -> Void)
|
|
||||||
{
|
|
||||||
ALTAppleAPI.shared.fetchProvisioningProfile(for: appID, deviceType: .iphone, team: team, session: session) { (profile, error) in
|
|
||||||
switch Result(profile, error)
|
|
||||||
{
|
|
||||||
case .failure(let error): completionHandler(.failure(error))
|
|
||||||
case .success(let profile):
|
|
||||||
|
|
||||||
// Delete existing profile
|
|
||||||
ALTAppleAPI.shared.delete(profile, for: team, session: session) { (success, error) in
|
|
||||||
switch Result(success, error)
|
|
||||||
{
|
|
||||||
case .failure:
|
|
||||||
// As of March 20, 2023, the free provisioning profile is re-generated each fetch, and you can no longer delete it.
|
|
||||||
// So instead, we just return the fetched profile from above.
|
|
||||||
completionHandler(.success(profile))
|
|
||||||
|
|
||||||
case .success:
|
|
||||||
Logger.sideload.notice("Generating new free provisioning profile for App ID \(appID.bundleIdentifier, privacy: .public).")
|
|
||||||
|
|
||||||
// Fetch new provisioning profile
|
|
||||||
ALTAppleAPI.shared.fetchProvisioningProfile(for: appID, deviceType: .iphone, team: team, session: session) { (profile, error) in
|
|
||||||
completionHandler(Result(profile, error))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,10 +77,10 @@ struct OperationsLoggingControlView: View {
|
|||||||
}
|
}
|
||||||
))
|
))
|
||||||
|
|
||||||
CustomToggle("7. FetchProvisioningProfiles", isOn: Binding(
|
CustomToggle("7. FetchProvisioningProfiles(I)", isOn: Binding(
|
||||||
get: { self.viewModel.getFromDatabase(for: FetchProvisioningProfilesOperation.self) },
|
get: { self.viewModel.getFromDatabase(for: FetchProvisioningProfilesInstallOperation.self) },
|
||||||
set: { value in
|
set: { value in
|
||||||
self.viewModel.updateDatabase(for: FetchProvisioningProfilesOperation.self, value: value)
|
self.viewModel.updateDatabase(for: FetchProvisioningProfilesInstallOperation.self, value: value)
|
||||||
}
|
}
|
||||||
))
|
))
|
||||||
|
|
||||||
@@ -108,7 +108,14 @@ struct OperationsLoggingControlView: View {
|
|||||||
|
|
||||||
CustomSection(header: Text("Refresh Operations"))
|
CustomSection(header: Text("Refresh Operations"))
|
||||||
{
|
{
|
||||||
CustomToggle("1. RefreshApp", isOn: Binding(
|
CustomToggle("1. FetchProvisioningProfiles(R)", isOn: Binding(
|
||||||
|
get: { self.viewModel.getFromDatabase(for: FetchProvisioningProfilesRefreshOperation.self) },
|
||||||
|
set: { value in
|
||||||
|
self.viewModel.updateDatabase(for: FetchProvisioningProfilesRefreshOperation.self, value: value)
|
||||||
|
}
|
||||||
|
))
|
||||||
|
|
||||||
|
CustomToggle("2. RefreshApp", isOn: Binding(
|
||||||
get: { self.viewModel.getFromDatabase(for: RefreshAppOperation.self) },
|
get: { self.viewModel.getFromDatabase(for: RefreshAppOperation.self) },
|
||||||
set: { value in
|
set: { value in
|
||||||
self.viewModel.updateDatabase(for: RefreshAppOperation.self, value: value)
|
self.viewModel.updateDatabase(for: RefreshAppOperation.self, value: value)
|
||||||
|
|||||||
Reference in New Issue
Block a user