2

According to the docs, sending sendMessage from the WatchKit app will wake the iPhone app if it is inactive.

I would like to know the differences between such a wakeup app startup and a normal one. Surely a background process has a lot of differences to a normal foreground app. However, I could not find a thorough documentation on the subject.

Here's what I found so far:

  • Since such a "wakeup" is not a normal app startup, I expect didFinishLaunchingWithOptions to receive a special launchOptions key. After all, the user did not start the app on the home screen, so there should be an indication in launchOptions. But when I tried it out, launchOptions was nil. Doesn't that contradict the docs?
  • I also thought there should be differences because there is no UI present in a background process. So perhaps [UIScreen mainScreen] might be nil. But there seems to be no difference in mainScreen in the background process. In my AppDelegate.m, the code that creates the main window seems to run exactly the same way as in the foreground process.
  • I also expect that there are limits to the background process. Since the user did not actively start the process, I'm pretty sure that it cannot run for an infinite amount of time. Maybe there are also stricter memory limits.
  • Is there a way I can debug such a background process in XCode? Can I tell XCode "wait until the app runs on the iPhone", such that the debugger gets attached as soon as the app runs?
  • I also tried this in a React Native app. The Objective-C code in AppDelegate.m seemed to run exactly the same way, regardless of background or foreground process. However, the whole Javascript part of the app did not run (which is kind of expected, because in a background process, we do not need any React UI). But there must be a difference in the process that causes the Javascript part to not run.

Please don't consider this question to be about "more than one question". The question of this post is quite clear: I want to know all the differences between a didReceiveMessage background process and a normal one. In the enumeration above, I just listed all the differences I would expect or that I have encountered so far, and the lack of documentation on those topics.

Jonas Sourlier
  • 13,684
  • 16
  • 77
  • 148

2 Answers2

1

I think the background mode is just a UIKit concept. The app is started (thanks to the UIApplicationMain function) as a regular one but your app UI is not rendered.

It is just a warning: this is a transition state, your app can be suspended at any moment, be concise. The documentation is clear.

Regular UIKit APIs are available (if it was not the case, imagine all the potential crashs). But you won't receive any external events like touches.

Some external tasks like asking permissions, launching audio sessions etc would probably not be available too.

You can wait for the app to be launched by using the wait for the executable to be launched option in the scheme panel.

enter image description here

GaétanZ
  • 4,870
  • 1
  • 23
  • 30
  • Thank you. There must be one difference to normal startup that is not mentioned in your answer, because of the way React Native does not start up its Javascript part when in background. – Jonas Sourlier Nov 17 '21 at 18:04
  • I don't know RN. I would love to know the answer! – GaétanZ Nov 17 '21 at 18:12
  • Thanks for your answer. It does not answer all my points, but as there are no other answers, you can have the bounty :) – Jonas Sourlier Nov 24 '21 at 10:21
  • Aha thanks @cheesus. I saw this [question](https://stackoverflow.com/questions/69841422/does-the-ios-open-all-apps-after-a-reboot) yesterday. There is some info on the background mode. – GaétanZ Nov 24 '21 at 12:44
1

But when I tried it out, launchOptions was nil. Doesn't that contradict the docs?

Unfortunately LaunchOptions doesn't cover all ways an app gets launched. So if you see it nil then your case is one them too.

But there seems to be no difference in mainScreen in the background process.

That's true and expected. Things all get launched using the main thread. See here

Is there a way I can debug such a background process in XCode?

GaetanZ Has already answered this. Additionally you can use os.log and console together. That gives you a more realistic approach. Xcode interruptions are not fun to deal with. The wait for the executable to be launched scheme change often makes debugging super slow or often Xcode just disconnects or even throws you weird errors and the app gets killed without even giving you the option to attach to the debugger again.

I often use reboot the phone entirely. And then use oslog to see what happens to my app without ever having Xcode connected. For more on that see here.

A reboot is different to user-termination because often things don't get launched after-user termination. That being said I don't think the OS restricts app launch if user engages with their watch — even after a user-termination. Because user-engagement trumps everything.

However, the whole Javascript part of the app did not run (which is kind of expected, because in a background process, we do not need any React UI).

You then also said "which is kind of expected, because in a background process, we do not need any React UI"

I know very little of React, but also I'm confused what your question is about if you say it's expected.

But the part that the AppDelegate goes through all it's life-cycle is expected as previously mentioned.

You need to add a gazzilion amount of logs to see where you have a different code-path.

Most developers don't know that launching the app into the background will go all the way till the root viewController of your app and all its child viewcontrollers and stuff. But you learned it the hard way. Just as I did. Congratulations!

But once you know of that then the next thing is making sure your app doesn't segue into a different code-path i.e. on a normal launch you get WillBecomeActive and willEnterForeground, for a launch into the background you get something else. I'm not sure what it is right now. I think it's WillBecomeActive & didEnterBackground. Not sure.

Or like you may not be setting the delegate of your webview before things fire off and you miss its callbacks.

Remember app being in a background state doesn't mean things get executed on background queue. everything gets executed on the same queue/thread as it would in a foregrounded app. The only thing different is that the OS will often restrict network calls when an app isn't provisioned for them.

Likely that's what's happening. Like the OS doesn't want a webview to make network calls when it hasn't informed the app to be using and background Tasks as mentioned here or here

mfaani
  • 33,269
  • 19
  • 164
  • 293
  • Thank you, that gives me a lot to explore to go forward. With "is kind of expected" I meant, in a background process I would expect some differences related to UI. After all, there is no UI in a background process. But I do not know these differences, and I would like to know them. – Jonas Sourlier Nov 24 '21 at 23:25
  • Can you clarify what you mean by "After all, there is no UI in a background process"? What do you define as 'background process"? – mfaani Nov 24 '21 at 23:58
  • I mean, when the app is started in the background, then it is not the active app, the one in the foreground. We could have Gmail opened on your iPhone, and then iOS would start our app in the background, and we would not have any visible UI. – Jonas Sourlier Nov 25 '21 at 08:04