summaryrefslogtreecommitdiff
path: root/doc/ci/mobile_devops.md
blob: 175a63dc3b91603418eb916134a4181787006f49 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
---
stage: none
group: unassigned
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
type: reference
---

# Mobile DevOps (Experimental)

Use GitLab Mobile DevOps to quickly build, sign, and release native and cross-platform mobile apps
for Android and iOS using GitLab CI/CD. Mobile DevOps is an experimental feature developed by
[GitLab Incubation Engineering](https://about.gitlab.com/handbook/engineering/incubation/).

Mobile DevOps is still in development, but you can:

- [Request a feature](https://gitlab.com/gitlab-org/incubation-engineering/mobile-devops/feedback/-/issues/new?issuable_template=feature_request).
- [Report a bug](https://gitlab.com/gitlab-org/incubation-engineering/mobile-devops/feedback/-/issues/new?issuable_template=report_bug).
- [Share feedback](https://gitlab.com/gitlab-org/incubation-engineering/mobile-devops/feedback/-/issues/new?issuable_template=general_feedback).

## Build environments

Get started quickly by using [GitLab.com SaaS runners](../ci/runners/index.md),
or set up [self-managed runners](https://docs.gitlab.com/runner/#use-self-managed-runners)
for complete control over the build environment.

### Android build environments

Set up an Android build environment by selecting an appropriate Docker image
and adding it to your `.gitlab-ci.yml` file. [Fabernovel](https://hub.docker.com/r/fabernovel/android/tags)
provides a variety of supported Android versions.

For example:

```yaml
test:
  image: fabernovel/android:api-33-v1.7.0
  stage: test
  script:
    - fastlane test
```

### iOS build environments

GitLab SaaS runners on macOS are currently available in beta. Follow the [instructions to request access](../ci/runners/saas/macos_saas_runner.md#access-request-process)
for your project.

After you are granted access to the beta macOS runners, [choose an image](../ci/runners/saas/macos/environment.md#available-images)
and add it to your `.gitlab-ci.yml` file.

For example:

```yaml
test:
  image: macos-12-xcode-14
  stage: test
  script:
    - fastlane test
  tags:
    - saas-macos-medium-m1
```

## Code signing

All Android and iOS apps must be securely signed before being distributed through
the various app stores. Signing ensures that applications haven't been tampered with
before reaching a user's device.

With [project-level secure files](secure_files/index.md), you can store the following
in GitLab, so that they can be used to securely sign apps in CI/CD builds:

- Keystores
- Provision profiles
- Signing certificates

<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
For an overview, see [Project-level secure files demo](https://youtu.be/O7FbJu3H2YM).

### Code signing Android projects with fastlane & Gradle

To set up code signing for Android:

1. Upload your keystore and keystore properties files to project-level secure files.
1. Update the Gradle configuration to use those files in the build.

<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
For an overview, see [How to build and release an Android app to Google Play with GitLab](https://youtu.be/u8yC8W2k85U).

#### Create a keystore

Run the following command to generate a keystore file if you don't already have one:

```shell
keytool -genkey -v -keystore release-keystore.jks -storepass password -alias release -keypass password -keyalg RSA -keysize 2048 -validity 10000 
```

Next, put the keystore configuration in a file called `release-keystore.properties`,
which should look similar to this example:

```plaintext
storeFile=.secure_files/release-keystore.jks
keyAlias=release
keyPassword=password
storePassword=password
```

After these files are created:

- [Upload them as Secure Files](secure_files/index.md) in the GitLab project
  so they can be used in CI/CD jobs.
- Add both files to your `.gitignore` file so they aren't committed to version control.

#### Configure Gradle

The next step is to configure Gradle to use the newly created keystore. In the app's `build.gradle` file:

1. Immediately after the plugins section, add:

   ```gradle
   def keystoreProperties = new Properties()
   def keystorePropertiesFile = rootProject.file('.secure_files/release-keystore.properties')
   if (keystorePropertiesFile.exists()) {
     keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
   }
   ```

1. Anywhere within the `android` block, add:

   ```gradle
   signingConfigs {
     release {
       keyAlias keystoreProperties['keyAlias']
       keyPassword keystoreProperties['keyPassword']
       storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
       storePassword keystoreProperties['storePassword']
     }
   }
   ```

1. Add the `signingConfig` to the release build type:

   ```gradle
   signingConfig signingConfigs.release
   ```

With this configuration in place, you can use fastlane to build & sign the app
with the files stored in secure files.

For example:

- Sample `fastlane/Fastfile` file:

  ```ruby
  default_platform(:android)

  platform :android do
    desc "Create and sign a new build"
    lane :build do
      gradle(tasks: ["clean", "assembleRelease", "bundleRelease"])
    end
  end
  ```

- Sample `.gitlab-ci.yml` file:

  ```yaml
  build:
    image: fabernovel/android:api-33-v1.7.0
    stage: build
    script:
      - apt update -y && apt install -y curl
      - curl --silent "https://gitlab.com/gitlab-org/incubation-engineering/mobile-devops/download-secure-files/-/raw/main/installer" | bash
      - fastlane build
  ```

### Code sign iOS projects with fastlane

To set up code signing for iOS, you must:

1. Install fastlane locally so you can upload your signing certificates to GitLab.
1. Configure the build to use those files.

<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
For an overview, see [How to build and release an iOS app to Test Flight with GitLab](https://youtu.be/Ar8IsBgP1as).

#### Initialize fastlane

With fastlane installed, start by running:

```shell
fastlane init
```

This command creates a `fastlane` folder in the project with an `Appfile` and a stubbed-out `fastfile`.
This process asks you for login credentials to App Store Connect
to generate an app identifier and App Store app if they don't already exist.

The next step sets up fastlane match to manage code signing files for the project.
Run the following command to generate a `Matchfile` with the configuration:

```shell
fastlane match init
```

This command prompts you to:

- Choose which storage backend you want to use, you must select `gitlab_secure_files`.
- Input your project path, for example `gitlab-org/gitlab`.

#### Generate and upload certificates

Run the following command to generate certificates and profiles in the Apple Developer portal
and upload those files to GitLab:

```shell
PRIVATE_TOKEN=YOUR-TOKEN bundle exec fastlane match development
```

In this example:

- `YOUR-TOKEN` must be either a personal or project access token with Maintainer role for the GitLab project.
- Replace `development` with the type of build you want to sign, for example `appstore` or `ad-hoc`.

You can view the files in your project's CI/CD settings as soon as the command completes.

#### Upload-only

If you have already created signing certificates and provisioning profiles for your project,
you can optionally use `fastlane match import` to load your existing files into GitLab:

```shell
PRIVATE_TOKEN=YOUR-TOKEN bundle exec fastlane match import
```

You are prompted to input the path to your files. After you provide those details,
your files are uploaded and visible in your project's CI/CD settings.
If prompted for the `git_url` during the import, it is safe to leave it blank and press <kbd>enter</kbd>.

With this configuration in place, you can use fastlane to build and sign the app with
the files stored in secure files.

For example:

- Sample `fastlane/Fastfile` file:

  ```ruby
  default_platform(:ios)
  
  platform :ios do
    desc "Build and sign the application for development"
    lane :build do
      setup_ci

      match(type: 'development', readonly: is_ci)

      build_app(
        project: "ios demo.xcodeproj",
        scheme: "ios demo",
        configuration: "Debug",
        export_method: "development"
      )
    end
  end
  ```

- Sample `.gitlab-ci.yml` file:

  ```yaml
  build_ios:
    image: macos-12-xcode-14
    stage: build
    script:
      - fastlane build
    tags:
      - shared-macos-amd64
  ```

## Distribution

Signed builds can be uploaded to the Google Play Store or Apple App Store by using
the Mobile DevOps Distribution integrations.

### Android distribution with Google Play integration and fastlane

To create an Android distribution with Google Play integration and fastlane, you must:

1. [Create a Google service account](https://docs.fastlane.tools/actions/supply/#setup)
   in Google Cloud Platform and grant that account access to the project in Google Play.
1. [Enable the Google Play integration](#enable-google-play-integration).
1. Add the release step to your pipeline.

<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
For an overview, see [Google Play integration demo](https://youtu.be/Fxaj3hna4uk).

#### Enable Google Play Integration

Use the [Google Play integration](../user/project/integrations/google_play.md),
to configure your CI/CD pipelines to connect to the [Google Play Console](https://play.google.com/console)
to build and release Android apps. To enable the integration:

1. On the top bar, select **Main menu > Projects** and find your project.
1. On the left sidebar, select **Settings > Integrations**.
1. Select **Google Play**.
1. In **Enable integration**, select the **Active** checkbox.
1. In **Package name**, enter the package name of the app. For example, `com.gitlab.app_name`.
1. In **Service account key (.JSON)** drag or upload your key file.
1. Select **Save changes**.

With the integration enabled, you can use fastlane to distribute a build to Google Play.

For example:

- Sample `fastlane/Fastfile`:

  ```ruby
  default_platform(:android)

  platform :android do
    desc "Submit a new Beta build to the Google Play store"
    lane :beta do
      upload_to_play_store(
        track: 'internal',
        aab: 'app/build/outputs/bundle/release/app-release.aab',
        release_status: 'draft'
      )
    end
  end
  ```

- Sample `.gitlab-ci.yml`:

  ```yaml
  beta:
    image: fabernovel/android:api-33-v1.7.0
    stage: beta
    script:
      - fastlane beta
  ```

### iOS distribution Apple Store integration and fastlane

To create an iOS distribution with the Apple Store integration and fastlane, you must:

1. Generate an API Key for App Store Connect API. In the Apple App Store Connect portal,
   [generate a new private key for your project](https://developer.apple.com/documentation/appstoreconnectapi/creating_api_keys_for_app_store_connect_api).
1. [Enable the Apple App Store integration](#enable-apple-app-store-integration).
1. Add the release step to your pipeline and fastlane configuration.

<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
For an overview, see [Apple App Store integration demo](https://youtu.be/CwzAWVgJeK8).

#### Enable Apple App Store Integration

Use the [Apple App Store integration](../user/project/integrations/apple_app_store.md)
to configure your CI/CD pipelines to connect to [App Store Connect](https://appstoreconnect.apple.com/)
to build and release apps for iOS, iPadOS, macOS, tvOS, and watchOS. To enable the integration:

1. On the top bar, select **Main menu > Projects** and find your project.
1. On the left sidebar, select **Settings > Integrations**.
1. Select **Apple App Store**.
1. Turn on the **Active** toggle under **Enable Integration**.
1. Provide the Apple App Store Connect configuration information:
   - **Issuer ID**: You can find the Apple App Store Connect Issuer ID in the **Keys** section under **Users and Access** in the Apple App Store Connect portal.
   - **Key ID**: The key ID of the new private key that was just generated.
   - **Private Key**: The private key that was just generated. You can only download this key one time.
1. Select **Save changes**.

With the integration enabled, you can use fastlane to distribute a build to TestFlight
and the Apple App Store.

For example:

- Sample `fastlane/Fastfile`:

  ```ruby
  default_platform(:ios)

  platform :ios do
    desc "Build and sign the application for distribution, upload to TestFlight"
    lane :beta do
      setup_ci

      match(type: 'appstore', readonly: is_ci)

      app_store_connect_api_key

      increment_build_number(
        build_number: latest_testflight_build_number(initial_build_number: 1) + 1,
        xcodeproj: "ios demo.xcodeproj"
      )

      build_app(
        project: "ios demo.xcodeproj",
        scheme: "ios demo",
        configuration: "Release",
        export_method: "app-store"
      )

      upload_to_testflight
    end
  end
  ```

- Sample `.gitlab-ci.yml`:

  ```yaml
  beta_ios:
    image: macos-12-xcode-14
    stage: beta
    script:
      - fastlane beta
  ```

## Review apps for mobile

You can use [review apps](review_apps/index.md) to preview changes directly from a merge request.
This feature is possible through an integration with [Appetize.io](https://appetize.io/).

<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
For an overview, see [Review apps for mobile setup instructions](https://youtu.be/X15mI19TXa4).

To get started, see the [setup instructions](https://gitlab.com/gitlab-org/incubation-engineering/mobile-devops/readme/-/issues/15).

## Mobile SAST

You can use [Static Application Security Testing (SAST)](../user/application_security/sast/index.md)
to run static analyzers on code to check for known security vulnerabilities. Mobile SAST
expands this functionality for mobile teams with an [experimental SAST feature](../user/application_security/sast/index.md#experimental-features)
based on [Mobile Security Framework (MobSF)](https://github.com/MobSF/Mobile-Security-Framework-MobSF).

## Sample Reference Projects

See the sample reference projects below for complete build, sign, and release pipeline examples for various platforms. A list of all available projects can be found in [the Mobile DevOps Demo Projects group](https://gitlab.com/gitlab-org/incubation-engineering/mobile-devops/demo-projects/).

- [Android Demo](https://gitlab.com/gitlab-org/incubation-engineering/mobile-devops/demo-projects/android_demo)
- [iOS Demo](https://gitlab.com/gitlab-org/incubation-engineering/mobile-devops/demo-projects/ios-demo)
- [Flutter Demo](https://gitlab.com/gitlab-org/incubation-engineering/mobile-devops/demo-projects/flutter-demo)

## Mobile DevOps Blog

Additional reference material can be found in the [#mobile section](https://about.gitlab.com/blog/tags.html#mobile) of the GitLab blog.