This project demonstrates how to build an iOS SwiftUI application using Bazel with InjectionLite integration for hot reloading during development. You can run this project either from the command line using Bazel directly, or generate an Xcode project for development in Xcode.
-
Using Homebrew (Recommended):
brew install bazel
-
Using the Bazel installer:
- Download from Bazel releases
- Follow the installation instructions for macOS
-
Verify installation:
bazel version
- Install Xcode from the Mac App Store
- Install Xcode Command Line Tools:
xcode-select --install
cd InjectionLiteSampleBazelProjectmake update-swift-package-managerNote: bazel build/run invokes the project wrapper internally; you don't need to call ./tools/bazel directly.
bazel build //:InjectionLiteSampleBazelProjectAppbazel run //:InjectionLiteSampleBazelProjectApp- Build and run the app:
bazel run //:InjectionLiteSampleBazelProjectApp - The wrapper will auto-launch
tools/injection/InjectionNext.appif needed and register the workspace for watching - Make changes to Swift files (e.g.,
ContentView.swift) and save - InjectionLite will hot-reload changes in the running app (simulator)
bazel run //:InjectionLiteSampleProjectThis will generate an Xcode project file: InjectionLiteSampleBazelProject.xcodeproj
open InjectionLiteSampleBazelProject.xcodeproj- Open the generated Xcode project
- Select your target device/simulator in Xcode
- Build and run using Xcode (⌘+R)
- Make changes to Swift files directly in Xcode
- Hot reload is NOT supported when running from Xcode in this project
- Rebuild to see changes when using Xcode
- Full Xcode IDE features (autocomplete, debugging, etc.)
- Integrated Interface Builder (if using Storyboards)
- Xcode's built-in iOS Simulator management
- Native Xcode debugging experience
- Access to Xcode's profiling tools
BUILD- Bazel build configuration defining iOS app target and Xcode project generationMODULE.bazel- Bazel module configuration with dependencies (includes rules_xcodeproj)Package.swift- Swift Package Manager configuration for InjectionLitetools/bazel- Bazel wrapper that auto-starts InjectionNext and registers the workspace when running iOS app targetstools/injection/InjectionNext.app- Bundled InjectionNext app used for hot reloadtools/injection/notify-watch.py- Helper to notify InjectionNext of the project rootInjectionLiteSampleBazelProject/- Source code directoryInjectionLiteSampleBazelProjectApp.swift- Main app entry pointContentView.swift- SwiftUI view with InjectionLite integrationInfo.plist- iOS app configuration
This project includes InjectionLite for hot reloading:
- Linker flags:
-interposableflag is configured in the BUILD file - Dependencies: InjectionLite is imported from the Swift package
- GUI App:
InjectionNext.appis bundled attools/injection/InjectionNext.app - Auto start: Using
bazel runauto-starts InjectionNext (if not running) and registers the workspace for hot reload - Usage: Save any Swift file while running in debug mode to see changes
- Support: Hot reload is only supported via command-line
bazel run; Xcode builds do not support InjectionNext in this project
- Port: The wrapper uses port
8887by default. Override withINJECTION_PORT, e.g.INJECTION_PORT=8888 bazel run //:InjectionLiteSampleBazelProjectApp.
- Ensure Xcode Command Line Tools are installed:
xcode-select --install - Clean Bazel cache:
bazel clean --expunge - Update dependencies:
make update-swift-package-manager
If you encounter errors like:
undeclared inclusion(s) in rulemissing dependency declarations for the following files- Header files not found
- Swift package dependency resolution failures
Solution:
bazel clean --expunge
make update-swift-package-manager
bazel build //:InjectionLiteSampleBazelProjectAppThe --expunge flag completely removes all build artifacts and cached dependencies, forcing a fresh rebuild that often resolves dependency and header issues.
If you see errors about targets not being visible or excluded from builds:
- Add
visibility = ["//visibility:public"]to your targets in BUILD file - Run
bazel clean --expungeto clear any cached visibility rules - Regenerate dependencies:
make update-swift-package-manager
If you encounter permission errors for reading or writing files:
- Check file permissions:
ls -la - Ensure your user has read/write access to the project directory
- Run
bazel clean --expungeto clear any corrupted cache files - On macOS, you may need to grant Terminal/IDE access in System Preferences > Security & Privacy
- If Xcode project generation fails, try:
bazel clean --expunge - Regenerate the project:
bazel run //:InjectionLiteSampleProject - Make sure rules_xcodeproj is properly configured in MODULE.bazel
- Make sure you have iOS Simulator installed with Xcode
- Check available simulators:
xcrun simctl list devices
- Ensure you're running in debug mode
- Check that the
-interposablelinker flag is present in BUILD file - Prefer iOS Simulator over physical devices
- Hot reload is not supported when running from Xcode; use
bazel run //:InjectionLiteSampleBazelProjectApp - If you changed the port, ensure
INJECTION_PORTmatchesnotify-watch.pysecond arg
When in doubt, try this sequence:
bazel clean --expunge- Completely clean all Bazel artifactsmake update-swift-package-manager- Update Swift package dependenciesbazel build //:InjectionLiteSampleBazelProjectApp- Rebuild from scratch- If using Xcode:
bazel run //:InjectionLiteSampleProject- Regenerate Xcode project
To modify this sample for your own project:
- Update the
bundle_idinBUILDfile - Change the
nameinMODULE.bazel - Update Swift package dependencies in
Package.swift - Modify source files in the
InjectionLiteSampleBazelProject/directory