David Chen | c4af828 | 2016-01-20 11:06:35 +0000 | [diff] [blame] | 1 | --- |
| 2 | layout: documentation |
| 3 | title: Tutorial - Build an iOS App |
| 4 | --- |
| 5 | |
Googler | 36a3fd2 | 2015-09-01 16:42:51 +0000 | [diff] [blame] | 6 | # Tutorial - Build an iOS App |
| 7 | |
| 8 | Like the [Android app](android-app.md) you built in the previous step, the iOS |
| 9 | app is a simple mobile app that communicates with the |
| 10 | [backend server](backend-server.md). |
| 11 | |
| 12 | Here, you'll do the following: |
| 13 | |
| 14 | * Review the source files for the app |
| 15 | * Create a `BUILD` file |
Dave MacLachlan | 8d24710 | 2016-02-21 18:55:25 +0000 | [diff] [blame] | 16 | * Build the app for the simulator |
Googler | 36a3fd2 | 2015-09-01 16:42:51 +0000 | [diff] [blame] | 17 | * Find the build outputs |
Dave MacLachlan | 8d24710 | 2016-02-21 18:55:25 +0000 | [diff] [blame] | 18 | * Run/Debug the app on the simulator |
| 19 | * Build the app for a device |
| 20 | * Install the app on a device |
Googler | 36a3fd2 | 2015-09-01 16:42:51 +0000 | [diff] [blame] | 21 | |
| 22 | Note that, unlike with the Android app, you don't have to modify your |
| 23 | `WORKSPACE` file to add iOS-specific external dependencies. |
| 24 | |
| 25 | If you're following the steps in this tutorial on Mac OS X, you can go ahead |
| 26 | and build the sample iOS app as described below. If you are on Linux, skip ahead |
| 27 | to the [next step](backend-server.md). |
| 28 | |
| 29 | ## Review the source files |
| 30 | |
| 31 | Let's take a look at the source files for the app. These are located in |
| 32 | `$WORKSPACE/ios-app/UrlGet`. Again, you're just looking at these files now to |
| 33 | become familiar with the structure of the app. You don't have to edit any of the |
| 34 | source files to complete this tutorial. |
| 35 | |
| 36 | ## Create a BUILD file |
| 37 | |
| 38 | At a command-line prompt, open your new `BUILD` file for editing: |
| 39 | |
| 40 | ```bash |
| 41 | $ vi $WORKSPACE/ios-app/BUILD |
| 42 | ``` |
| 43 | |
| 44 | ## Add an objc_library rule |
| 45 | |
Googler | 3251ebb | 2015-09-29 22:11:40 +0000 | [diff] [blame] | 46 | Bazel provides several build rules that you can use to build an app for the |
Googler | 36a3fd2 | 2015-09-01 16:42:51 +0000 | [diff] [blame] | 47 | iOS platform. For this tutorial, you'll first use the |
David Chen | c23d661 | 2015-11-02 22:56:13 +0000 | [diff] [blame] | 48 | [`objc_library`](/docs/be/objective-c.html#objc_library) rule to tell Bazel |
Googler | 36a3fd2 | 2015-09-01 16:42:51 +0000 | [diff] [blame] | 49 | how to build an |
| 50 | [static library](https://developer.apple.com/library/ios/technotes/iOSStaticLibraries/Introduction.html) |
| 51 | from the app source code and Xib files. Then you'll use the |
| 52 | `objc_binary` rule to tell it how to bundle the iOS application. (Note that |
| 53 | this is a minimal use case of the Objective-C rules in Bazel. For example, you |
| 54 | have to use the `ios_application` rule to build multi-architecture iOS |
| 55 | apps.) |
| 56 | |
| 57 | Add the following to your `BUILD` file: |
| 58 | |
| 59 | ```python |
| 60 | objc_library( |
| 61 | name = "UrlGetClasses", |
| 62 | srcs = [ |
| 63 | "UrlGet/AppDelegate.m", |
| 64 | "UrlGet/UrlGetViewController.m", |
| 65 | ], |
| 66 | hdrs = glob(["UrlGet/*.h"]), |
| 67 | xibs = ["UrlGet/UrlGetViewController.xib"], |
| 68 | ) |
| 69 | ``` |
| 70 | |
| 71 | Note the name of the rule, `UrlGetClasses`. |
| 72 | |
| 73 | ## Add an objc_binary rule |
| 74 | |
David Chen | c23d661 | 2015-11-02 22:56:13 +0000 | [diff] [blame] | 75 | The [`objc_binary`](/docs/be/objective-c.html#objc_binary) rule creates a |
Chris Parsons | 6afd416 | 2015-10-14 18:23:25 +0000 | [diff] [blame] | 76 | binary to be bundled in the application. |
Googler | 36a3fd2 | 2015-09-01 16:42:51 +0000 | [diff] [blame] | 77 | |
| 78 | Add the following to your `BUILD` file: |
| 79 | |
| 80 | ```python |
| 81 | objc_binary( |
Chris Parsons | 6afd416 | 2015-10-14 18:23:25 +0000 | [diff] [blame] | 82 | name = "ios-app-binary", |
Googler | 36a3fd2 | 2015-09-01 16:42:51 +0000 | [diff] [blame] | 83 | srcs = [ |
| 84 | "UrlGet/main.m", |
| 85 | ], |
| 86 | deps = [ |
| 87 | ":UrlGetClasses", |
| 88 | ], |
Chris Parsons | 6afd416 | 2015-10-14 18:23:25 +0000 | [diff] [blame] | 89 | ) |
| 90 | |
| 91 | ``` |
| 92 | Note how the `deps` attribute references the output of the |
| 93 | `UrlGetClasses` rule you added to the `BUILD` file above. |
| 94 | |
| 95 | ## Add an ios_application rule |
| 96 | |
David Chen | c23d661 | 2015-11-02 22:56:13 +0000 | [diff] [blame] | 97 | The [`ios_application`](/docs/be/objective-c.html#ios_application) rule |
Chris Parsons | 6afd416 | 2015-10-14 18:23:25 +0000 | [diff] [blame] | 98 | creates the bundled `.ipa` archive file for the application and also generates |
| 99 | an Xcode project file. |
| 100 | |
| 101 | Add the following to your `BUILD` file: |
| 102 | |
| 103 | ```python |
| 104 | ios_application( |
| 105 | name = "ios-app", |
| 106 | binary = ":ios-app-binary", |
Googler | 36a3fd2 | 2015-09-01 16:42:51 +0000 | [diff] [blame] | 107 | infoplist = "UrlGet/UrlGet-Info.plist", |
| 108 | ) |
| 109 | ``` |
| 110 | |
| 111 | Now, save and close the file. You can compare your `BUILD` file to the |
| 112 | [completed example](https://github.com/bazelbuild/examples/blob/master/tutorial/ios-app/BUILD) |
| 113 | in the `master` branch of the GitHub repo. |
| 114 | |
Dave MacLachlan | 8d24710 | 2016-02-21 18:55:25 +0000 | [diff] [blame] | 115 | ## Build the app for the simulator |
Googler | 36a3fd2 | 2015-09-01 16:42:51 +0000 | [diff] [blame] | 116 | |
| 117 | Make sure that your current working directory is inside your Bazel workspace: |
| 118 | |
| 119 | ```bash |
| 120 | $ cd $WORKSPACE |
| 121 | ``` |
| 122 | |
| 123 | Now, enter the following to build the sample app: |
| 124 | |
| 125 | ```bash |
| 126 | $ bazel build //ios-app:ios-app |
| 127 | ``` |
| 128 | |
| 129 | Bazel now launches and builds the sample app. During the build process, its |
| 130 | output will appear similar to the following: |
| 131 | |
| 132 | ```bash |
| 133 | INFO: Found 1 target... |
| 134 | Target //ios-app:ios-app up-to-date: |
Googler | 36a3fd2 | 2015-09-01 16:42:51 +0000 | [diff] [blame] | 135 | bazel-bin/ios-app/ios-app.ipa |
| 136 | bazel-bin/ios-app/ios-app.xcodeproj/project.pbxproj |
| 137 | INFO: Elapsed time: 3.765s, Critical Path: 3.44s |
| 138 | ``` |
| 139 | |
| 140 | ## Find the build outputs |
| 141 | |
| 142 | The `.ipa` file and other outputs are located in the |
| 143 | `$WORKSPACE/bazel-bin/ios-app` directory. |
| 144 | |
Dave MacLachlan | 8d24710 | 2016-02-21 18:55:25 +0000 | [diff] [blame] | 145 | ## Run/Debug the app on the simulator |
Googler | 36a3fd2 | 2015-09-01 16:42:51 +0000 | [diff] [blame] | 146 | |
| 147 | You can now run the app from Xcode using the iOS Simulator. To run the app, |
| 148 | open the project directory `$WORKSPACE/bazel-bin/ios-app/ios-app.xcodeproj` in |
| 149 | Xcode, choose an iOS Simulator as the runtime scheme and then click the **Run** |
| 150 | button. |
| 151 | |
| 152 | **Note:** If you change anything about the project file set in Xcode (for |
| 153 | example, if you add or remove a file, or add or change a dependency), you must |
| 154 | rebuild the app using Bazel and then re-open the project. |
| 155 | |
Dave MacLachlan | 8d24710 | 2016-02-21 18:55:25 +0000 | [diff] [blame] | 156 | ## Build the app for a device |
| 157 | |
| 158 | You need to set up bazel so that it can find the appropriate provisioning |
| 159 | profile for the device you want to build for. To set up the "default" |
| 160 | provisioning profile for all bazel builds: |
| 161 | |
| 162 | 1. Go to [Apple Profiles](https://developer.apple.com/account/ios/profile/profileList.action) |
| 163 | and download the appropriate provisioning profile for your device. |
| 164 | If this is confusing, please refer to [Apple's documentation](https://developer.apple.com/library/ios/documentation/IDEs/Conceptual/AppDistributionGuide/MaintainingProfiles/MaintainingProfiles.html). |
| 165 | 1. Move your profile into `$WORKSPACE/tools/objc`. |
| 166 | 1. Optional - You may want to add your profile to your `.gitignore`. |
| 167 | 1. Edit `$WORKSPACE/tools/objc/BUILD` and add: |
| 168 | |
| 169 | ```python |
| 170 | filegroup( |
| 171 | name = "default_provisioning_profile", |
| 172 | srcs = ["<NAME OF YOUR PROFILE>.mobileprovision"], |
| 173 | ) |
| 174 | ``` |
| 175 | |
| 176 | Now you should be able to build the app for your device: |
| 177 | |
| 178 | ```bash |
| 179 | $ bazel build //ios-app:ios-app --ios_multi_cpus=armv7,arm64 |
| 180 | ``` |
| 181 | |
| 182 | This will build the app "fat". If you would prefer just to build for |
| 183 | your specific device architecture you can designate a single architecture. |
| 184 | |
| 185 | If you would like to select a specific Xcode version/SDK version you can do so |
| 186 | with the `--xcode_version=7.2 --ios_sdk_version=9.2` options. Make sure that |
| 187 | the Xcode version that you select has the appropriate SDK installed in it. |
| 188 | |
| 189 | If you would like to specify a minimum version of iOS to run against, you can |
| 190 | do so with the `--ios_minimum_os=7.0` option. |
| 191 | |
| 192 | ## Install the app on a device |
| 193 | |
| 194 | The easiest way to install the app on the device is to launch Xcode and use the |
| 195 | `Windows > Devices` command. Select your plugged in device from the list on the |
| 196 | left, and then add the app by clicking on the "plus" sign under installed apps |
| 197 | and selecting the `.ipa` that you built. |
| 198 | |
| 199 | If your app does not launch, please make sure that your device was on your |
| 200 | provisioning profile. The `View Device Logs` button on the `Devices` screen in |
| 201 | Xcode may provide other information as to what has gone wrong. |
| 202 | |
Googler | 36a3fd2 | 2015-09-01 16:42:51 +0000 | [diff] [blame] | 203 | ## What's next |
| 204 | |
| 205 | The next step is to build a [backend server](backend-server.md) for the two |
| 206 | mobile apps you built in this tutorial. |