Skip to main content

Overview

Deploying an Android app to Google Play involves creating a signed App Bundle (AAB), configuring your app listing, and uploading to the Play Console. NativePHP automates the build and signing process.

Prerequisites

A Google Play Developer account is required ($25 one-time fee).
Create your app in Google Play Console with the same package name as your NATIVEPHP_APP_ID.
Generate a keystore file for signing your app releases.
For automated uploads, create a service account with Play Console access.

Keystore Generation

Generate a signing keystore for your app:
keytool -genkey -v -keystore my-release-key.jks \
  -keyalg RSA -keysize 2048 -validity 10000 \
  -alias my-key-alias
You’ll be prompted for:
  • Keystore password
  • Key password
  • Your name and organization details
Keep your keystore safe! If you lose it, you cannot update your app on Play Store. Back it up securely.
Best Practices:
  • Store keystore outside your project repository
  • Use a strong password (16+ characters)
  • Back up to secure cloud storage
  • Never commit keystore to version control

Version Configuration

Android apps use two version identifiers:

Version Name

Human-readable version displayed to users:
// config/nativephp.php
'version' => env('NATIVEPHP_APP_VERSION', '1.0.0'),
# .env
NATIVEPHP_APP_VERSION=1.0.0
This maps to versionName in your app’s build configuration.

Version Code

Internal integer version that must increase with each release:
// config/nativephp.php
'version_code' => env('NATIVEPHP_APP_VERSION_CODE', 1),
# .env
NATIVEPHP_APP_VERSION_CODE=1
This maps to versionCode in your app’s build configuration. Version Code Rules:
  • Must be a positive integer
  • Must increase with every Play Store release
  • Cannot be reused or decreased
  • Automatically incremented during packaging
Example Version Progression:
ReleaseVersion NameVersion Code
Initial1.0.01
Bug fix1.0.12
Feature1.1.03
Major2.0.04

Building for Play Store

Create App Bundle

Build a signed App Bundle (AAB) for Play Store:
php artisan native:package android \
  --build-type=bundle \
  --keystore=/path/to/my-release-key.jks \
  --keystore-password=keystorepass \
  --key-alias=my-key-alias \
  --key-password=keypass

Using Environment Variables

Store credentials securely in .env:
ANDROID_KEYSTORE_FILE=/path/to/my-release-key.jks
ANDROID_KEYSTORE_PASSWORD=your_keystore_password
ANDROID_KEY_ALIAS=my-key-alias
ANDROID_KEY_PASSWORD=your_key_password
Then simply run:
php artisan native:package android --build-type=bundle

Build Output

After successful build:
Build output: nativephp/android/app/build/outputs/bundle/release/app-release.aab
File size: 18.3 MB
The output directory will open automatically.

Automated Play Store Upload

Service Account Setup

1

Create Service Account

In Google Cloud Console, create a service account for your project.
2

Generate Key

Create and download a JSON key for the service account.
3

Grant Play Console Access

In Play Console, go to Users and Permissions > Invite new users and add the service account email with Release Manager role.
4

Configure Environment

Add the service account key path to your .env:
GOOGLE_SERVICE_ACCOUNT_KEY=/path/to/service-account.json

Upload to Play Store

Build and upload in one command:
php artisan native:package android \
  --build-type=bundle \
  --upload-to-play-store \
  --play-store-track=internal
With Google Service Account:
php artisan native:package android \
  --build-type=bundle \
  --upload-to-play-store \
  --google-service-key=/path/to/service-account.json \
  --play-store-track=internal

Play Store Tracks

Choose which track to publish to:
# Internal testing (fast, no review)
--play-store-track=internal

# Closed alpha testing
--play-store-track=alpha

# Open beta testing
--play-store-track=beta

# Production release
--play-store-track=production
Track Comparison:
TrackReview RequiredUser LimitRollout Speed
InternalNo100Immediate
AlphaNoUnlimitedFast
BetaNoUnlimitedFast
ProductionYesUnlimitedStaged/Full

Test Upload

Test uploading an existing AAB without rebuilding:
php artisan native:package android \
  --test-push=/path/to/app-release.aab \
  --google-service-key=/path/to/service-account.json \
  --play-store-track=internal

Build Configuration

Configure Android build options in config/nativephp.php:
'android' => [
    'build' => [
        // Code minification and obfuscation
        'minify_enabled' => env('NATIVEPHP_ANDROID_MINIFY_ENABLED', false),
        'shrink_resources' => env('NATIVEPHP_ANDROID_SHRINK_RESOURCES', false),
        'obfuscate' => env('NATIVEPHP_ANDROID_OBFUSCATE', false),
        
        // Debug symbols
        'debug_symbols' => env('NATIVEPHP_ANDROID_DEBUG_SYMBOLS', 'FULL'),
        'generate_mapping_files' => env('NATIVEPHP_ANDROID_MAPPING_FILES', false),
        'mapping_file_path' => env('NATIVEPHP_ANDROID_MAPPING_PATH', 'build/outputs/mapping/release/'),
        
        // ProGuard rules
        'keep_line_numbers' => env('NATIVEPHP_ANDROID_KEEP_LINE_NUMBERS', false),
        'keep_source_file' => env('NATIVEPHP_ANDROID_KEEP_SOURCE_FILE', false),
        'custom_proguard_rules' => env('NATIVEPHP_ANDROID_CUSTOM_PROGUARD_RULES', []),
        
        // Build performance
        'parallel_builds' => env('NATIVEPHP_ANDROID_PARALLEL_BUILDS', true),
        'incremental_builds' => env('NATIVEPHP_ANDROID_INCREMENTAL_BUILDS', true),
    ],
],

Minification and Obfuscation

Reduce APK size and protect code:
# Enable R8 minification
NATIVEPHP_ANDROID_MINIFY_ENABLED=true

# Remove unused resources
NATIVEPHP_ANDROID_SHRINK_RESOURCES=true

# Obfuscate code
NATIVEPHP_ANDROID_OBFUSCATE=true
Minification and obfuscation can make debugging harder. Test thoroughly before enabling for production.

Debug Symbols

Control debug information in builds:
# Full debug symbols (default)
NATIVEPHP_ANDROID_DEBUG_SYMBOLS=FULL

# Line numbers only
NATIVEPHP_ANDROID_DEBUG_SYMBOLS=LINE_NUMBERS_ONLY

# No debug symbols
NATIVEPHP_ANDROID_DEBUG_SYMBOLS=NONE

Generate Mapping Files

For deobfuscating crash reports:
NATIVEPHP_ANDROID_MAPPING_FILES=true
NATIVEPHP_ANDROID_MAPPING_PATH=build/outputs/mapping/release/
Mapping files are needed to interpret ProGuard-obfuscated stack traces.

Firebase Configuration (Optional)

For push notifications or analytics:
1

Download google-services.json

Get your Firebase configuration file from the Firebase Console.
2

Place in Project

Save it to either:
  • nativephp/resources/google-services.json (recommended)
  • google-services.json (project root)
3

Rebuild

The file is automatically copied during build:
php artisan native:package android --build-type=bundle
The google-services.json file is automatically included in your Android build.

Manual Play Store Submission

If not using automated uploads:
1

Build AAB

Create your signed App Bundle:
php artisan native:package android --build-type=bundle
2

Open Play Console

Navigate to your app in Google Play Console.
3

Create Release

Go to Release > Production (or Testing track) > Create new release.
4

Upload AAB

Drag and drop your app-release.aab file or browse to select it.
5

Complete Release Notes

Add release notes describing what’s new or changed.
6

Review and Rollout

Review the release details and click Start rollout to Production.

App Signing by Google Play

Google Play uses App Signing to manage your signing keys:
1

Enroll in App Signing

When creating a new app, Google Play will prompt you to enroll in App Signing.
2

Upload Signing Key

Google will either:
  • Generate a new signing key for you (recommended for new apps)
  • Accept your existing key for migration
3

Use Upload Key

You sign AABs with your upload key (your keystore) Google re-signs with the app signing key before distribution
Benefits:
  • Google securely manages your app signing key
  • You can reset your upload key if compromised
  • Smaller app downloads through APK optimization

Version Code Auto-Increment

When uploading to Play Store with service account configured:
php artisan native:package android \
  --build-type=bundle \
  --upload-to-play-store
The version code is automatically checked against Play Store and incremented to the next available number.

Manual Version Increment

Jump ahead by a specific number:
php artisan native:package android \
  --build-type=bundle \
  --upload-to-play-store \
  --jump-by=10

CI/CD Integration

GitHub Actions Example

name: Android Release

on:
  push:
    tags:
      - 'v*'

jobs:
  android:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: Setup PHP
        uses: shivammathur/setup-php@v2
        with:
          php-version: 8.2
      
      - name: Setup Java
        uses: actions/setup-java@v3
        with:
          java-version: '17'
          distribution: 'temurin'
      
      - name: Install Dependencies
        run: composer install
      
      - name: Build and Upload to Play Store
        env:
          ANDROID_KEYSTORE_FILE: ${{ secrets.ANDROID_KEYSTORE_FILE }}
          ANDROID_KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }}
          ANDROID_KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }}
          ANDROID_KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }}
          GOOGLE_SERVICE_ACCOUNT_KEY: ${{ secrets.GOOGLE_SERVICE_ACCOUNT_KEY }}
        run: |
          echo "$ANDROID_KEYSTORE_FILE" | base64 -d > keystore.jks
          echo "$GOOGLE_SERVICE_ACCOUNT_KEY" | base64 -d > service-account.json
          
          php artisan native:package android \
            --build-type=bundle \
            --upload-to-play-store \
            --play-store-track=internal \
            --keystore=keystore.jks \
            --google-service-key=service-account.json \
            --no-tty

Troubleshooting

Missing Signing Configuration

Missing required signing configuration
  - --keystore (or ANDROID_KEYSTORE_FILE env var)
Solution: Provide all required signing parameters.

Version Code Already Used

This version code has already been used
Solution: Increment NATIVEPHP_APP_VERSION_CODE in .env or use auto-increment.

Package Name Mismatch

Package name does not match Play Console app
Solution: Ensure NATIVEPHP_APP_ID matches the package name in Play Console exactly.

Upload Failed

Solutions:
  • Verify service account has Release Manager permissions
  • Check service account key hasn’t expired
  • Ensure AAB is properly signed
  • Verify version code is higher than previous release

Build Failed

Check the build log:
cat nativephp/android-build.log
Common issues:
  • Android SDK not configured
  • Gradle build errors
  • Missing dependencies
  • Signing configuration errors

Play Store Review Process

1

Automated Review

Initial automated checks (usually minutes)
2

Manual Review

Human review of app functionality (varies, typically hours to days)
3

Approval or Rejection

You’ll receive email notification of the decision
4

Publishing

If approved, app goes live based on your rollout settings
Review Guidelines:
  • App must be stable and functional
  • Must comply with Google Play policies
  • Content rating must be accurate
  • Privacy policy required if collecting data
  • Target API level must meet minimum requirements

Next Steps

iOS Deployment

Deploy your app to the App Store

Hot Reload

Speed up development with hot reload

Build docs developers (and LLMs) love