Android Build Guide
This guide walks you through setting up and building the zmNinjaNg Android app from scratch.
Prerequisites
Before you begin, ensure you have the following installed:
Node.js ^20.19.0 || >=22.12.0 and npm - Download here
Android Studio - Download here
Android SDK (installed via Android Studio)
Java JDK 17+ (usually bundled with Android Studio)
Environment Setup
1. Configure Android SDK
After installing Android Studio, set up the ANDROID_HOME environment
variable:
macOS/Linux:
# Add to ~/.zshrc or ~/.bashrc
export ANDROID_HOME=$HOME/Library/Android/sdk
export PATH=$PATH:$ANDROID_HOME/emulator
export PATH=$PATH:$ANDROID_HOME/tools
export PATH=$PATH:$ANDROID_HOME/tools/bin
export PATH=$PATH:$ANDROID_HOME/platform-tools
Windows:
ANDROID_HOME=C:\Users\YourUsername\AppData\Local\Android\Sdk
Verify the installation:
echo $ANDROID_HOME # Should show the SDK path
adb --version # Should show ADB version
2. Create an Android Virtual Device (AVD)
For push notifications to work, you need an emulator with Google Play Services:
Open Android Studio
Go to Tools > Device Manager
Click Create Device
Select a device (e.g., Pixel 5)
Choose a system image with the Play Store icon (e.g., Android 13 with Google APIs)
Click Finish
Project Setup
1. Clone the Repository
git clone https://github.com/ZoneMinder/zmNinjaNg
cd zmNinjaNg/app
2. Install Dependencies
npm install
Push Notifications Setup
To enable push notifications, you need to configure Firebase Cloud Messaging (FCM):
1. Create Firebase Project
Go to Firebase Console
Click Add project
Follow the setup wizard to create your project (call it anything, I called mine zmNinjaNg)
2. Add Android App to Firebase
In Firebase Console, click Add app and select Android
Enter the package name:
com.zoneminder.zmNinjaNG(Optional) Enter an app nickname: “zmNinjaNg Android”
Click Register app
3. Download Configuration File
Download the
google-services.jsonfilePlace it in the following location:
zmNinjaNg/app/android/app/google-services.json
4. Verify Firebase Configuration
The project already includes the necessary Firebase dependencies. The
google-services.json file is all you need to enable push
notifications.
Note: Push notifications will only work on emulators/devices with Google Play Services installed.
5. Configure ZoneMinder Event Notification Server
zmNinjaNg works out of the box with zmES web socket notifications. If you
want push notification support, the ZoneMinder event notification server
(zmeventnotification.pl) needs to be configured to work with your
Firebase project. You will need to use a modified version that I
provided
here.
Follow its README
Building and Running
Debug Build
To build and run the app on an emulator or connected device:
# Build web assets, sync to Android, and run
npm run android
# Open in Android Studio
npm run android:open
This command will: 1. Build the React web app 2. Sync files to the Android project 3. Launch the app on a connected device/emulator
View logs:
npm run android:logs
Check connected devices:
npm run android:devices
Production Build
To create a release build for distribution or the Google Play Store:
1. Generate a Signing Key
If you don’t already have a keystore, create one:
keytool -genkey -v -keystore zmninja-ng-upload.jks -keyalg RSA -keysize 2048 -validity 10000 -alias zmninja-ng-upload
You’ll be prompted to enter a keystore password and identity fields.
Keep your keystore file and passwords safe! You’ll need them for all
future app updates. Store the keystore outside the repo (e.g.,
~/.signing-keys/).
2. Configure Signing
The build reads signing configuration from environment variables. Add
these to your ~/.zshrc or ~/.bashrc:
export ZMNINJA_KEYSTORE_PATH="$HOME/.signing-keys/zmninja-ng-upload.jks"
export ZMNINJA_KEYSTORE_PASSWORD="your_password"
export ZMNINJA_KEY_ALIAS="zmninja-ng-upload"
export ZMNINJA_KEY_PASSWORD="your_password"
Then reload your shell: source ~/.zshrc
3. Build Release APK
cd app
npx cap sync android
cd android && ./gradlew assembleRelease
Output location:
android/app/build/outputs/apk/release/app-release.apk
4. Build App Bundle (AAB) for Play Store
For publishing to Google Play Store, use the App Bundle format:
cd app/android && ./gradlew bundleRelease
Output location:
android/app/build/outputs/bundle/release/app-release.aab
5. Upload to Google Play Console
Go to Google Play Console
Select zmNinjaNg
Go to Testing > Internal testing (or Production) and click Create new release
Upload the
.aabfileAdd release notes and roll out
CI/CD
The GitHub Actions workflow (build-android.yml) handles signed
release builds automatically. It uses these repository secrets:
ANDROID_KEYSTORE_BASE64: base64-encoded keystore fileANDROID_KEYSTORE_PASSWORD: keystore passwordANDROID_KEY_ALIAS: key aliasANDROID_KEY_PASSWORD: key password
To generate the base64 keystore value:
base64 -i ~/.signing-keys/zmninja-ng-upload.jks | pbcopy
Paste the clipboard contents as the ANDROID_KEYSTORE_BASE64 secret
in GitHub > Settings > Secrets and variables > Actions.
Troubleshooting
Build Fails with “ANDROID_HOME not set”
Make sure you’ve set the ANDROID_HOME environment variable and
restarted your terminal.
Push Notifications Don’t Work
Ensure you’re using an emulator/device with Google Play Services
Verify
google-services.jsonis in the correct locationCheck that the package name in Firebase matches
com.zoneminder.zmNinjaNGIf using your own Firebase project, ensure the ZoneMinder server is configured with your FCM credentials
Check for “sender ID mismatch” errors in logcat - this means your app’s Firebase project doesn’t match the server’s
FCM Image Errors (“Failed to decode image”)
If you see this error in the Android logs:
Failed to download image: java.io.IOException: Failed to decode image
This means the ZoneMinder server is sending an incorrectly formatted
image URL. Fix it by: 1. Editing /etc/zm/zmeventnotification.ini on
your ZoneMinder server 2. Setting picture_url to use view=image
instead of view=frame 3. Removing username/password from the URL
(use tokens instead) 4. Example:
picture_url = http://your-server/index.php?view=image&eid=EVENTID&fid=snapshot&width=600
App Won’t Connect to ZoneMinder Server (HTTP)
Android 9+ blocks cleartext HTTP by default
The app includes
network_security_config.xmlto allow HTTPIf you modified the config, ensure it allows cleartext traffic
Gradle Build Errors
Try cleaning the build:
cd android
./gradlew clean
cd ..
npm run android
Next Steps
Testing: Run the app and connect to your ZoneMinder server
Customization: Update app icons, splash screens, and branding
Distribution: Upload AAB to Google Play Console for release
For more information, see: - Capacitor Android Documentation - Android Developer Guide - Firebase Cloud Messaging