I'm confused about WatchKit and WidgetKit and Watch Apps... Help!

Sorry for the length of this post, and all the questions.

I have an iOS app written in Objective-C (too big to convert to Swift right now), and I successfully added a WatchKit app and WatchKit Extension some years ago. I also added Home Screen widgets when iOS 14 was released.

With the iOS 16 betas I'd like to support Lock Screen widgets, and have also decided to move the WatchKit app/extension to SwiftUI.

User journey: MyApp is launched and an item with an image is created. This item is stored in Core Data and its image is stored in a directory in the app's documents directory. A version of it is stored in NSUserDefaults in a shared app group. The user adds a Home Screen widget to show that item. Its data is pulled from the defaults, and the image is loaded from the document's directory.

The user installs the Watch app and launches it. The Watch app looks inside the user defaults to retrieve the item. The iOS app sends the image to the Watch and the Watch app stores it locally (it's a small image, taking up barely a few Kb).

This all works fine right now.

Currently I have these targets:

  • MyApp = main iOS app.
  • MyApp WatchKit = Watch app storyboards and asset catalogs.
  • MyApp WatchKit Extension = code to update the Watch interface.
  • MyApp Widget = Home Screen widgets.
  • MyApp IntentHandler = dynamic intents handler for the Home Screen widgets.

Q1. Where do I put the code for the Lock Screen widgets? I figure these go into the My App Widget target because they're widgets and appear on the iPhone?


In this video (https://developer.apple.com/videos/play/wwdc2022/10050) at 07:00 it tells you to duplicate the existing Widget target, change the bundle, change it to run on watchOS and embed it in your existing Watch App. As my original Watch App is written in Objective-C (MyApp WatchKit Extension, above) I can't/shouldn't do that, so...

Q2. I think I have to create a new MyApp Watch App target, and perform the video steps on that target? I can create the views for that app, no problem.


Most people update to the latest watchOS, and it's only now that watchOS 9 won't support Watch Series 3.

Q3. Do I need to keep MyApp WatchKit and MyApp WatchKit Extension around? I can support older versions of watchOS if it helps my users, but they'll probably want to use the new version of watchOS, right? Can you install both versions of the app on your Watch (with watchOS 9), or does the new Swift app override the old WatchKit extension?


Q4. Once I've designed the new Watch App's views in SwiftUI to replace the old WatchKit extension, where do I put the code for the complications that are being replaced? The WWDC 2022 videos (above, and a couple linked to on that page) have confused me a bit. Do I put complications views in the new MyApp Watch App target along with the other views that replace the old Watch app, or in MyApp Widget?


Q5. The MyApp Widget target contains a bunch of code (WidgetUtils.swift) that populates the Home Screen widgets (and the new Lock Screen widgets), and it would fit right into the new MyApp Watch App target. Can I share that code between the two app targets just by adding WidgetUtils.swift to both target's membership?


MyApp sends small images to the current MyApp WatchKit Extension. There's no code in the existing WidgetUtils.swift to handle file transfers because the images for the Home Screen widgets are pulled from the iOS app, so I need to write that in Swift for the new MyApp Watch App. The logic is already there in the old target, but I can't see any sort of equivalent to the WatchKit extension delegate where I currently handle the file transfers.

Q6. Where does that go in MyApp Watch App?


The existing MyApp WatchKit Extension occasionally asks MyApp for some new data. This is all done in the extension delegate which wakes up the iOS app and updates the NSUserDefaults which the extension then reads from.

Q7. How do you do that in MyApp Watch App?


Don't be afraid to be verbose in your responses. The more detail the better! Thank you in advance.

Replies

A1. Yes, your iOS lock screen widgets belong in the same widget target as your home screen widgets.

A2 and A3. You should not have to create a new target. Xcode 14's "update to recommended settings" in the Issue navigator can migrate your watch app and extension to a single watch app target. The app built out of this single target works on watchOS 7 and newer, so your customers with Apple Watch Series 3 can still install it.

A4. The complication code should be in the watch app target. That's where watchOS 7 and 8 will look for complications, and where watchOS 9 will look for old ClockKit complications for migration to their WidgetKit counterparts.

A5. If the code is part of your iOS widget target, then it sounds like it would make sense to put it in your watchOS widget target instead of your watchOS app target. However, if this code would be useful for your ClockKit complications when your app is installed on earlier watchOS versions, then it would make sense to add it to the app target as well.

A6 and A7. WKApplicationDelegate should work for every use case you previously used WKExtensionDelegate for.

Thanks for your response.

A1. Thanks. Makes sense.

A2/3. I started work on this version a few weeks ago, and definitely accepted the "update to recommended settings" option, but I do not have a single watch app target. I definitely have the targets I listed in my post.

Since starting the new version I've made little improvements here and there, adding new functionality, so I can't go back to an older backup of my code and start from there. Besides, I just opened the previous version with the latest Xcode 14b5, and I don't get "update to recommended settings" in the Issue Navigator.

What do I have to do with the "MyApp WatchKit" and "MyApp WatchKit Extension" targets to make them into one app? And, if I do manage to have them combined somehow, does the new target work with both the old Objective-C code and the new SwiftUI stuff I'll be using for the watchOS 9 stuff?

A4. Thanks.

A5. Sorry, you've confused me there. The utils code is currently in MyApp Widget (the iOS widget target), so I should put it in the "watchOS widget target" - which is that? A2/3 said the update would create a new single watch app target ("MyApp Watch App"?), and you said I don't need to add a new target?

A6/7. Are there any examples of how the WKApplicationDelegate looks? Any sample code anywhere?

Sometimes I do think Apple need some clearer documentation to show us where stuff should be put. At the moment, looking through WWDC videos to pick up on minutiae is a bit time-consuming.

Did you manage to migrate your extension and app into a signle watch app? If so any instructions would be amazing!

Hi @radox1, no I didn't manage to migrate them in the way you suggest. Xcode never offered me that option.

Here's how I've done it:

  1. Make sure your Home Screen and Lock Screen Widgets are in one iOS WidgetKit Extension target.
  2. Add a new watchOS WidgetKit Extension target and ensure you embed it in your Watch App. Put your complications in this new target.
  3. You can add code that's shared between targets into a folder at your project's root level, i.e. not within a specific target, and mark those files as available to the appropriate targets. For example, I have a shared functions Swift file that my Complications, Widgets and Watch App can use, and I put my localised strings into that folder, too.
  4. Use ConfigurationAppIntents to configure dynamic widgets and complications. The old way of using SiriKit is an annoying nightmare that Apple should never have forced onto us.