# GitHub Actions: How to Compile and release a React Native Android app

**GitHub Actions** is a tool integrated into Github to perform tasks related to the repository given an “event”.

I must give credit to this [post](https://www.andrewhoog.com/post/how-to-build-react-native-android-app-with-github-actions/) and its [Youtube video](https://www.youtube.com/watch?v=_uRbEyBa9q0) because I was of great help in this regard.

If you’re in a hurry, here’s the [repo](https://github.com/henryjperez/gh-actions_react-native-release--tutorial) containing the whole file of this tutorial.

# How GitHub Actions works

As I said it’s a tool integrated into GitHub to automate processes related to the repository. It works by declaring a `.yml` (you can find a complete view of **YAML** files in this [article](https://dev.henryjperez.com/the-yaml-files)) in the relative of your repo: `/.github/workflows/`

In those files will live the configurations of the tasks that will be executed when a given event occurs on the repo: push, pull requests, issues, tags, etc.

# Where to begin?

Well, if you’re completely new to this I suggest starting to create a folder in the root of your project called `.github`. Inside there, create another folder called `workflows` (yes, this is the path that I mentioned before).

Then create a file with the `.yml` extension. You can call it whatever you want but I’ll call it: `build-android.yml`.

And finally, enable **Github Actions** in the ***Actions*** tab:

![Actions Tab in GitHub](https://cdn.hashnode.com/res/hashnode/image/upload/v1679182749953/562d8ac5-3a42-4140-be39-05f9fca08b3e.png align="center")

With that, we are ready to begin.

## Considerations for this tutorial

You don’t need to be the owner of the repository to make this tutorial. If you have access to it like a contributor it’s enough.

I’ll gonna compile multiple .apk files for different architectures of CPUs, and if you only gonna compile one .apk then you can do it just fine.

# Steps

## Name the Action

At the top of the file put whatever name you want the **action** to have. You can do it like this:

```yaml
name: Build Android .apk
```

## Name of the runtime (optional)

By default, the action in the **Actions** tab will run with the name of the commit that triggers it, but you can change that by putting `run-name` in the file. Like this:

```yaml
name: Build Android .apk

run-name: "Building the .apk with the tag triggered by @${{ github.actor }}"
```

The workflow running will look like this:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1679182842445/7a70c102-27be-4ee3-9a6c-a4ae98597ee6.png align="center")

The `${{ [github.actor](http://github.actor) }}` is a variable that **Github** provides with the user that triggered the **action**: [**GitHub Object**](https://docs.github.com/en/actions/learn-github-actions/contexts#github-context)**.**

## Event Trigger

In this part, you can put any event that you see fit, but since this is a tutorial to create a release with the output, then it’s necessary to use **git tags** to trigger the **action**.

```yaml
name: Build Android .apk

run-name: "Building the .apk with the tag triggered by @${{ github.actor }}"

permissions:
  contents: write

on:
  push:
    tags:
      - "v*"
```

The `"v*"` means that the tag name must start with `v`, but you can put it like this to trigger it at any **tag**: `"*"`.

## Jobs

**Jobs** are different processes that can run in parallel (or in sequence) in **GitHub Actions**. For this tutorial, we’ll not gonna worry too much about it, but I’ll leave you some resources for you to deep dive into it:

[Github Actions Job Objects](https://docs.github.com/en/actions/using-jobs/using-jobs-in-a-workflow)

[Youtube: 5 Ways to DevOps-ify your App - Github Actions Tutorial](https://www.youtube.com/watch?v=eB0nUzAI7M8)

For now, I’ll gonna call this ***job*** as `build` (but you can call it otherwise if you want) and say it to run on the **latest version of Ubuntu**:

```yaml
jobs:
  build:
    runs-on: ubuntu-latest
```

## Steps Object

Before we start giving instructions on how to compile the app, first let’s declare the `step` object that will wrap the processes:

```yaml
jobs:
  build:
    runs-on: ubuntu-latest

    steps:
```

## Setting the repository

Now, this is the part that we all have been waiting for: The **Actions** of **GitHub Actions**.

To use them you need to declare a `name` and a `uses` parameter. You’ll see the pattern with the rest of the tutorial.

Use the [checkout action](https://github.com/marketplace/actions/checkout) to move to the root of your project:

```yaml
steps:
    - name: Checkout repository
      uses: actions/checkout@v2
```

## Installing Java

Use the [Java action](https://github.com/marketplace/actions/setup-java-jdk) with the **Gradle** version:

```yaml
- name: Install Java
    uses: actions/setup-java@v3
    with:
      java-version: "11"
      distribution: "adopt"
      cache: "gradle"
```

## Validate Gradle (optional)

I’ll not gonna lie to you, this is something that I saw in the tutorial that I mention but I suppose that you can do it without it anyway.

```yaml
- name: Validate Gradle wrapper
  uses: gradle/wrapper-validation-action@v1
```

## Installing Node.js

Setup node with the [GitHub Action](https://github.com/marketplace/actions/setup-node-js-environment):

```yaml
- name: Setup Node  
  uses: actions/setup-node@v3
  with:
    node-version: '16'
```

With this, you will set up `yarn` and `npm` if you need them. In my case, I’ll use `yarn` for the rest of the tutorial, but it will depend on your use case.

## Installing dependencies and building the project

As I said, I’ll use `yarn` for this but it will depend on you.

```yaml
- name: Run Yarn Install
  run: yarn install

- name: Build application
  run: yarn release
```

The `release` script in the `package.json` file looks like this:

```json
"release": "cd android && ./gradlew assembleRelease",
```

## List the compiled files (optional)

This is just to see the name of the .apk files in case you need to see them to do something else.

```yaml
- name: List the .apks compiled
  run: ls ./android/app/build/outputs/apk/release/ -hal
```

## Changing the name of the main .apk file (optional)

This is not necessary, but I’ll add it anyways because it’s better to download the .apk, when needed, with the version that has a semantic name.

In this case, I’ll rename the `app-universal-release.apk`, but in your case, it might look different. So be aware of that.

```yaml
- name: Rename the .apk to the tag version
  run: mv ./android/app/build/outputs/apk/release/app-universal-release.apk ./android/app/build/outputs/apk/release/app-name_${{ github.ref_name }}.apk
```

The `{{GitHub.ref_name }}` has the version name of the ***git tag***.

## Creating Release and Uploading Files

Finally, the [GH Release Action](https://github.com/marketplace/actions/gh-release) to create the release and push the .apk compiled.

As I said, I’ll upload many files because I’m compiling a .apk for each CPU architecture, in your case it could be only one, but don’t worry I’ll show you how to do it as well.

```yaml
- name: Create Release and Uploading Files
  uses: softprops/action-gh-release@v1
  if: startsWith(github.ref, 'refs/tags/')
  with:
    files: |
      android/app/build/outputs/apk/release/app-arm64-v8a-release.apk
      android/app/build/outputs/apk/release/app-armeabi-v7a-release.apk
      android/app/build/outputs/apk/release/app-x86_64-release.apk
      android/app/build/outputs/apk/release/app-x86-release.apk
      android/app/build/outputs/apk/release/app-name_${{ github.ref_name }}.apk
```

In the `files` part, in case you want to upload only one file, do it like this:

```yaml
files: android/app/build/outputs/apk/release/app-name_${{ github.ref_name }}.apk
```

Or

```yaml
files: android/app/build/outputs/apk/release/app-universal-release.apk
```

# Results

Well, the result would look something like this:

```yaml
name: Build Android .apk

run-name: "Building the .apk with the tag triggered by @${{ github.actor }}"

permissions:
  contents: write

on:
  push:
    tags:
      - "v*"

jobs:
  build:
    runs-on: ubuntu-latest
    # runs-on: ubuntu-22.04 # this is the Ubuntu version that this was created on

    steps:
      - name: Checkout repository
        uses: actions/checkout@v2

      - name: Install Java
        uses: actions/setup-java@v3
        with:
          java-version: "11"
          distribution: "adopt"
          cache: "gradle"

      - name: Validate Gradle wrapper
        uses: gradle/wrapper-validation-action@v1

      # Node, Yarn and NPM
      - name: Setup Node  
        uses: actions/setup-node@v3
        with:
          node-version: '16'

      - name: Run Yarn Install
        run: yarn install

      - name: Build application
        run: yarn release

      - name: List the .apks compiled
        run: ls ./android/app/build/outputs/apk/release/ -hal

      - name: Rename the .apk to the tag version
        run: mv ./android/app/build/outputs/apk/release/app-universal-release.apk ./android/app/build/outputs/apk/release/app_name_${{ github.ref_name }}.apk
      

      # Creating and Uploading the releases
      - name: Create Release and Uploading Files
        uses: softprops/action-gh-release@v1
        if: startsWith(github.ref, 'refs/tags/')
        with:
          files: |
            android/app/build/outputs/apk/release/app-arm64-v8a-release.apk
            android/app/build/outputs/apk/release/app-armeabi-v7a-release.apk
            android/app/build/outputs/apk/release/app-x86_64-release.apk
            android/app/build/outputs/apk/release/app-x86-release.apk
            android/app/build/outputs/apk/release/app_name_${{ github.ref_name }}.apk
```

Remember that everything we did is in the [repository of this tutorial](https://github.com/henryjperez/gh-actions_react-native-release--tutorial).

After you commit the file and push a **tag** into your repository you’ll see something like this in the **Actions** tab:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1679182869381/7d05ae91-1e80-480e-bac4-24e6ca1b8eab.png align="center")

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1679182882648/786b0e6b-f3da-40ef-97eb-aab1b11638a2.png align="center")

And you’ll also see the release:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1679182891237/b763ae3f-e219-4fc6-86b1-05cd3f63e821.png align="center")

---

Well, that’s it for me now. Please let me know if it was useful to you or if you had any issues.

Follow me on [Twitter](https://twitter.com/henryjperez), [LinkedIn](https://www.linkedin.com/in/henryjperez/), [Instagram](https://www.instagram.com/henryjperez/), [Github](https://github.com/henryjperez/), [Medium](https://medium.com/@henryjperez) (For more opinion-based posts), and here on [Hashnode](https://hashnode.com/@henryjperez) and my [Hashnode blog](https://dev.henryjperez.com/).

Have a nice day and until next time. Bye.
