1

My goal is this: perform local backup / copy of some files/folders.

My app is an open source Signal app fork from GitHub. a Messaging app. Messages are store in a local database.

  • I need to perform local backup on my iOS app, at least once a day even if app is not in background but closed.
  • No server involved in the backup, is all a local process where some files, such images and database are required to be copied in a folder, zipped and encrypted.
  • No alert interaction from user should be required.
  • App won't be in the store, so I do not have a review fear at this moment.

I only found references to background activity, with a schema about background task (not refresh) that I report in this question, but it will work up to OS needs and wills, even if a preferred hour was set. I understand this. I give my code for example and possible help.

But is it possible to perform intensive operation such a backup while app is closed? Is there a way to perform my local backup at least once a day even if app is closed? how do other apps such Calendar, Alarm wok?

so, no shortcuts, I need to understand if there is some way to book a task while app is closed, or at least wile suspended. If the answer is "not possible" it is ok, I just need an explanation reference for my company.

This is my code for background task, if not possible doing what I ask, is this code right? Tried to test on console, seems to work

Targeting at least iOS 13, using UIKit.

I enabled background modes, background fetch and background processing in settings and capabilities, then added a string for the BGProcessingTaskRequest.

UPADTED from BGAppRefreshTask to BGProcessingTaskRequest (does not have 30 second of activity limit).

import UIKit
import BackgroundTasks

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

        BGTaskScheduler.shared.register(forTaskWithIdentifier: "com.example.mytask", using: nil) { task in
            self.handleAppRefreshTask(task: task as! BGProcessingTaskRequest)
        }
        
        scheduleAppRefresh()

        return true
    }

    func scheduleAppRefresh() {
        print("called: scheduleAppRefresh")
        
        let request = BGProcessingTaskRequest(identifier: "com.example.mytask")
        request.earliestBeginDate = Date(timeIntervalSinceNow: 5 * 60

        do {
            try BGTaskScheduler.shared.submit(request)
        } catch {
            print("not possible scheduling background app activity: \(error.localizedDescription)")
        }
        
    }

    func handleAppRefreshTask(task: BGProcessingTaskRequest) {
        let startDate = Date()
        print("starting backup date: \(startDate)")

        DispatchQueue.global().async {
            let backupDuration: TimeInterval = 180
            let endTime = Date(timeIntervalSinceNow: backupDuration)

            while Date() < endTime {
                print("performing backup...")
                Thread.sleep(forTimeInterval: 1)
            }

            let endDate = Date()
            print("end of backup: \(endDate)")

            task.setTaskCompleted(success: true)
        }

        scheduleAppRefresh()
    }



}

my info.plist

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>UIApplicationSceneManifest</key>
    <dict>
        <key>UIApplicationSupportsMultipleScenes</key>
        <false/>
        <key>UISceneConfigurations</key>
        <dict>
            <key>UIWindowSceneSessionRoleApplication</key>
            <array>
                <dict>
                    <key>UISceneConfigurationName</key>
                    <string>Default Configuration</string>
                    <key>UISceneDelegateClassName</key>
                    <string>$(PRODUCT_MODULE_NAME).SceneDelegate</string>
                    <key>UISceneStoryboardFile</key>
                    <string>Main</string>
                </dict>
            </array>
        </dict>
    </dict>
    <key>BGTaskSchedulerPermittedIdentifiers</key>
    <array>
        <string>com.example.mytask</string>
    </array>
    <key>UIBackgroundModes</key>
    <array>
        <string>fetch</string>
        <string>processing</string>
    </array>
</dict>
</plist>
biggreentree
  • 1,633
  • 3
  • 20
  • 35
  • 1
    `BGAppRefreshTask` that's for a "small interaction". In the sample from what you got that code, take the other one: `BGProcessingTaskRequest` if it's an heavy operation. And you won't "get logs" as the app is not running with Xcode. You need extra work to write on a file, and be able to read it later, so see your logs (there are third party for that). – Larme Jun 09 '23 at 17:09
  • thank you for hint, I updated the question.BUt other than not having the 30 second limit, this is still working up to the app being active somehow, and always up to OS needs. Is there a way to perform my local backup at least once a day even if app is closed? how do other apps such Calendar, Alarm wok? – biggreentree Jun 11 '23 at 09:47
  • For apps such as Calendar and Alarm, you would likely schedule them through the [User Notification framework](https://developer.apple.com/documentation/usernotifications/scheduling_a_notification_locally_from_your_app) – Ranoiaetep Jun 11 '23 at 09:57
  • 1
    @biggreentree Why do you need to run a backup process in the background at least once a day even if the app is closed? If the user doesn't use the app for a few days then there isn't a need to perform a backup on those unused days since no data would have changed, right? – HangarRash Jun 11 '23 at 14:56
  • @Ranoiaetep How could I use it? would it work even if app is closed? – biggreentree Jun 12 '23 at 07:07
  • @HangarRash I need to perform it because my boss wants it, we are talking about encrypted backup file of a messaging app, messages are received and stored even if app is closed. I need to perform this operation. Matter is, is it possible if app is closed somehow? – biggreentree Jun 12 '23 at 07:07
  • So how are you receiving the messages if no server's are involved? – Ranoiaetep Jun 12 '23 at 09:06
  • @Ranoiaetep no server is involved in local backup feature. My backup, It must be local, since user can move the encrypted file any moment and save it elsewhere. This is by design. My focus is find a way, if present, to perform my task in a certain time each day , if it is possible, with no action from user other than enable or disable relative switch in settings. – biggreentree Jun 12 '23 at 10:31
  • What you're trying to do is impossible. You will have to redesign. There is no "perform my task in a certain type each day" capability in iOS for 3rdparty apps. But your "messages are received and stored even if app is closed" doesn't make sense. How is the message received without the app launching into the background at least? What stores the message? – Rob Napier Jun 12 '23 at 14:00
  • You mentioned Calendar and Alarm, but neither of those do what you're describing. What functionality are you trying to replace from them? (It's very unclear where these files are that you're copying, or how they're getting updated without your app's involvement. Perhaps this would be smoother if you would explain your actual situation, since the answer to your question as asked is "it's impossible." Your actual situation might have a straightforward solution, however, if you'll tell us what it really is.) – Rob Napier Jun 12 '23 at 14:06
  • @RobNapier I added more detail about my app in the question. I know it is strange, but this is my need. Perform a protected local copy of some files in order for the user to copy such folder elsewhere via iTunes . So, is there a way, other than BGProcessingTaskRequest feature, to book an intensive operation, in background, in a moment of the day? I think no, my company yes, so I just need material to do it or demonstrate it cannot be done following best practices. – biggreentree Jun 12 '23 at 17:56
  • "So, is there a way, other than BGProcessingTaskRequest feature, to book an intensive operation, in background, in a moment of the day?" No. The closest you can get is to send a silent push notification from your server to every user. As long as the user accepts push notifications, and has network access, this will work. You can also do similar server-driven hacks like set up a permanent VoIP connection and push a websocket command saying "do thing." But all of them look like "have a server connection and have the server do something." – Rob Napier Jun 12 '23 at 18:01
  • There is no definite list from Apple of everything forbidden. There are documents that explain what is allowed, though no list I know that enumerates everything in one place. In iOS, you should assume if it is not explicitly permitted, it is forbidden. (Not 100% true, but generally true.) "I think there's an app on the App Store that does it!" is not the same as "permitted." In some cases things are permitted if you have a special entitlement from Apple. And sometimes there are hacks that work until Apple breaks them, so you can try stuff and see if it "works." I know no current one for this. – Rob Napier Jun 12 '23 at 18:19

1 Answers1

2

The tool you want is BGProcessingTaskRequest, and this is exactly the use case it's designed for, but it is not promised to run once a day. There is no mechanism to run something on a specific schedule other than sending silent push notifications, which have various limits of their own (the user can disable them, for example, and the phone needs a network or cell connection). There is no guaranteed way to run code on a fixed schedule. This is by design. Trying to work around it with tricks like background audio are, as you suggest, bad and can cause you to fail app review and be removed from the store.

You should step back and think through the actual problem you're trying to solve. Since there's no server, it sounds like this isn't actually a "backup," so much as perhaps moving/copying something to per-day files. If that's what you're doing, you can do that when the app launches; you don't have to do it exactly when the day changes. And you can use a BGProcessingTaskRequest to schedule that "occasionally" in the background so that it doesn't impact launch time as much.

Rob Napier
  • 286,113
  • 34
  • 456
  • 610
  • Thank you for your answer, in effect I do not have to be reviewed from this store (updated question), I'm now trying to use BGProcessingRequest, the lines to test them on console work, but in 24hours they did not work in "real life". My boss wants to know If I can perform a localized and encrypted copy of some data locally. Asking me why apple can schedule some task at a certain hour and I cannot. what do you think about it? could I use User Notification framework some how to schedule such actions? or it is better as you suggest perform a backup IE avery 2 days if the app is running? – biggreentree Jun 12 '23 at 07:03
  • With local notifications, you can alert the user to open the app, but you cannot launch the app silently. "Asking me why apple can schedule some task at a certain hour and I cannot." This is a strange question. Because they write the operating system. (Though I'm not aware of any app that does this. Calendar and Alarm don't do this.) – Rob Napier Jun 12 '23 at 14:05
  • I understand this, I agree with you. Matter is my boss does it with android, so I need to double check my knowledge, or demonstrate I cannot do the same, no shame on me, but OS design. what's up allows to decide a time for backup, but they do operation online, I do not. I'm asked "why you cannot do it. what if I want schedule something?" – biggreentree Jun 12 '23 at 17:59
  • I have over 15 years experience in Mac and iPhone development. If they'd like a consultant to come in and discuss what is and isn't possible, I'm happy to discuss rates. :D But more seriously, no, what you want is not possible, at least in the precise way you're describing. The more general problem might be solvable if we knew what it is (and I'm happy to consult on it directly if they prefer that). – Rob Napier Jun 12 '23 at 18:10
  • Thank you @RobNapier you are very clear. Unluckily I cannot discuss rates :D but I'll show you your answer. Matter is I'm a Swift developer, tryng to show swifty way to android developer. – biggreentree Aug 09 '23 at 06:40