|  | Project: /_project.yaml | 
|  | Book: /_book.yaml | 
|  |  | 
|  | # Bazel Tutorial: Build an iOS App | 
|  |  | 
|  | This tutorial covers how to build a simple iOS app using Bazel. | 
|  |  | 
|  | ## What you'll learn | 
|  |  | 
|  | In this tutorial, you learn how to: | 
|  |  | 
|  | *   Set up the environment by installing Bazel and Xcode, and downloading the | 
|  | sample project | 
|  | *   Set up a Bazel [workspace](/concepts/build-ref#workspace) that contained the source code | 
|  | for the app and a `WORKSPACE` file that identifies the top level of the | 
|  | workspace directory | 
|  | *   Update the `WORKSPACE` file to contain references to the required | 
|  | external dependencies | 
|  | *   Create a `BUILD` file | 
|  | *   Run Bazel to build the app for the simulator and an iOS device | 
|  | *   Run the app in the simulator and on an iOS device | 
|  |  | 
|  | ## Set up your environment | 
|  |  | 
|  | To get started, install Bazel and Xcode, and get the sample project. | 
|  |  | 
|  | ### Install Bazel | 
|  |  | 
|  | Follow the [installation instructions](/install/) to install Bazel and | 
|  | its dependencies. | 
|  |  | 
|  | ### Install Xcode | 
|  |  | 
|  | Download and install [Xcode](https://developer.apple.com/xcode/downloads/){: .external}. | 
|  | Xcode contains the compilers, SDKs, and other tools required by Bazel to build | 
|  | Apple applications. | 
|  |  | 
|  | ### Get the sample project | 
|  |  | 
|  | You also need to get the sample project for the tutorial from GitHub. The GitHub | 
|  | repo has two branches: `source-only` and `main`. The `source-only` branch | 
|  | contains the source files for the project only. You'll use the files in this | 
|  | branch in this tutorial. The `main` branch contains both the source files | 
|  | and completed Bazel `WORKSPACE` and `BUILD` files. You can use the files in this | 
|  | branch to check your work when you've completed the tutorial steps. | 
|  |  | 
|  | Enter the following at the command line to get the files in the `source-only` | 
|  | branch: | 
|  |  | 
|  | ```bash | 
|  | cd $HOME | 
|  | git clone -b source-only https://github.com/bazelbuild/examples | 
|  | ``` | 
|  |  | 
|  | The `git clone` command creates a directory named `$HOME/examples/`. This | 
|  | directory contains several sample projects for Bazel. The project files for this | 
|  | tutorial are in `$HOME/examples/tutorial/ios-app`. | 
|  |  | 
|  | ## Set up a workspace | 
|  |  | 
|  | A [workspace](/concepts/build-ref#workspace) is a directory that contains the | 
|  | source files for one or more software projects, as well as a `WORKSPACE` 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 `WORKSPACE` file at its root. In this tutorial, your | 
|  | workspace directory is `$HOME/examples/tutorial/`, which contains the sample | 
|  | project files you cloned from the GitHub repo in the previous step. | 
|  |  | 
|  | Note: Bazel itself doesn't impose any requirements for organizing source | 
|  | files in your workspace. The sample source files in this tutorial are organized | 
|  | according to conventions for the target platform. | 
|  |  | 
|  | For your convenience, set the `$WORKSPACE` environment variable now to refer to | 
|  | your workspace directory. At the command line, enter: | 
|  |  | 
|  | ```bash | 
|  | export WORKSPACE=$HOME/examples/tutorial | 
|  | ``` | 
|  |  | 
|  | ### Create a WORKSPACE file | 
|  |  | 
|  | Every workspace must have a text file named `WORKSPACE` located in the top-level | 
|  | workspace directory. This file may be empty or it may contain references | 
|  | to [external dependencies](/docs/external) required to build the | 
|  | software. | 
|  |  | 
|  | For now, you'll create an empty `WORKSPACE` file, which simply serves to | 
|  | identify the workspace directory. In later steps, you'll update the file to add | 
|  | external dependency information. | 
|  |  | 
|  | Enter the following at the command line: | 
|  |  | 
|  | ```bash | 
|  | touch $WORKSPACE/WORKSPACE | 
|  | open -a Xcode $WORKSPACE/WORKSPACE | 
|  | ``` | 
|  |  | 
|  | This creates and opens the empty `WORKSPACE` file. | 
|  |  | 
|  | ### Update the WORKSPACE file | 
|  |  | 
|  | To build applications for Apple devices, Bazel needs to pull the latest | 
|  | [Apple build rules](https://github.com/bazelbuild/rules_apple){: .external} | 
|  | from its GitHub repository. To enable this, add the following | 
|  | [`git_repository`](/reference/be/workspace#git_repository) | 
|  | rules to your `WORKSPACE` file: | 
|  |  | 
|  | ```python | 
|  | load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository") | 
|  |  | 
|  | git_repository( | 
|  | name = "build_bazel_rules_apple", | 
|  | remote = "https://github.com/bazelbuild/rules_apple.git", | 
|  | tag = "0.19.0", | 
|  | ) | 
|  |  | 
|  | git_repository( | 
|  | name = "build_bazel_rules_swift", | 
|  | remote = "https://github.com/bazelbuild/rules_swift.git", | 
|  | tag = "0.13.0", | 
|  | ) | 
|  |  | 
|  | git_repository( | 
|  | name = "build_bazel_apple_support", | 
|  | remote = "https://github.com/bazelbuild/apple_support.git", | 
|  | tag = "0.7.2", | 
|  | ) | 
|  |  | 
|  | git_repository( | 
|  | name = "bazel_skylib", | 
|  | remote = "https://github.com/bazelbuild/bazel-skylib.git", | 
|  | tag = "0.9.0", | 
|  | ) | 
|  | ``` | 
|  |  | 
|  | Note: "Always use the | 
|  | [latest version of the build_apple rules](https://github.com/bazelbuild/rules_apple/releases){: .external} | 
|  | in the `tag` attribute. Make sure to check the latest dependencies required in | 
|  | `rules_apple`'s [project](https://github.com/bazelbuild/rules_apple){: .external}." | 
|  |  | 
|  | Note: You **must** set the value of the `name` attribute in the | 
|  | `git_repository` rule to `build_bazel_rules_apple` or the build will fail. | 
|  |  | 
|  | ## Review the source files | 
|  |  | 
|  | Take a look at the source files for the app located in | 
|  | `$WORKSPACE/ios-app/UrlGet`. Again, you're just looking at these files now to | 
|  | become familiar with the structure of the app. You don't have to edit any of the | 
|  | source files to complete this tutorial. | 
|  |  | 
|  | ## Create a BUILD file | 
|  |  | 
|  | At a command-line prompt, open a new `BUILD` file for editing: | 
|  |  | 
|  | ```bash | 
|  | touch $WORKSPACE/ios-app/BUILD | 
|  | open -a Xcode $WORKSPACE/ios-app/BUILD | 
|  | ``` | 
|  |  | 
|  | ### Add the rule load statement | 
|  |  | 
|  | To build iOS targets, Bazel needs to load build rules from its GitHub repository | 
|  | whenever the build runs. To make these rules available to your project, add the | 
|  | following load statement to the beginning of your `BUILD` file: | 
|  |  | 
|  | ``` | 
|  | load("@build_bazel_rules_apple//apple:ios.bzl", "ios_application") | 
|  | ``` | 
|  |  | 
|  | You only need to load the `ios_application` rule because the `objc_library` | 
|  | rule is built into the Bazel package. | 
|  |  | 
|  | ### Add an objc_library rule | 
|  |  | 
|  | Bazel provides several build rules that you can use to build an app for the | 
|  | iOS platform. For this tutorial, you'll first use the | 
|  | [`objc_library`](/reference/be/objective-c#objc_library) rule to tell Bazel | 
|  | how to build a static library from the app source code and Xib files. Then | 
|  | you'll use the | 
|  | [`ios_application`](https://github.com/bazelbuild/rules_apple/tree/main/doc){: .external} | 
|  | rule to tell it how to build the application binary and the `.ipa` bundle. | 
|  |  | 
|  | Note: This tutorial presents a minimal use case of the Objective-C rules in | 
|  | Bazel. For example, you have to use the `ios_application` rule to build | 
|  | multi-architecture iOS apps. | 
|  |  | 
|  | Add the following to your `BUILD` file: | 
|  |  | 
|  | ```python | 
|  | objc_library( | 
|  | name = "UrlGetClasses", | 
|  | srcs = [ | 
|  | "UrlGet/AppDelegate.m", | 
|  | "UrlGet/UrlGetViewController.m", | 
|  | "UrlGet/main.m", | 
|  | ], | 
|  | hdrs = glob(["UrlGet/*.h"]), | 
|  | data = ["UrlGet/UrlGetViewController.xib"], | 
|  | ) | 
|  | ``` | 
|  |  | 
|  | Note the name of the rule, `UrlGetClasses`. | 
|  |  | 
|  | ### Add an ios_application rule | 
|  |  | 
|  | The | 
|  | [`ios_application`](https://github.com/bazelbuild/rules_apple/tree/main/doc){: .external} | 
|  | rule builds the application binary and creates the `.ipa` bundle file. | 
|  |  | 
|  | Add the following to your `BUILD` file: | 
|  |  | 
|  | ```python | 
|  | ios_application( | 
|  | name = "ios-app", | 
|  | bundle_id = "Google.UrlGet", | 
|  | families = [ | 
|  | "iphone", | 
|  | "ipad", | 
|  | ], | 
|  | minimum_os_version = "9.0", | 
|  | infoplists = [":UrlGet/UrlGet-Info.plist"], | 
|  | visibility = ["//visibility:public"], | 
|  | deps = [":UrlGetClasses"], | 
|  | ) | 
|  | ``` | 
|  |  | 
|  | Note: Please update the `minimum_os_version` attribute to the minimum | 
|  | version of iOS that you plan to support. | 
|  |  | 
|  | Note how the `deps` attribute references the output of the `UrlGetClasses` rule | 
|  | you added to the `BUILD` file above. | 
|  |  | 
|  | Now, save and close the file. You can compare your `BUILD` file to the | 
|  | [completed example](https://github.com/bazelbuild/examples/blob/main/tutorial/ios-app/BUILD){: .external} | 
|  | in the `main` branch of the GitHub repo. | 
|  |  | 
|  | ## Build and deploy the app | 
|  |  | 
|  | You are now ready to build your app and deploy it to a simulator and onto an | 
|  | iOS device. | 
|  |  | 
|  | Note: The app launches standalone but requires a backend server in order to | 
|  | produce output. See the README file in the sample project directory to find out | 
|  | how to build the backend server. | 
|  |  | 
|  | The built app is located in the `$WORKSPACE/bazel-bin` directory. | 
|  |  | 
|  | Completed `WORKSPACE` and `BUILD` files for this tutorial are located in the | 
|  | [main branch](https://github.com/bazelbuild/examples/tree/main/tutorial){: .external} | 
|  | of the GitHub repo. You can compare your work to the completed files for | 
|  | additional help or troubleshooting. | 
|  |  | 
|  | ### Build the app for the simulator | 
|  |  | 
|  | Make sure that your current working directory is inside your Bazel workspace: | 
|  |  | 
|  | ```bash | 
|  | cd $WORKSPACE | 
|  | ``` | 
|  |  | 
|  | Now, enter the following to build the sample app: | 
|  |  | 
|  | ```bash | 
|  | bazel build //ios-app:ios-app | 
|  | ``` | 
|  |  | 
|  | Bazel launches and builds the sample app. During the build process, its | 
|  | output will appear similar to the following: | 
|  |  | 
|  | ```bash | 
|  | INFO: Found 1 target... | 
|  | Target //ios-app:ios-app up-to-date: | 
|  | bazel-bin/ios-app/ios-app.ipa | 
|  | INFO: Elapsed time: 0.565s, Critical Path: 0.44s | 
|  | ``` | 
|  |  | 
|  | ### Find the build outputs | 
|  |  | 
|  | The `.ipa` file and other outputs are located in the | 
|  | `$WORKSPACE/bazel-bin/ios-app` directory. | 
|  |  | 
|  | ### Run and debug the app in the simulator | 
|  |  | 
|  | You can now run the app from Xcode using the iOS Simulator. First, | 
|  | [generate an Xcode project using Tulsi](http://tulsi.bazel.build/){: .external}. | 
|  |  | 
|  | Then, open the project in Xcode, choose an iOS Simulator as the runtime scheme, | 
|  | and click **Run**. | 
|  |  | 
|  | Note: If you modify any project files in Xcode (for example, if you add or | 
|  | remove a file, or add or change a dependency), you must rebuild the app using | 
|  | Bazel, re-generate the Xcode project in Tulsi, and then re-open the project in | 
|  | Xcode. | 
|  |  | 
|  | ### Build the app for a device | 
|  |  | 
|  | To build your app so that it installs and launches on an iOS device, Bazel needs | 
|  | the appropriate provisioning profile for that device model. Do the following: | 
|  |  | 
|  | 1. Go to your [Apple Developer Account](https://developer.apple.com/account){: .external} | 
|  | and download the appropriate provisioning profile for your device. See | 
|  | [Apple's documentation](https://developer.apple.com/library/ios/documentation/IDEs/Conceptual/AppDistributionGuide/MaintainingProfiles/MaintainingProfiles.html){: .external} | 
|  | for more information. | 
|  |  | 
|  | 2. Move your profile into `$WORKSPACE`. | 
|  |  | 
|  | 3. (Optional) Add your profile to your `.gitignore` file. | 
|  |  | 
|  | 4. Add the following line to the `ios_application` target in your `BUILD` file: | 
|  |  | 
|  | ```python | 
|  | provisioning_profile = "<your_profile_name>.mobileprovision", | 
|  | ``` | 
|  |  | 
|  | Note: Ensure the profile is correct so that the app can be installed on a | 
|  | device. | 
|  |  | 
|  | Now build the app for your device: | 
|  |  | 
|  | ```bash | 
|  | bazel build //ios-app:ios-app --ios_multi_cpus=armv7,arm64 | 
|  | ``` | 
|  |  | 
|  | This builds the app as a fat binary. To build for a specific device | 
|  | architecture, designate it in the build options. | 
|  |  | 
|  | To build for a specific Xcode version, use the `--xcode_version` option. To | 
|  | build for a specific SDK version, use the `--ios_sdk_version` option. The | 
|  | `--xcode_version` option is sufficient in most scenarios. | 
|  |  | 
|  | To specify a minimum required iOS version, add the `minimum_os_version` | 
|  | parameter to the `ios_application` build rule in your `BUILD` file. | 
|  |  | 
|  | You can also use | 
|  | [Tulsi](http://tulsi.bazel.build/docs/gettingstarted.html){: .external} to | 
|  | build your app using a GUI rather than the command line. | 
|  |  | 
|  | ### Install the app on a device | 
|  |  | 
|  | The easiest way to install the app on the device is to launch Xcode and use the | 
|  | `Windows > Devices` command. Select your plugged-in device from the list on the | 
|  | left, then add the app by clicking the **Add** (plus sign) button under | 
|  | "Installed Apps" and selecting the `.ipa` file that you built. | 
|  |  | 
|  | If your app fails to install on your device, ensure that you are specifying the | 
|  | correct provisioning profile in your `BUILD` file (step 4 in the previous | 
|  | section). | 
|  |  | 
|  | If your app fails to launch, make sure that your device is part of your | 
|  | provisioning profile. The `View Device Logs` button on the `Devices` screen in | 
|  | Xcode may provide other information as to what has gone wrong. | 
|  |  | 
|  | ## Further reading | 
|  |  | 
|  | For more details, see | 
|  | [main branch](https://github.com/bazelbuild/examples/tree/main/tutorial){: .external} | 
|  | of the GitHub repo. | 
|  |  |