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