What you’ll learn
In this tutorial, you learn how to:- Set up a Bazel workspace and build files to declare a basic iOS application
- Use Bazel to build and run the app in an iOS simulator
- Use Bazel to build and run the app on an iOS device
- Create an Xcode project to continue working on your iOS application
Set up your environment
To get started, you’ll need to install Bazel and Xcode first.Install Bazel
Follow the installation instructions to install Bazel and its dependencies.Install Xcode
Download and install Xcode. Xcode contains the compilers, SDKs, and other tools required by Bazel to build Apple applications.Set up a workspace
A workspace is a directory that contains the source files for one or more software projects, as well as aMODULE.bazel file
and BUILD files that contain the instructions that Bazel uses to build the
software. The workspace may also contain symbolic links to output directories.
A workspace directory can be located anywhere on your filesystem and is denoted
by the presence of the MODULE.bazel file at its root.
Create a MODULE.bazel file
Start by creating a directory that will contain your workspace. Name itrules-apple-example, and set it as the current directory:
touch MODULE.bazel to create the file, then open it in your preferred text
editor. Add the following code snippet to the file:
bazel_deps are versions available on the
Bazel Central Registry:
apple_supportis responsible for registering Xcode and the platform SDKs as a Bazel toolchain.rules_appleprovides rules for packaging and running code on Apple platforms.rules_swiftprovides build rules and utilities for compiling and testing Swift code.
MODULE.bazel to
minimize incompatibility with newer releases of Bazel and Xcode. You can find
release information for each bazel_dep at
https://registry.bazel.build.
Add some Swift code
Create a new directory namedSources by executing mkdir Sources in your
terminal. This directory will contain a basic Swift source file for a simple iOS
application built in SwiftUI.
Run touch Sources/BazelApp.swift to create the file, then open it in your
preferred text editor. Add the following code snippet to the file:
Create a BUILD file
A Bazel workspace is made up of directories called packages. A package is a directory containing aBUILD file and can contain any number of sources or
subpackages. BUILD files contain specifications for
targets that you use Bazel to build, run, or test.
Run touch BUILD to create a file, then open it in your preferred text editor.
Then, add load statements to bring the rules you will
be using into scope:
swift_library target using the rule you just loaded:
lib, which can be referenced with the label
//:lib (or simply lib when running Bazel in the current directory). Also note
the glob function passed to the srcs
attribute, which will automatically add all files in Sources with the .swift
extension to the library.
Finally, you’re going to set up an ios_application target in much the same way.
You will be using this target to build the iOS application as an .ipa. Create
another directory next to Sources named Resources and create an Info.plist
in that directory. You may use
this example Info.plist
as a reference to populate your new Info.plist.
Then, below the swift_library, add the following code snippet to the file:
deps attribute references the lib target you declared
earlier. This is one of the ways Bazel expresses dependencies between targets.
Additionally, you may update the minimum_os_version attribute to whatever
minimum OS version you plan to support.
With that, you’re now ready to run your app!
Build and run the app
To build the app you just created, execute the following:.ipa targeting the
Simulator. Once it’s finished, you should see output similar to the following:
bazel-bin/iOSApp.ipa in the above output refers to one of the outputs of
the build command – namely the .ipa you just built with Bazel! This file is
also available in a subdirectory of bazel-out, under a path resembling
bazel-out/ios-sim_arm64-min17.0-applebin_ios-ios_sim_arm64-fastbuild-ST-b6790d224f6d/bin/iOSApp.ipa.
To run this app in a simulator, replace the build command above with run:
--@rules_apple//apple/build_settings:ios_simulator_device and
--@rules_apple//apple/build_settings:ios_simulator_version to control the run
destination used to launch the app.
Generate an Xcode project
rules_xcodeproj is the de-facto solution for generating Xcode projects for Bazel workspaces. These generated projects build with Bazel under-the-hood, giving you access to remote cache and other Bazel features within Xcode. First, in yourMODULE.bazel file, add the following code snippet:
BUILD file, add the following code snippet:
iOSApp target must be visible to it. Add the following code snippet to your
ios_application target:
BUILD file, add the following code snippet:
"device" to target_environments to build for devices from Xcode.
To generate the Xcode project, invoke this rule by executing the following
command:
iOSApp.xcodeproj in Xcode (for
example, with xed iOSApp.xcodeproj) to perform all the usual operations of
building and testing in Xcode.
Build and run the app on an iOS device
Building an iOS application to run on iOS devices requires some additional setup to ensure the app can be codesigned properly. The steps below will guide you through the process of integrating provisioning information with Bazel, but presumes that your Apple Developer account is set up to provision apps for your device, and your system has codesigning identities installed.- Go to the Apple Developer Center. Download the appropriate provisioning profile for your device.
-
Move your provisioning profile into your workspace directory.
Provisioning profiles do not contain sensitive signing information, so don’t
worry about them lingering on your system. If you’d rather not track them in
version control, add the path to a
.gitignore(if using Git). -
In your
BUILDfile, add the following code snippet to yourios_applicationtarget: -
Build the app for device:
--ios_multi_cpus
flag controls the architecture(s) of the built application. The default
unspecified value for ios_application is ios_sim_arm64 (or ios_x86_64 if
your host is an Intel Mac). A full list of possible options can be found
here.
Tip: rules_apple provides a pair of more advanced integrations for exposing
provisioning profiles to Bazel, with the
provisioning_profile_repository
and
local_provisioning_profile
rules.
Similar to the simulator, you can install and run the app on a physical iOS
device by replacing the build command above with run:
minimum_os_version of the
ios_application. You may use
--@rules_apple//apple/build_settings:ios_device to specify a particular device.
The flag accepts device UUIDs, ECIDs, UDIDs, serial numbers, names, or DNS names.
Tip: Use xcrun devicectl list devices to list the devices available to
devicectl.
Another method to install the app on a connected device is using Xcode. Launch
Xcode, and open the Devices and Simulators window under the Window menu
item. Select your connected device from the list, click the Add (plus sign)
button under Installed Apps, and select the .ipa you built. If your app
fails to install on your device, ensure that your provisioning profile is valid
and configured for your device. If your app fails to launch, the View Device
Logs button may provide more insight into why.