Closed Maximization closed 1 month ago
Hi, it should be possible but no-one has asked before now. I've updated the https://github.com/johnno1962/InjectionNext project (which is similar but a bit easier to work on) to support this if you want to try it out.
@johnno1962 Thank you for the quick reply! And making those changes. It's a bit unclear to me how I should enable hot reloading with SwiftUI. What I've done:
-Xlinker
and -interposable
to Other Linker FlagsI see a green injection icon in the menu bar but hot reloading seems to not be working. I think I'm missing .enableInjection()
and @ObserveInjection var forceRedraw
for each view. But when I add them I get compiler errors. Do I need to add HotSwiftUI as a package dependency too? Even though watchOS is not included as a platform platforms: [.macOS("10.15"), .iOS("13.0"), .tvOS("13.0")],
You're nearly there. You need the @ObserveInjection to force redraws and the .enableInjection() to make them reliable. You add either HotSwiftUI or Inject which contain these functions as a package dependency and @_exported import them. I didn't have a problem using the missing platform.
I tried using Inject without avail. I think Inject doesn't include the property wrapper and modifier for watchOS
Those errors go away when using HotSwiftUI, but one still remains
I'm using the Landmarks App from Apple's SwiftUI tutorial in case you want to test locally.
Sorry, I should have said use the branch main for the InjectionNext package. I haven't tagged it yet. The other problems you're seeing will probably relate to Inject/HotSwiftUI only being added to one target.
Ok so after ownloading the main branch zip of InjectionNext, building the app, and dragging to applications folder, I run the watchOS app and get the following error in the console:
"⚠️ Could not load injection bundle from /Applications/InjectionIII.app/Contents/Resources/iOSInjection.bundle. Have you downloaded the InjectionIII.app from either https://github.com/johnno1962/InjectionIII/releases or the Mac App Store? Build clean if you have been using the HotReloading Swift Package from github."
What am I doing wrong?
You don't need to update the InjectionNext.app but switch the branch on the package dependency of your app to be main. But it sounds like you might have a different problem where The InjectionNext package is not linked with your main bundle or watch extension.
I downloaded the project you mentioned and did the following: add https://github.com/johnno1962/InjectionNext, branch main as SPM dependency to target "WatchLandmarks Watch App", finally add -Xlinker -interopsable as "Other Linker flags" to that target. Run the app and see that it connects showing an orange state. View a source file in Xcode and use menu item "Prepare SwiftUI/Entire Project" in the InjectionNext.app on the menu bar to prepare the project and run it again. If you use the HotSwiftUI package make sure it is added to the same target as InjectionNext.
I removed everything and followed your steps and it magically worked! Don't know what went wrong previously. Thank you very much for taking the time to help me out.
Do you think it's possible to make the same changes to InjectionIII as well, or is it a ton of extra work? I'd like to use Cursor editor (AI integration) with the simulator side-by-side. I tried running the app with XCode and changing a file in Cursor, but changes aren't picked up unfortunately. Also happy to open a PR if you could point me in the right direction.
Yeah watchOS is a bit tricky as there are multiple targets. I've created a new release candidate of InjectionIII for wtachOS which should work if you also update HotSwiftUI to 1.1.11. It only works "standalone" where you don't run the app at all for various reasons. See how you get on.
@johnno1962 Thanks for providing a release for InjectionIII so quickly! I've started with a clean setup, followed the steps as before, and this time using HotSwiftUI 1.1.11. I'm getting this error after a view change:
💉 InjectionIII connected /Users/maxim/Code/Landmarks/Landmarks.xcodeproj
💉 Watching files under the directory /Users/maxim/Code/Landmarks
💉 Compiling /Users/maxim/Code/Landmarks/Landmarks/Views/Landmarks/LandmarkList.swift
💉 Loading .dylib ...
💉 ⚠️ dlopen() error: dlopen(/Users/maxim/Library/Developer/CoreSimulator/Devices/8B2A5033-A94E-42E7-9811-F6F44FB290CA/data/Containers/Data/Application/F7841159-7329-4ABD-AFA3-391044DEFFD4/tmp/eval101.dylib, 0x0002): tried: '/Users/maxim/Library/Developer/Xcode/DerivedData/Landmarks-dvsetkchrlunrfhbmumbcwfoswdv/Build/Products/Debug-watchsimulator/eval101.dylib' (no such file), '/Users/maxim/Library/Developer/Xcode/DerivedData/Landmarks-dvsetkchrlunrfhbmumbcwfoswdv/Build/Products/Debug-iphonesimulator/eval101.dylib' (no such file), '/Library/Developer/CoreSimulator/Volumes/watchOS_21T575/Library/Developer/CoreSimulator/Profiles/Runtimes/watchOS 10.5.simruntime/Contents/Resources/RuntimeRoot/usr/lib/system/introspection/eval101.dylib' (no such file), '/Library/Developer/CoreSimulator/Volumes/watchOS_21T575/Library/Developer/CoreSimulator/Profiles/Runtimes/watchOS 10.5.simruntime/Contents/Resources/RuntimeRoot/Users/maxim/Library/Developer/CoreSimulator/Devices/8B2A5033-A94E-42E7-9811-F6F44FB290CA/data/Containers/Data/Application/F7841159-7329-4ABD-AFA3-391044DEFFD4/tmp/eval101.dylib' (no such file), '/Users/maxim/Library/Developer/CoreSimulator/Devices/8B2A5033-A94E-42E7-9811-F6F44FB290CA/data/Containers/Data/Application/F7841159-7329-4ABD-AFA3-391044DEFFD4/tmp/eval101.dylib' (mach-o file (/Users/maxim/Library/Developer/CoreSimulator/Devices/8B2A5033-A94E-42E7-9811-F6F44FB290CA/data/Containers/Data/Application/F7841159-7329-4ABD-AFA3-391044DEFFD4/tmp/eval101.dylib), but incompatible platform (have 'iOS-sim', need 'watchOS-sim'))
💉 ⚠️ Clean build folder when switching platform
Cleaning the build folder didn't fix the issue. Something I can do on my end perhaps? Maybe this offers a clue: but incompatible platform (have 'iOS-sim', need 'watchOS-sim')
Hi, that isn't "standalone" injection if it is connecting. Quit the InjectionIII.app and let the bundle do all the work for you.
Ah I was trying to make it work with XCode first before doing it standalone. Just tried standalone and got a similar error:
💉 Unable to connect to InjectionIII app, falling back to standalone HotReloading.
💉 Standalone InjectionIII available for sources under ["/Users/maxim"]
💉 Using logs: /Users/maxim/Library/Developer/Xcode/DerivedData/Landmarks-dvsetkchrlunrfhbmumbcwfoswdv/Logs/Build/2DD2BE0F-C37D-49E3-8A28-EA96BFC5E574.xcactivitylog.
💉 Compiling /Users/maxim/Code/Landmarks/Landmarks/Views/Landmarks/LandmarkList.swift
💉 Loading .dylib ...
💉 ⚠️ dlopen() error: dlopen(/Users/maxim/Library/Developer/CoreSimulator/Devices/8B2A5033-A94E-42E7-9811-F6F44FB290CA/data/Containers/Data/Application/33F6EAEB-D61C-4DAC-953C-9B3BD1E85420/tmp/eval101.dylib, 0x0002): tried: '/Library/Developer/CoreSimulator/Volumes/watchOS_21T575/Library/Developer/CoreSimulator/Profiles/Runtimes/watchOS 10.5.simruntime/Contents/Resources/RuntimeRoot/Users/maxim/Library/Developer/CoreSimulator/Devices/8B2A5033-A94E-42E7-9811-F6F44FB290CA/data/Containers/Data/Application/33F6EAEB-D61C-4DAC-953C-9B3BD1E85420/tmp/eval101.dylib' (no such file), '/Users/maxim/Library/Developer/CoreSimulator/Devices/8B2A5033-A94E-42E7-9811-F6F44FB290CA/data/Containers/Data/Application/33F6EAEB-D61C-4DAC-953C-9B3BD1E85420/tmp/eval101.dylib' (mach-o file (/Users/maxim/Library/Developer/CoreSimulator/Devices/8B2A5033-A94E-42E7-9811-F6F44FB290CA/data/Containers/Data/Application/33F6EAEB-D61C-4DAC-953C-9B3BD1E85420/tmp/eval101.dylib), but incompatible platform (have 'iOS-sim', need 'watchOS-sim'))
💉 ⚠️ Clean build folder when switching platform
Standalone means separate from the app rather than Xcode, though it works without Xcode as well once you've used Xcode for the initial build. It's probably cached the wrong compile command now. Can you introduce a syntax error into the file you're injecting and inject it again. This will fail and should flush the cache, then remove the syntax error and try again.
It works! Amazing. Thank you so much 🙏
For anyone reading this in the future, here's how to make hot reload work with WatchOS in standalone mode (without Injection app):
@_exported import HotSwiftUI
.enableInjection()
modifier to the body and @ObserveInjection
property wrapper:
import SwiftUI
struct ContentView: View { var body: some View { // Some view { // ... // } .enableInjection() } }
@ObserveInjection var inject
}
6. Build & Run your project and you should see hot reloading work after you make a change in a view that has enabled injection
My setup is using [Cursor](https://www.cursor.com/) with [Swift lang](https://marketplace.visualstudio.com/items?itemName=sswg.swift-lang) and [SweetPad](https://marketplace.visualstudio.com/items?itemName=sweetpad.sweetpad) extensions working on a WatchOS companion app for an iOS app built with React Native.
A huge thanks to @johnno1962 for his incredible work in making hot reloading in Swift possible, and for his quick response and support in getting it to work for watchOS! 🙌
I've tried to make it work on WatchOS simulator without any luck. Can InjectionIII work with WatchOS simulator somehow?