mirror of
https://github.com/SideStore/SideStore.git
synced 2026-02-21 12:43:25 +01:00
Adds support for isBackgroundRefreshEnabled setting
This commit is contained in:
@@ -63,6 +63,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
|
||||
ServerManager.shared.startDiscovering()
|
||||
|
||||
UserDefaults.standard.registerDefaults()
|
||||
|
||||
if UserDefaults.standard.firstLaunch == nil
|
||||
{
|
||||
Keychain.shared.reset()
|
||||
@@ -129,8 +131,11 @@ extension AppDelegate
|
||||
}
|
||||
|
||||
func application(_ application: UIApplication, performFetchWithCompletionHandler backgroundFetchCompletionHandler: @escaping (UIBackgroundFetchResult) -> Void)
|
||||
{
|
||||
if UserDefaults.standard.isBackgroundRefreshEnabled
|
||||
{
|
||||
ServerManager.shared.startDiscovering()
|
||||
}
|
||||
|
||||
let refreshIdentifier = UUID().uuidString
|
||||
|
||||
@@ -140,9 +145,11 @@ extension AppDelegate
|
||||
{
|
||||
// If finish is actually called, that means an error occured during installation.
|
||||
|
||||
if UserDefaults.standard.isBackgroundRefreshEnabled
|
||||
{
|
||||
ServerManager.shared.stopDiscovering()
|
||||
|
||||
self.scheduleFinishedRefreshingNotification(for: result, identifier: refreshIdentifier, delay: 0)
|
||||
}
|
||||
|
||||
taskCompletionHandler()
|
||||
}
|
||||
@@ -183,12 +190,73 @@ private extension AppDelegate
|
||||
backgroundFetchCompletionHandler: @escaping (UIBackgroundFetchResult) -> Void,
|
||||
completionHandler: @escaping (Result<[String: Result<InstalledApp, Error>], Error>) -> Void)
|
||||
{
|
||||
var fetchSourceResult: Result<Source, Error>?
|
||||
var serversResult: Result<Void, Error>?
|
||||
|
||||
let dispatchGroup = DispatchGroup()
|
||||
dispatchGroup.enter()
|
||||
|
||||
AppManager.shared.fetchSource() { (result) in
|
||||
fetchSourceResult = result
|
||||
|
||||
do
|
||||
{
|
||||
let source = try result.get()
|
||||
|
||||
guard let context = source.managedObjectContext else { return }
|
||||
|
||||
let previousUpdatesFetchRequest = InstalledApp.updatesFetchRequest() as! NSFetchRequest<NSFetchRequestResult>
|
||||
previousUpdatesFetchRequest.includesPendingChanges = false
|
||||
previousUpdatesFetchRequest.resultType = .dictionaryResultType
|
||||
previousUpdatesFetchRequest.propertiesToFetch = [#keyPath(InstalledApp.bundleIdentifier)]
|
||||
|
||||
let previousUpdates = try context.fetch(previousUpdatesFetchRequest) as! [[String: String]]
|
||||
|
||||
try context.save()
|
||||
|
||||
let updatesFetchRequest = InstalledApp.updatesFetchRequest()
|
||||
let updates = try context.fetch(updatesFetchRequest)
|
||||
|
||||
for update in updates
|
||||
{
|
||||
guard !previousUpdates.contains(where: { $0[#keyPath(InstalledApp.bundleIdentifier)] == update.bundleIdentifier }) else { continue }
|
||||
guard let storeApp = update.storeApp else { continue }
|
||||
|
||||
let content = UNMutableNotificationContent()
|
||||
content.title = NSLocalizedString("New Update Available", comment: "")
|
||||
content.body = String(format: NSLocalizedString("%@ %@ is now available for download.", comment: ""), update.name, storeApp.version)
|
||||
|
||||
let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: nil)
|
||||
UNUserNotificationCenter.current().add(request)
|
||||
}
|
||||
|
||||
DispatchQueue.main.async {
|
||||
UIApplication.shared.applicationIconBadgeNumber = updates.count
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
print("Error fetching apps:", error)
|
||||
|
||||
fetchSourceResult = .failure(error)
|
||||
}
|
||||
|
||||
dispatchGroup.leave()
|
||||
}
|
||||
|
||||
if UserDefaults.standard.isBackgroundRefreshEnabled
|
||||
{
|
||||
dispatchGroup.enter()
|
||||
|
||||
DatabaseManager.shared.persistentContainer.performBackgroundTask { (context) in
|
||||
|
||||
let installedApps = InstalledApp.fetchAppsForBackgroundRefresh(in: context)
|
||||
guard !installedApps.isEmpty else {
|
||||
backgroundFetchCompletionHandler(.noData)
|
||||
serversResult = .success(())
|
||||
dispatchGroup.leave()
|
||||
|
||||
completionHandler(.failure(RefreshError.noInstalledApps))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -210,74 +278,6 @@ private extension AppDelegate
|
||||
}
|
||||
}
|
||||
|
||||
var fetchSourceResult: Result<Source, Error>?
|
||||
var serversResult: Result<Void, Error>?
|
||||
|
||||
let dispatchGroup = DispatchGroup()
|
||||
dispatchGroup.enter()
|
||||
dispatchGroup.enter()
|
||||
|
||||
AppManager.shared.fetchSource() { (result) in
|
||||
fetchSourceResult = result
|
||||
dispatchGroup.leave()
|
||||
|
||||
do
|
||||
{
|
||||
let source = try result.get()
|
||||
|
||||
guard let context = source.managedObjectContext else { return }
|
||||
|
||||
let updatesFetchRequest = InstalledApp.updatesFetchRequest()
|
||||
updatesFetchRequest.includesPendingChanges = true
|
||||
|
||||
let previousUpdatesFetchRequest = InstalledApp.updatesFetchRequest()
|
||||
previousUpdatesFetchRequest.includesPendingChanges = false
|
||||
|
||||
let previousUpdates = try context.fetch(previousUpdatesFetchRequest)
|
||||
|
||||
try context.save()
|
||||
|
||||
let updates = try context.fetch(updatesFetchRequest)
|
||||
|
||||
for update in updates
|
||||
{
|
||||
guard !previousUpdates.contains(where: { $0.bundleIdentifier == update.bundleIdentifier }) else { continue }
|
||||
|
||||
guard let storeApp = update.storeApp else { continue }
|
||||
|
||||
let content = UNMutableNotificationContent()
|
||||
content.title = NSLocalizedString("New Update Available", comment: "")
|
||||
content.body = String(format: NSLocalizedString("%@ %@ is now available for download.", comment: ""), update.name, storeApp.version)
|
||||
|
||||
let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: nil)
|
||||
UNUserNotificationCenter.current().add(request)
|
||||
}
|
||||
|
||||
DispatchQueue.main.async {
|
||||
UIApplication.shared.applicationIconBadgeNumber = updates.count
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
print("Error fetching apps:", error)
|
||||
}
|
||||
}
|
||||
|
||||
dispatchGroup.notify(queue: .main) {
|
||||
guard let fetchSourceResult = fetchSourceResult, let serversResult = serversResult else {
|
||||
backgroundFetchCompletionHandler(.failed)
|
||||
return
|
||||
}
|
||||
|
||||
// Call completionHandler early to improve chances of refreshing in the background again.
|
||||
switch (fetchSourceResult, serversResult)
|
||||
{
|
||||
case (.success, .success): backgroundFetchCompletionHandler(.newData)
|
||||
case (.success, .failure(ConnectionError.serverNotFound)): backgroundFetchCompletionHandler(.newData)
|
||||
case (.failure, _), (_, .failure): backgroundFetchCompletionHandler(.failed)
|
||||
}
|
||||
}
|
||||
|
||||
// Wait for three seconds to:
|
||||
// a) give us time to discover AltServers
|
||||
// b) give other processes a chance to respond to requestAppState notification
|
||||
@@ -328,6 +328,40 @@ private extension AppDelegate
|
||||
}
|
||||
}
|
||||
|
||||
dispatchGroup.notify(queue: .main) {
|
||||
if !UserDefaults.standard.isBackgroundRefreshEnabled
|
||||
{
|
||||
guard let fetchSourceResult = fetchSourceResult else {
|
||||
backgroundFetchCompletionHandler(.failed)
|
||||
return
|
||||
}
|
||||
|
||||
switch fetchSourceResult
|
||||
{
|
||||
case .failure: backgroundFetchCompletionHandler(.failed)
|
||||
case .success: backgroundFetchCompletionHandler(.newData)
|
||||
}
|
||||
|
||||
completionHandler(.success([:]))
|
||||
}
|
||||
else
|
||||
{
|
||||
guard let fetchSourceResult = fetchSourceResult, let serversResult = serversResult else {
|
||||
backgroundFetchCompletionHandler(.failed)
|
||||
return
|
||||
}
|
||||
|
||||
// Call completionHandler early to improve chances of refreshing in the background again.
|
||||
switch (fetchSourceResult, serversResult)
|
||||
{
|
||||
case (.success, .success): backgroundFetchCompletionHandler(.newData)
|
||||
case (.success, .failure(ConnectionError.serverNotFound)): backgroundFetchCompletionHandler(.newData)
|
||||
case (.failure, _), (_, .failure): backgroundFetchCompletionHandler(.failed)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func receivedApplicationState(notification: CFNotificationName)
|
||||
{
|
||||
let baseName = String(CFNotificationName.appIsRunning.rawValue)
|
||||
|
||||
@@ -15,4 +15,11 @@ extension UserDefaults
|
||||
@NSManaged var firstLaunch: Date?
|
||||
|
||||
@NSManaged var preferredServerID: String?
|
||||
|
||||
@NSManaged var isBackgroundRefreshEnabled: Bool
|
||||
|
||||
func registerDefaults()
|
||||
{
|
||||
self.register(defaults: [#keyPath(UserDefaults.isBackgroundRefreshEnabled): true])
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user