March 24, 2026

I Keep Forgetting About My Long-Running Mobile App Builds

ci-cdmobiledevopsproductivity

I’m a mobile developer. My Android builds take me easily 15-20 minutes. iOS with Fastlane, tests, code signing, and TestFlight upload? Easily 30 minutes.

Every time I make a PR, I’d start a build, switch to something else, and forget about it. An hour later, I’d come back and check the Actions tab to see that the build failed 45 minutes ago. Or that the build actually worked and QA has been waiting on this for a long time.

This has been happening too many times for me to count, so I built something to solve this problem.

The Problem

There’s no way to automatically sense that the build is complete. You just need to keep an eye on the Actions tab or wait for your PR to become mergeable.

What I actually wanted:

  • A push notification on my phone the moment the build finishes
  • A direct link that I could tap the notification and go straight to Firebase App Distribution or TestFlight
  • Different messages for success and failure
  • A link to the GitHub Actions run for failed builds so that I can see what went wrong
  • No waiting around, no checking every 10 minutes and no post-it notes under the monitor

What I Did

I created a simple service that sends push notifications to your phone. You send it an event via the API or GitHub Actions, and it buzzes your phone. The key feature for CI/CD pipelines is that it can include a link in the notification. You can tap the notification to get to where you need to go. You can find the service at API Alerts.

Here’s what my Android staging workflow looks like:

- name: Upload to Firebase
  uses: wzieba/Firebase-Distribution-Github-Action@v1
  with:
    appId: ${{ secrets.ANDROID_FIREBASE_APP_ID }}
    serviceCredentialsFileContent: ${{ secrets.GCP_CREDENTIALS }}
    groups: staging
    file: app/build/outputs/apk/release/app-release.apk

- name: Notify
  if: success() || failure()
  uses: apialerts/notify-action@v2
  with:
    api_key: ${{ secrets.API_ALERTS_KEY }}
    channel: 'developer'
    message: ${{ job.status == 'success' && 'Android staging deployed' || 'Android staging failed' }}
    tags: 'deploy,staging,android'
    link: ${{ job.status == 'success' && 'https://appdistribution.firebase.google.com/testerapps/MY_APP_ID' || format('{0}/{1}/actions/runs/{2}', github.server_url, github.repository, github.run_id) }}

The if: success() || failure() is important. It sends a notification no matter the outcome but uses different messages.

The Workflow Now

  1. Push code to a PR
  2. Context switch. Make a coffee, quick power nap, play with my cat Earl, review another PR, whatever
  3. Phone buzzes: “Android staging deployed”
  4. Tap > Firebase App Distribution opens > install > test

Or:

  1. Phone buzzes: “Android staging failed”
  2. Tap > The GitHub Actions run opens > see exactly what broke

The entire process from “push code” to “testing the build on my phone” now requires zero attention.

iOS Too

I use the same approach for iOS builds. My Fastlane workflow uploads to Firebase App Distribution (or TestFlight) and then sends the notification:

- name: Test App
  run: fastlane ios tests

- name: Build
  run: fastlane ios build_beta

- name: Deploy
  run: fastlane ios deploy_beta group:staging

- name: Notify
  if: success() || failure()
  uses: apialerts/notify-action@v2
  with:
    api_key: ${{ secrets.API_ALERTS_KEY }}
    channel: 'developer'
    message: ${{ job.status == 'success' && 'iOS staging deployed' || 'iOS staging failed' }}
    tags: 'deploy,staging,ios'
    link: ${{ job.status == 'success' && 'https://appdistribution.firebase.google.com/testerapps/MY_APP_ID' || format('{0}/{1}/actions/runs/{2}', github.server_url, github.repository, github.run_id) }}

Staging vs Production

I use separate channels to keep things organised:

  • developer for staging and feature branch builds. Just me.
  • releases for production builds. The messages are different too:
# Production
channel: 'releases'
message: ${{ job.status == 'success' && 'Android production ready to submit' || 'Android production failed' }}
link: ${{ job.status == 'success' && 'https://play.google.com/store/apps/details?id=com.myapp' || '...' }}

It’s Not Just Mobile

I’ve taken this approach and applied it to my backend deployments, web builds, and even SDK releases. Any build or deployment that takes more than a minute and may fail now sends a notification.

The GitHub action is a simple step to add to any workflow. If you’re a mobile dev spending your day waiting on CI, try adding this action.

I wrote a more detailed step-by-step blog post on the API Alerts blog if you want the full walkthrough.

I’m the developer behind API Alerts, I built it because I needed it. If you have questions about the setup or want to see other use cases, drop a comment.