Removes active app extension limits on 13.5 or later

This commit is contained in:
Riley Testut
2020-05-17 23:36:30 -07:00
parent e0dea67380
commit 39b60a07d9
4 changed files with 55 additions and 12 deletions

View File

@@ -23,6 +23,7 @@ extension UserDefaults
@NSManaged var legacySideloadedApps: [String]?
@NSManaged var isLegacyDeactivationSupported: Bool
@NSManaged var activeAppLimitIncludesExtensions: Bool
var activeAppsLimit: Int? {
get {
@@ -43,9 +44,13 @@ extension UserDefaults
func registerDefaults()
{
let ios13_5 = OperatingSystemVersion(majorVersion: 13, minorVersion: 5, patchVersion: 0)
let activeAppLimitIncludesExtensions = !ProcessInfo.processInfo.isOperatingSystemAtLeast(ios13_5)
self.register(defaults: [
#keyPath(UserDefaults.isBackgroundRefreshEnabled): true,
#keyPath(UserDefaults.isLegacyDeactivationSupported): false
#keyPath(UserDefaults.isLegacyDeactivationSupported): false,
#keyPath(UserDefaults.activeAppLimitIncludesExtensions): activeAppLimitIncludesExtensions
])
}
}

View File

@@ -56,6 +56,11 @@ class InstalledApp: NSManagedObject, InstalledAppProtocol
return 1 + self.appExtensions.count
}
var requiredActiveSlots: Int {
let requiredActiveSlots = UserDefaults.standard.activeAppLimitIncludesExtensions ? self.appIDCount : 1
return requiredActiveSlots
}
private override init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?)
{
super.init(entity: entity, insertInto: context)

View File

@@ -809,7 +809,18 @@ private extension MyAppsViewController
@objc func presentInactiveAppsAlert()
{
let alertController = UIAlertController(title: NSLocalizedString("What are inactive apps?", comment: ""), message: NSLocalizedString("Free developer accounts are limited to 3 apps and app extensions. Inactive apps don't count towards your total, but cannot be opened until activated.", comment: ""), preferredStyle: .alert)
let message: String
if UserDefaults.standard.activeAppLimitIncludesExtensions
{
message = NSLocalizedString("Free developer accounts are limited to 3 apps and app extensions. Inactive apps don't count towards your total, but cannot be opened until activated.", comment: "")
}
else
{
message = NSLocalizedString("Free developer accounts are limited to 3 apps. Inactive apps are backed up and uninstalled so they don't count towards your total, but will be reinstalled with all their data when activated again.", comment: "")
}
let alertController = UIAlertController(title: NSLocalizedString("What are inactive apps?", comment: ""), message: message, preferredStyle: .alert)
alertController.addAction(.ok)
self.present(alertController, animated: true, completion: nil)
}
@@ -929,12 +940,34 @@ private extension MyAppsViewController
let activeApps = InstalledApp.fetchActiveApps(in: DatabaseManager.shared.viewContext)
.filter { $0.bundleIdentifier != installedApp.bundleIdentifier } // Don't count app towards total if it matches activating app
let activeAppsCount = activeApps.map { $0.appIDCount }.reduce(0, +)
var title: String = NSLocalizedString("Cannot Activate More than 3 Apps", comment: "")
let message: String
if UserDefaults.standard.activeAppLimitIncludesExtensions
{
if installedApp.appExtensions.isEmpty
{
message = NSLocalizedString("Free developer accounts are limited to 3 active apps and app extensions. Please choose an app to deactivate.", comment: "")
}
else
{
title = NSLocalizedString("Cannot Activate More than 3 Apps and App Extensions", comment: "")
let appExtensionText = installedApp.appExtensions.count == 1 ? NSLocalizedString("app extension", comment: "") : NSLocalizedString("app extensions", comment: "")
message = String(format: NSLocalizedString("Free developer accounts are limited to 3 active apps and app extensions, and “%@” contains %@ %@. Please choose an app to deactivate.", comment: ""), installedApp.name, NSNumber(value: installedApp.appExtensions.count), appExtensionText)
}
}
else
{
message = NSLocalizedString("Free developer accounts are limited to 3 active apps. Please choose an app to deactivate.", comment: "")
}
let activeAppsCount = activeApps.map { $0.requiredActiveSlots }.reduce(0, +)
let availableActiveApps = max(activeAppsLimit - activeAppsCount, 0)
guard installedApp.appIDCount > availableActiveApps else { return completion(true) }
guard installedApp.requiredActiveSlots > availableActiveApps else { return completion(true) }
let alertController = UIAlertController(title: NSLocalizedString("Cannot Activate More than 3 Apps", comment: ""), message: NSLocalizedString("Free developer accounts are limited to 3 active apps and app extensions. Please choose an app to deactivate.", comment: ""), preferredStyle: .alert)
let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: UIAlertAction.cancel.title, style: UIAlertAction.cancel.style) { (action) in
completion(false)
})
@@ -942,8 +975,8 @@ private extension MyAppsViewController
for app in activeApps where app.bundleIdentifier != StoreApp.altstoreAppID
{
alertController.addAction(UIAlertAction(title: app.name, style: .default) { (action) in
let availableActiveApps = availableActiveApps + app.appIDCount
if availableActiveApps >= installedApp.appIDCount
let availableActiveApps = availableActiveApps + app.requiredActiveSlots
if availableActiveApps >= installedApp.requiredActiveSlots
{
// There are enough slots now to activate the app, so pre-emptively
// mark it as active to provide visual feedback sooner.
@@ -1572,10 +1605,10 @@ extension MyAppsViewController: UICollectionViewDropDelegate
return UICollectionViewDropProposal(operation: .move, intent: .insertAtDestinationIndexPath)
}
let activeAppsCount = (self.activeAppsDataSource.fetchedResultsController.fetchedObjects ?? []).map { $0.appIDCount }.reduce(0, +)
let activeAppsCount = (self.activeAppsDataSource.fetchedResultsController.fetchedObjects ?? []).map { $0.requiredActiveSlots }.reduce(0, +)
let availableActiveApps = max(activeAppsLimit - activeAppsCount, 0)
if installedApp.appIDCount <= availableActiveApps
if installedApp.requiredActiveSlots <= availableActiveApps
{
// Enough active app slots, so no need to deactivate app first.
return UICollectionViewDropProposal(operation: .copy, intent: .insertAtDestinationIndexPath)

View File

@@ -122,10 +122,10 @@ class InstallAppOperation: ResultOperation<InstalledApp>
var activeApps = InstalledApp.fetch(fetchRequest, in: backgroundContext)
if !activeApps.contains(installedApp)
{
let availableActiveApps = max(sideloadedAppsLimit - activeApps.count, 0)
let requiredActiveAppSlots = 1 + installedExtensions.count // As of iOS 13.3.1, app extensions count as "apps"
let activeAppsCount = activeApps.map { $0.requiredActiveSlots }.reduce(0, +)
if requiredActiveAppSlots <= availableActiveApps
let availableActiveApps = max(sideloadedAppsLimit - activeAppsCount, 0)
if installedApp.requiredActiveSlots <= availableActiveApps
{
// This app has not been explicitly activated, but there are enough slots available,
// so implicitly activate it.