Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 12 additions & 4 deletions Nextcloud.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,8 @@
F710FC80277B7D2700AA9FBF /* RealmSwift in Frameworks */ = {isa = PBXBuildFile; productRef = F710FC7F277B7D2700AA9FBF /* RealmSwift */; };
F710FC84277B7D3500AA9FBF /* RealmSwift in Frameworks */ = {isa = PBXBuildFile; productRef = F710FC83277B7D3500AA9FBF /* RealmSwift */; };
F710FC88277B7D3F00AA9FBF /* RealmSwift in Frameworks */ = {isa = PBXBuildFile; productRef = F710FC87277B7D3F00AA9FBF /* RealmSwift */; };
F7110AE02F9773230095AA5C /* AppDelegate+AppRefresh.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7110ADF2F9773210095AA5C /* AppDelegate+AppRefresh.swift */; };
F7110AE42F9774140095AA5C /* AppDelegate+AppProcessing.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7110AE32F9774130095AA5C /* AppDelegate+AppProcessing.swift */; };
F711A4DC2AF92CAE00095DD8 /* NCUtility+Date.swift in Sources */ = {isa = PBXBuildFile; fileRef = F711A4DB2AF92CAD00095DD8 /* NCUtility+Date.swift */; };
F711A4DD2AF92CAE00095DD8 /* NCUtility+Date.swift in Sources */ = {isa = PBXBuildFile; fileRef = F711A4DB2AF92CAD00095DD8 /* NCUtility+Date.swift */; };
F711A4DE2AF92CAE00095DD8 /* NCUtility+Date.swift in Sources */ = {isa = PBXBuildFile; fileRef = F711A4DB2AF92CAD00095DD8 /* NCUtility+Date.swift */; };
Expand Down Expand Up @@ -1331,6 +1333,8 @@
F71070AA2F7E49E100AEE58A /* NCEndToEndSetup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCEndToEndSetup.swift; sourceTree = "<group>"; };
F710D1F42405770F00A6033D /* NCViewerPDF.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCViewerPDF.swift; sourceTree = "<group>"; };
F710D2012405826100A6033D /* NCContextMenuViewer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCContextMenuViewer.swift; sourceTree = "<group>"; };
F7110ADF2F9773210095AA5C /* AppDelegate+AppRefresh.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppDelegate+AppRefresh.swift"; sourceTree = "<group>"; };
F7110AE32F9774130095AA5C /* AppDelegate+AppProcessing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppDelegate+AppProcessing.swift"; sourceTree = "<group>"; };
F711A4DB2AF92CAD00095DD8 /* NCUtility+Date.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NCUtility+Date.swift"; sourceTree = "<group>"; };
F7132C6B2D085AD200B42D6A /* NCTermOfServiceModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCTermOfServiceModel.swift; sourceTree = "<group>"; };
F7132C6C2D085AD200B42D6A /* NCTermOfServiceView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCTermOfServiceView.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -3287,6 +3291,8 @@
children = (
AA517BB42D66149900F8D37C /* .tx */,
F702F2CC25EE5B4F008F8E80 /* AppDelegate.swift */,
F7110ADF2F9773210095AA5C /* AppDelegate+AppRefresh.swift */,
F7110AE32F9774130095AA5C /* AppDelegate+AppProcessing.swift */,
F7CAFE1A2F16AA8600DB35A5 /* main.swift */,
F794E13E2BBC0F70003693D7 /* SceneDelegate.swift */,
F7CF067A2E0FF38F0063AD04 /* NCAppStateManager.swift */,
Expand Down Expand Up @@ -4508,6 +4514,7 @@
F70753F12542A9A200972D44 /* NCViewerMedia.swift in Sources */,
F799DF822C4B7DCC003410B5 /* NCSectionFooter.swift in Sources */,
F76B649C2ADFFAED00014640 /* NCImageCache.swift in Sources */,
F7110AE42F9774140095AA5C /* AppDelegate+AppProcessing.swift in Sources */,
F76341182EBE0BC60056F538 /* NCNetworking+NextcloudKitDelegate.swift in Sources */,
F78A18B823CDE2B300F681F3 /* NCViewerRichWorkspace.swift in Sources */,
F34E1AD92ECC839100FA10C3 /* EmojiTextField.swift in Sources */,
Expand All @@ -4531,6 +4538,7 @@
F765E9CD295C585800A09ED8 /* NCUploadScanDocument.swift in Sources */,
F741C2242B6B9FD600E849BB /* NCMediaSelectTabBar.swift in Sources */,
F7BF9D822934CA21009EE9A6 /* NCManageDatabase+LayoutForView.swift in Sources */,
F7110AE02F9773230095AA5C /* AppDelegate+AppRefresh.swift in Sources */,
AA8D31662D411FA100FE2775 /* NCShareDateCell.swift in Sources */,
F3F442EE2DDE292D00FD701F /* NCMetadataPermissions.swift in Sources */,
F3374A812D64AB9F002A38F9 /* StatusInfo.swift in Sources */,
Expand Down Expand Up @@ -5790,7 +5798,7 @@
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1;
CURRENT_PROJECT_VERSION = 0;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = NKUJUXUJ3B;
Expand Down Expand Up @@ -5818,7 +5826,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 33.0.6;
MARKETING_VERSION = 33.0.7;
ONLY_ACTIVE_ARCH = YES;
OTHER_CFLAGS = "-v";
OTHER_LDFLAGS = "";
Expand Down Expand Up @@ -5858,7 +5866,7 @@
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1;
CURRENT_PROJECT_VERSION = 0;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = NKUJUXUJ3B;
Expand All @@ -5884,7 +5892,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 33.0.6;
MARKETING_VERSION = 33.0.7;
ONLY_ACTIVE_ARCH = YES;
OTHER_CFLAGS = "-v";
OTHER_LDFLAGS = "";
Expand Down
98 changes: 98 additions & 0 deletions iOSClient/AppDelegate+AppProcessing.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
// SPDX-FileCopyrightText: Nextcloud GmbH
// SPDX-FileCopyrightText: 2026 Marino Faggiana
// SPDX-License-Identifier: GPL-3.0-or-later

import UIKit
import NextcloudKit
import BackgroundTasks

extension AppDelegate {
// Schedules the next processing task.
//
// The scheduler may delay execution depending on device conditions,
// battery state, thermal conditions, and system policy.
func scheduleAppProcessing() {
BGTaskScheduler.shared.cancel(taskRequestWithIdentifier: global.processingTask)

let request = BGProcessingTaskRequest(identifier: global.processingTask)
request.earliestBeginDate = Date(timeIntervalSinceNow: 5 * 60)
request.requiresNetworkConnectivity = false
request.requiresExternalPower = false

do {
try BGTaskScheduler.shared.submit(request)
} catch {
nkLog(tag: self.global.logTagTask, emoji: .error, message: "Processing task failed to submit request: \(error)")
}
}

// Handles the BGProcessingTask lifecycle for weekly cleanup or background synchronization.
//
// The function:
// - validates background Realm availability,
// - schedules the next processing task,
// - executes either weekly cleanup or background sync,
// - cooperates with BGTask expiration by cancelling the Swift task,
// - reports success only if the work completes without cancellation.
//
// - Parameter task: The system-provided background processing task.
func handleProcessingTask(_ task: BGProcessingTask) {
nkLog(tag: self.global.logTagTask, emoji: .start, message: "Start processing task")

guard NCManageDatabase.shared.openRealmBackground() else {
nkLog(tag: self.global.logTagTask, emoji: .error, message: "Failed to open Realm in background")
task.setTaskCompleted(success: false)
return
}

// Schedule next processing task.
scheduleAppProcessing()

let processingTask = Task { () -> Bool in
// If possible, cleaning every week.
if NCPreferences().cleaningWeek() {
nkLog(tag: self.global.logTagBgSync, emoji: .start, message: "Start cleaning week")

let tblAccounts = await NCManageDatabase.shared.getAllTableAccountAsync()
for tblAccount in tblAccounts {
guard !Task.isCancelled else {
return false
}

await NCManageDatabase.shared.cleanTablesOcIds(
account: tblAccount.account,
userId: tblAccount.userId,
urlBase: tblAccount.urlBase
)
}

guard !Task.isCancelled else {
return false
}

await NCUtilityFileSystem().cleanUpAsync()

guard !Task.isCancelled else {
return false
}

NCPreferences().setDoneCleaningWeek()
nkLog(tag: self.global.logTagBgSync, emoji: .stop, message: "Stop cleaning week")
return true
} else {
await NCAutoUpload.shared.autoUploadBackgroundSync()
return !Task.isCancelled
}
}

Task {
let success = await processingTask.value
task.setTaskCompleted(success: success)
}

task.expirationHandler = {
nkLog(tag: self.global.logTagTask, emoji: .stop, message: "Processing task expired")
processingTask.cancel()
}
}
}
64 changes: 64 additions & 0 deletions iOSClient/AppDelegate+AppRefresh.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// SPDX-FileCopyrightText: Nextcloud GmbH
// SPDX-FileCopyrightText: 2026 Marino Faggiana
// SPDX-License-Identifier: GPL-3.0-or-later

import UIKit
import NextcloudKit
import BackgroundTasks

extension AppDelegate {
// Schedules the next app refresh task.
//
// The scheduler may delay execution depending on device conditions,
// battery state, usage patterns, and system policy.
func scheduleAppRefresh() {
BGTaskScheduler.shared.cancel(taskRequestWithIdentifier: global.refreshTask)

let request = BGAppRefreshTaskRequest(identifier: global.refreshTask)
request.earliestBeginDate = Date(timeIntervalSinceNow: 60)

do {
try BGTaskScheduler.shared.submit(request)
} catch {
nkLog(tag: self.global.logTagTask, emoji: .error, message: "Refresh task failed to submit request: \(error)")
}
}

// Handles the BGAppRefreshTask lifecycle for background synchronization.
//
// The function:
// - validates background Realm availability,
// - schedules the next refresh task,
// - starts the background synchronization flow,
// - cooperates with BGTask expiration by cancelling the Swift task,
// - reports success only if the work completes without cancellation.
//
// - Parameter task: The system-provided background refresh task.
func handleAppRefresh(_ task: BGAppRefreshTask) {
nkLog(tag: self.global.logTagTask, emoji: .start, message: "Start refresh task")

guard NCManageDatabase.shared.openRealmBackground() else {
nkLog(tag: self.global.logTagTask, emoji: .error, message: "Failed to open Realm in background")
task.setTaskCompleted(success: false)
return
}

// Schedule next refresh.
scheduleAppRefresh()

let refreshTask = Task { () -> Bool in
await NCAutoUpload.shared.autoUploadBackgroundSync()
return !Task.isCancelled
}

Task {
let success = await refreshTask.value
task.setTaskCompleted(success: success)
}

task.expirationHandler = {
nkLog(tag: self.global.logTagTask, emoji: .stop, message: "Refresh task expired")
refreshTask.cancel()
}
}
}
Loading
Loading