So I have a parent app that logs in to a server, creates a user etc. I then use handleWatchKitExtensionRequest from the WatchApp to access the parent app but everything is null.
My question is, does handleWatchKitExtensionRequest get run in a different instance to the parent app? I read somewhere it does but I just need this confirmed.
Thanks
If handleWatchKitExtensionRequest returns nothing it means that the passed reply is never called. This is most probably due to application.didFinishLaunchingWithOptions runs into an error when the app is launched in background mode.
I had a similar issue with my app where I did some initializations on the app's navigationController. It turned out that the navigationController is not accessible when the app is launched in background mode.
I would suggest to completely comment out the code in didFinishLaunchingWithOptions and see if handleWatchKitExtensionRequest calls its reply. If so, uncomment the code in didFinishWithLaunchingWithOptions step by step to detect the faulty code.
This may be really hard to track down because one cannot attach the debugger to the iPhone app at this time of launching.
Another pitfall:
The function signature of handleWatchKitExtensionRequest has changed in Swift 1.2 without giving any compiler errors. It took me hours to figure that out.
Related
In the old versions of my app, the scene(_:openURLContexts:) method is always called in these two cases:
The app isn't running. Then It's launched by an airdropped file.
The app is already running. Then a file is airdropped.
I created a separate app to work on the new version and made a lot of code changes. None of the changes should affect the above behavior, but I find the case 1 doesn't work. If the app isn't running, the airdropped file launches it successfully, but scene(_:openURLContexts:) isn't called.
More information:
To verify scene(_:openURLContexts:) is really not called, I added logs in the method and used Console app to monitor the logs.
I tested the old app on the same phone, which runs iOS 16.0.2. It works fine in both cases. So this isn't an OS issue.
Both of the apps are SwiftUI apps.
I searched on the net and found this workaround. It works for me.
I've discovered that the code below is need in willConnectTo session:
self.scene(scene, openURLContexts: connectionOptions.urlContexts)
The Apple's doc is very concise on these APIs. It's not clear to me what's the expected behavior and why my two apps have different behavior. Does anyone know if scene(_:openURLContexts:) is expected to be called when when app is launched by an airdropped file?
UPDATE: from this answer, scene(_:openURLContexts:) is not expected to be called when when app is launched by an airdropped file. If so, I don't understand why my old app works (from my search on the net, I'm not the only one who observed the different behaviors).
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.
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.
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
I am developing an iOS app with swift 3-4 and I have to know the time when my app crashed. How do I achieve that? I don't use firebase.
Integrate crashlytics to know about the crash, line of code that caused the crash, number of times it got crashed for the same issue etc.
You may have these notifications inside UIApplicationDelegate class:
applicationDidFinishLaunchingWithOptions:
applicationWillResignActive:
applicationDidEnterBackground:
applicationWillEnterForeground:
applicationDidBecomeActive:
applicationWillTerminate:
There are also more inside here.
You can do what you want inside the implementation of these delegates, including record time. Note still you don't run short in time, some evwnta give you only limited time to react.
I'm writing a WatchKit app which needs to make a query to our Parse server. Because this is a network call, I follow the following procedure:
I make a call from WatchKit to the iOS app using openParentApplication:reply:
Inside of handleWatchKitExtensionRequest:userInfo:reply:, I start a background task with a UIBackgroundTaskIdentifier to ensure the iOS app isn't terminated immediately
I set up my PFQuery and call findObjectsInBackgroundWithBlock:
In the block I pass to the PFQuery, I reply the relevant information to the watch
I wrote this app maybe a month ago before the Apple Watch was out, and it ran just fine in the Watch simulator. Yesterday I received my Apple Watch and I was able to get the app running on the watch, but it doesn't quite work - I managed to figure out that when the iOS app is actively running in the foreground on the iPhone, then everything is great; but if the app is not active (e.g. backgrounded or terminated), then findObjectsInBackgroundWithBlock: never actually calls the block, and execution seems to just stop.
Does anyone have any ideas of what might be going on? My initial thought was that the iOS app is getting suspended/killed before it can complete the query, but I was pretty sure the background task would prevent that.
PS. If anyone stumbles upon this question because they were looking for how to get a WatchKit app running on an actual watch, I found this post extremely helpful in getting it working.
Turned out that I had several problems related to openParentApplication:reply:, and they all seem to have been resolved by using the technique from this post:
http://www.fiveminutewatchkit.com/blog/2015/3/11/one-weird-trick-to-fix-openparentapplicationreply
I had started a background task for my own app, but I didn't use the "bogus workaround" background task described in this post, because it wasn't necessary for me in the simulator. On the watch, though, it apparently was.
I need to know when my app is being terminated (I am not talking about going to background).
Unfortunately the applicationWillTerminate method is never called.
I found some posts on SO about applications going to background, but I really need it when they are terminated. (Pressing home-button twice and then swiping up)
Any ideas how to get notified, when the app is terminated?
When the app is killed you will not get any notification to handle it in your app. The app just gets a signal 9, and the kernel cleans up the process including all threads.
I'm developing iOS-apps for almost two years, and I often have put a breakpoint into the -applicationWillTerminate: method, and the debugger never happened to break there. I think the method is only relevant to apps that are not multitasking-enabled - not multitasking-enabled apps are pretty rare since iOS 5. You'd have to explicitly disable multitasking in your Info.plist file, and there is usually no good reason to do this!