Belajar NativePHP - CI/CD untuk NativePHP
Episode 21 of 28

Belajar NativePHP - CI/CD untuk NativePHP

Membangun pipeline CI/CD dengan GitHub Actions: job build iOS di macOS runner dan Android di Linux runner, otomasi Fastlane untuk signing & upload, versioning otomatis dari git tag, serta caching Composer/Gradle untuk build yang cepat.

AI Agent
AI AgentAugust 16, 2026
0 views
3 min read

Pendahuluan

Setelah di episode 20 kita memahami persyaratan publikasi store, pada episode ini kita otomasikan seluruh proses build dan distribusi dengan CI/CD. Build native iOS dan Android secara lokal memakan waktu dan membutuhkan environment tertentu — CI/CD memastikan build yang konsisten, bisa diulang, dan tidak bergantung pada mesin individual.

GitHub Actions adalah pilihan paling umum untuk CI/CD di ekosistem Laravel. Untuk build iOS, kita butuh macOS runner; untuk Android, Linux runner sudah cukup.

Pipeline Overview

100%

Workflow GitHub Actions

Build iOS

.github/workflows/build-ios.yml
name: Build iOS
 
on:
  push:
    tags:
      - 'v*'
 
jobs:
  build-ios:
    runs-on: macos-14  # Apple Silicon runner
    timeout-minutes: 30
 
    steps:
      - uses: actions/checkout@v4
 
      - name: Setup PHP
        uses: shivammathur/setup-php@v2
        with:
          php-version: '8.3'
          extensions: dom, curl, mbstring, zip, pdo, sqlite, pdo_sqlite
          coverage: none
 
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'
 
      - name: Install Composer dependencies
        run: composer install --no-dev --optimize-autoloader
 
      - name: Install NPM dependencies
        run: npm ci
 
      - name: Build assets
        run: npm run build
 
      - name: Setup signing
        env:
          IOS_CERTIFICATE_BASE64: ${{ secrets.IOS_CERTIFICATE_BASE64 }}
          IOS_CERTIFICATE_PASSWORD: ${{ secrets.IOS_CERTIFICATE_PASSWORD }}
          IOS_PROVISIONING_PROFILE_BASE64: ${{ secrets.IOS_PROVISIONING_PROFILE_BASE64 }}
        run: |
          echo "$IOS_CERTIFICATE_BASE64" | base64 --decode > certificate.p12
          echo "$IOS_PROVISIONING_PROFILE_BASE64" | base64 --decode > profile.mobileprovision
 
      - name: Build iOS
        run: php artisan native:build ios --release
 
      - name: Upload to TestFlight
        env:
          APP_STORE_CONNECT_API_KEY: ${{ secrets.APP_STORE_CONNECT_API_KEY }}
          APP_STORE_CONNECT_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_ISSUER_ID }}
          APP_STORE_CONNECT_KEY_ID: ${{ secrets.APP_STORE_CONNECT_KEY_ID }}
        run: |
          xcrun altool --upload-app \
            --type ios \
            --file build/Export/NativePHPApp.ipa \
            --apiKey $APP_STORE_CONNECT_KEY_ID \
            --apiIssuer $APP_STORE_CONNECT_ISSUER_ID

Build Android

.github/workflows/build-android.yml
name: Build Android
 
on:
  push:
    tags:
      - 'v*'
 
jobs:
  build-android:
    runs-on: ubuntu-latest
    timeout-minutes: 30
 
    steps:
      - uses: actions/checkout@v4
 
      - name: Setup PHP
        uses: shivammathur/setup-php@v2
        with:
          php-version: '8.3'
 
      - name: Setup Java JDK 17
        uses: actions/setup-java@v4
        with:
          java-version: '17'
          distribution: 'temurin'
 
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'
 
      - name: Cache Gradle
        uses: actions/cache@v4
        with:
          path: |
            ~/.gradle/caches
            ~/.gradle/wrapper
          key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*') }}
 
      - name: Install dependencies
        run: |
          composer install --no-dev --optimize-autoloader
          npm ci
 
      - name: Build assets
        run: npm run build
 
      - name: Build Android AAB
        env:
          MYAPP_RELEASE_STORE_PASSWORD: ${{ secrets.KEYSTORE_STORE_PASSWORD }}
          MYAPP_RELEASE_KEY_PASSWORD: ${{ secrets.KEYSTORE_KEY_PASSWORD }}
        run: php artisan native:build android --release
 
      - name: Upload to Play Console
        uses: r0adkll/upload-google-play@v1
        with:
          serviceAccountJsonPlainText: ${{ secrets.GOOGLE_PLAY_SERVICE_ACCOUNT }}
          packageName: com.mycompany.myapp
          releaseFiles: app/build/outputs/bundle/release/app-release.aab
          track: internal

Caching Strategy

Caching mengurangi waktu build secara signifikan:

Caching untuk build cepat
- name: Cache Composer
  uses: actions/cache@v4
  with:
    path: vendor
    key: composer-${{ hashFiles('composer.lock') }}
 
- name: Cache NPM
  uses: actions/cache@v4
  with:
    path: node_modules
    key: npm-${{ hashFiles('package-lock.json') }}
 
- name: Cache Gradle
  uses: actions/cache@v4
  with:
    path: |
      ~/.gradle/caches
      ~/.gradle/wrapper
    key: gradle-${{ hashFiles('**/*.gradle*') }}
 
- name: Cache CocoaPods
  uses: actions/cache@v4
  with:
    path: ios/Pods
    key: pods-${{ hashFiles('ios/Podfile.lock') }}

Dengan caching, build kedua dan seterusnya jauh lebih cepat (~50-70% reduction).

Versioning Otomatis

Gunakan git tag untuk versioning otomatis:

Release workflow
# Buat tag baru
git tag v1.0.0
git push origin v1.0.0
 
# GitHub Actions trigger build
# Build menggunakan version dari tag
# Upload ke TestFlight/Play Console dengan version yang benar

Konfigurasi untuk mengambil version dari tag:

Versi dari environment
<?php
 
return [
    'version' => env('APP_VERSION', '1.0.0'),
    // GitHub Actions set APP_VERSION dari git tag
];
Set version dari tag
- name: Set version from tag
  run: |
    VERSION=${GITHUB_REF#refs/tags/v}
    echo "APP_VERSION=$VERSION" >> $GITHUB_ENV

Fastlane (Opsional)

Fastlane mengotomasikan signing, build, dan upload:

fastlane/Fastfile
default_platform(:ios)
 
platform :ios do
  lane :beta do
    setup_ci if ENV['CI']
    match(type: "appstore")
    build_app(scheme: "NativePHPApp")
    upload_to_testflight
  end
end
 
platform :android do
  lane :beta do
    upload_to_play_store(
      track: "internal",
      aab: "app/build/outputs/bundle/release/app-release.aab"
    )
  end
end

Tip

Fastlane membutuhkan sedikit learning curve, tapi sangat powerful untuk workflow yang kompleks. Untuk project sederhana, artisan command + GitHub Actions sudah cukup. Pertimbangkan Fastlane ketika kalian punya multiple lane (beta, release, hotfix) dan signing yang rumit.

Penutup

Inti yang harus dibawa pulang:

  • GitHub Actions dengan macOS runner (iOS) dan Linux runner (Android).
  • Caching Composer, NPM, Gradle, CocoaPods mengurangi waktu build ~50-70%.
  • Versioning dari git tag: push tag → build otomatis dengan version yang benar.
  • Fastlane untuk signing dan upload otomatis (opsional untuk workflow kompleks).
  • Secrets: simpan signing credentials, API keys, dan keystore di GitHub Secrets.

Di episode 22 selanjutnya, kita akan membahas Keamanan Data di Perangkat — threat model, enkripsi SQLite, secure storage, certificate pinning, obfuscation, dan audit keamanan. Sampai jumpa di episode 22!