Differences between normal app startup and a wakeup from WatchKit's sendMessage?

Viewed 171

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.

2 Answers

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

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

Related