mirror of
https://github.com/SideStore/SideStore.git
synced 2026-02-19 19:53:25 +01:00
Adds support for isBackgroundRefreshEnabled setting
This commit is contained in:
@@ -63,6 +63,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
|||||||
|
|
||||||
ServerManager.shared.startDiscovering()
|
ServerManager.shared.startDiscovering()
|
||||||
|
|
||||||
|
UserDefaults.standard.registerDefaults()
|
||||||
|
|
||||||
if UserDefaults.standard.firstLaunch == nil
|
if UserDefaults.standard.firstLaunch == nil
|
||||||
{
|
{
|
||||||
Keychain.shared.reset()
|
Keychain.shared.reset()
|
||||||
@@ -129,8 +131,11 @@ extension AppDelegate
|
|||||||
}
|
}
|
||||||
|
|
||||||
func application(_ application: UIApplication, performFetchWithCompletionHandler backgroundFetchCompletionHandler: @escaping (UIBackgroundFetchResult) -> Void)
|
func application(_ application: UIApplication, performFetchWithCompletionHandler backgroundFetchCompletionHandler: @escaping (UIBackgroundFetchResult) -> Void)
|
||||||
|
{
|
||||||
|
if UserDefaults.standard.isBackgroundRefreshEnabled
|
||||||
{
|
{
|
||||||
ServerManager.shared.startDiscovering()
|
ServerManager.shared.startDiscovering()
|
||||||
|
}
|
||||||
|
|
||||||
let refreshIdentifier = UUID().uuidString
|
let refreshIdentifier = UUID().uuidString
|
||||||
|
|
||||||
@@ -140,9 +145,11 @@ extension AppDelegate
|
|||||||
{
|
{
|
||||||
// If finish is actually called, that means an error occured during installation.
|
// If finish is actually called, that means an error occured during installation.
|
||||||
|
|
||||||
|
if UserDefaults.standard.isBackgroundRefreshEnabled
|
||||||
|
{
|
||||||
ServerManager.shared.stopDiscovering()
|
ServerManager.shared.stopDiscovering()
|
||||||
|
|
||||||
self.scheduleFinishedRefreshingNotification(for: result, identifier: refreshIdentifier, delay: 0)
|
self.scheduleFinishedRefreshingNotification(for: result, identifier: refreshIdentifier, delay: 0)
|
||||||
|
}
|
||||||
|
|
||||||
taskCompletionHandler()
|
taskCompletionHandler()
|
||||||
}
|
}
|
||||||
@@ -183,12 +190,73 @@ private extension AppDelegate
|
|||||||
backgroundFetchCompletionHandler: @escaping (UIBackgroundFetchResult) -> Void,
|
backgroundFetchCompletionHandler: @escaping (UIBackgroundFetchResult) -> Void,
|
||||||
completionHandler: @escaping (Result<[String: Result<InstalledApp, Error>], Error>) -> 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
|
DatabaseManager.shared.persistentContainer.performBackgroundTask { (context) in
|
||||||
|
|
||||||
let installedApps = InstalledApp.fetchAppsForBackgroundRefresh(in: context)
|
let installedApps = InstalledApp.fetchAppsForBackgroundRefresh(in: context)
|
||||||
guard !installedApps.isEmpty else {
|
guard !installedApps.isEmpty else {
|
||||||
backgroundFetchCompletionHandler(.noData)
|
serversResult = .success(())
|
||||||
|
dispatchGroup.leave()
|
||||||
|
|
||||||
completionHandler(.failure(RefreshError.noInstalledApps))
|
completionHandler(.failure(RefreshError.noInstalledApps))
|
||||||
|
|
||||||
return
|
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:
|
// Wait for three seconds to:
|
||||||
// a) give us time to discover AltServers
|
// a) give us time to discover AltServers
|
||||||
// b) give other processes a chance to respond to requestAppState notification
|
// 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)
|
func receivedApplicationState(notification: CFNotificationName)
|
||||||
{
|
{
|
||||||
let baseName = String(CFNotificationName.appIsRunning.rawValue)
|
let baseName = String(CFNotificationName.appIsRunning.rawValue)
|
||||||
|
|||||||
@@ -15,4 +15,11 @@ extension UserDefaults
|
|||||||
@NSManaged var firstLaunch: Date?
|
@NSManaged var firstLaunch: Date?
|
||||||
|
|
||||||
@NSManaged var preferredServerID: String?
|
@NSManaged var preferredServerID: String?
|
||||||
|
|
||||||
|
@NSManaged var isBackgroundRefreshEnabled: Bool
|
||||||
|
|
||||||
|
func registerDefaults()
|
||||||
|
{
|
||||||
|
self.register(defaults: [#keyPath(UserDefaults.isBackgroundRefreshEnabled): true])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user