A Node.js CLI tool that automatically generates fully configured Flutter and React Native mobile applications from base architectures. This tool streamlines the setup process by handling project configuration, flavor management, Firebase integration, signing configurations, and more through a simple JSON configuration file.
Just want to run it? Here are the essential commands:
# Test your configuration first (recommended)
node setup-app.js --dry-run
# Generate your projects
node setup-app.js
# Use a custom config file
node setup-app.js --config my-config.json
# Test with custom config
node setup-app.js --config my-config.json --dry-run
# Show help
node setup-app.js --helpWhat you need:
- A
config.jsonfile with your project settings - Resource files in
res_flutter/and/orres_rn/directories - Base architecture (local folder or Git repository URL)
Output: Generated projects will be in the output/ directory.
For detailed information, see the sections below.
- Clone this repository or download the tool
- Prepare your resources in
res_flutter/andres_rn/directories - Create or edit
config.jsonwith your project settings - Test your configuration:
node setup-app.js --dry-run - Generate your projects:
node setup-app.js
Your generated projects will be in the output/ directory, ready to build and run.
- TL;DR - Quick Commands
- Quick Start
- Overview
- How It Works
- Project Structure
- Installation
- Configuration
- Directory Structure and File Placement
- Usage
- Configuration Options Explained
- Base Architecture Setup
- Resource Files
- Common Use Cases
- Examples
- Troubleshooting
- Best Practices
- Output Structure
- CI/CD Integration
This tool automates the creation of mobile applications by:
- Cloning base architecture repositories (from Bitbucket/Git or local folders)
- Configuring project files (pubspec.yaml, package.json, build.gradle, etc.)
- Setting up multiple flavors (dev, stage, prod)
- Integrating Firebase configurations per flavor
- Copying environment files, icons, and assets
- Configuring Android and iOS signing
- Generating flavor-specific entry points and build configurations
The tool is deterministic, idempotent, and CI/CD safe, making it perfect for automated build pipelines.
- Configuration Loading: Reads
config.jsonand validates all required fields and resources - Base Architecture Cloning:
- If
baseArchPathis a Git URL, clones the repository to a temporary directory - If it's a local path, uses the existing folder
- Automatically cleans up temporary clones after setup
- If
- Project Setup:
- Copies base architecture to output directory
- Updates project configuration files
- Creates flavor-specific entry points
- Platform Configuration:
- Android: Configures Gradle, flavors, Firebase, icons, signing
- iOS: Configures Xcode project, schemes, Firebase, icons, signing
- Resource Integration: Copies environment files, assets, and other resources
- Cleanup: Removes temporary cloned directories
- Flutter: Full support for multi-flavor Flutter applications
- React Native: Full support for multi-flavor React Native applications
- Both platforms can be configured simultaneously or independently
base_arch/
├── setup-app.js # Main CLI entry point
├── config.json # Configuration file
├── lib/ # Core library code
│ ├── core/ # Core utilities
│ │ ├── config-loader.js # Configuration parser
│ │ ├── validator.js # Configuration validator
│ │ ├── fs-wrapper.js # File system operations
│ │ ├── git-clone.js # Git repository cloning
│ │ └── logger.js # Logging utility
│ ├── flutter/ # Flutter-specific setup
│ │ ├── index.js # Flutter orchestrator
│ │ ├── project.js # Project file updates
│ │ ├── android.js # Android configuration
│ │ ├── ios.js # iOS configuration
│ │ ├── env.js # Environment files
│ │ └── assets.js # Asset copying
│ └── react-native/ # React Native-specific setup
│ ├── index.js # React Native orchestrator
│ ├── project.js # Project file updates
│ ├── android.js # Android configuration
│ ├── ios.js # iOS configuration
│ └── env.js # Environment files
├── basearch_flutter/ # Local Flutter base architecture (optional)
│ └── base_project_flutter/ # Flutter project template
├── basearch_rn/ # Local React Native base architecture (optional)
├── res_flutter/ # Flutter resources
│ ├── firebase/ # Firebase configs per flavor
│ ├── env/ # Environment files per flavor
│ ├── icons/ # App icons per flavor
│ ├── assets/ # Common assets
│ └── signing/ # Signing certificates
├── res_rn/ # React Native resources
│ ├── firebase/ # Firebase configs per flavor
│ ├── env/ # Environment files per flavor
│ ├── icons/ # App icons per flavor
│ └── signing/ # Signing certificates
└── output/ # Generated projects (created by tool)
├── flutter/
│ └── project_name/
└── rn/
└── project_name/
- Node.js (v14 or higher)
- Git (for cloning repositories)
- For Flutter: Flutter SDK
- For React Native: React Native development environment
-
Clone or download this repository
git clone <repository-url> cd base_arch
-
Verify Node.js installation
node --version # Should be v14 or higher -
No additional npm packages required - The tool uses only Node.js built-in modules
-
Ensure Git is installed (if using Git URLs for base architectures)
git --version
-
Prepare access to base architecture repositories (if using Git URLs)
- For HTTPS: Have your Bitbucket/GitHub credentials ready (App Password or token)
- For SSH: Ensure SSH keys are configured and added to your Git provider
The tool is configured entirely through a JSON file (default: config.json). The configuration is divided into several sections:
meta: Project metadata and output settingsflavors: List of flavors to generatecommon: Shared configuration across platformsflutter: Flutter-specific configurationreactNative: React Native-specific configuration
All resource files must be placed in the appropriate directories relative to your config.json file:
res_flutter/
├── firebase/
│ ├── dev/
│ │ ├── google-services.json # Android Firebase config
│ │ └── GoogleService-Info.plist # iOS Firebase config
│ ├── stage/
│ │ ├── google-services.json
│ │ └── GoogleService-Info.plist
│ └── prod/
│ ├── google-services.json
│ └── GoogleService-Info.plist
├── env/
│ ├── .env.dev # Development environment variables
│ ├── .env.stage # Staging environment variables
│ └── .env.prod # Production environment variables
├── icons/
│ ├── dev/
│ │ ├── android/ # Android launcher icons
│ │ │ ├── mipmap-mdpi/
│ │ │ ├── mipmap-hdpi/
│ │ │ ├── mipmap-xhdpi/
│ │ │ ├── mipmap-xxhdpi/
│ │ │ ├── mipmap-xxxhdpi/
│ │ │ └── mipmap-anydpi-v26/
│ │ └── ios/ # iOS app icons
│ │ └── AppIcon.appiconset/
│ ├── stage/
│ │ ├── android/
│ │ └── ios/
│ └── prod/
│ ├── android/
│ └── ios/
├── assets/
│ └── common/ # Common assets (images, fonts, etc.)
└── signing/
├── android/
│ ├── dev/
│ │ └── keystore.jks # Android keystore file
│ ├── stage/
│ │ └── keystore.jks
│ └── prod/
│ └── keystore.jks
└── ios/
├── dev/
│ └── profile.mobileprovision # iOS provisioning profile
├── stage/
│ └── profile.mobileprovision
└── prod/
└── profile.mobileprovision
res_rn/
├── firebase/
│ ├── dev/
│ │ ├── google-services.json
│ │ └── GoogleService-Info.plist
│ ├── stage/
│ └── prod/
├── env/
│ ├── .env.dev
│ ├── .env.stage
│ └── .env.prod
├── icons/
│ ├── dev/
│ │ ├── android/
│ │ └── ios/
│ ├── stage/
│ └── prod/
└── signing/
├── android/
│ ├── dev/
│ ├── stage/
│ └── prod/
└── ios/
├── dev/
├── stage/
└── prod/
You have two options for base architectures:
Place your base architecture folders in the project root:
base_arch/
├── basearch_flutter/
│ └── base_project_flutter/ # Your Flutter project template
└── basearch_rn/ # Your React Native project template
Then in config.json:
{
"flutter": {
"baseArchPath": "basearch_flutter"
},
"reactNative": {
"baseArchPath": "basearch_rn"
}
}Use Git URLs in config.json:
{
"flutter": {
"baseArchPath": "https://username:token@bitbucket.org/workspace/flutter-repo.git",
"baseArchBranch": "main"
},
"reactNative": {
"baseArchPath": "https://username:token@bitbucket.org/workspace/rn-repo.git",
"baseArchBranch": "main"
}
}The tool will automatically clone these repositories at runtime and clean them up afterward.
# Run with default config.json
node setup-app.js
# Preview changes without making them (recommended first)
node setup-app.js --dry-run
# Use a custom config file
node setup-app.js --config my-config.json
# Combine options
node setup-app.js --config production.json --dry-run
# Show help
node setup-app.js --help--dry-runor-d: Preview all changes without modifying the filesystem. Useful for testing configuration before actual execution.--configor-c <path>: Specify a custom configuration file path. Default isconfig.json.--helpor-h: Display help message and exit.
-
Prepare Resources: Place all required files in
res_flutter/andres_rn/directories according to the structure outlined in Directory Structure and File Placement -
Create Configuration: Create or edit
config.jsonwith your project settings. Start with a minimal configuration and add features incrementally. -
Test Configuration: Always run with
--dry-runfirst to verify everything is correct:node setup-app.js --dry-run
This will show you what would be created without making any changes.
-
Fix Any Issues: Review the dry-run output and fix any validation errors or missing files.
-
Generate Projects: Once dry-run passes, run without
--dry-runto create the projects:node setup-app.js
-
Review Output: Check the generated projects in the
output/directory:- Flutter:
output/flutter/project_name/ - React Native:
output/rn/project_name/
- Flutter:
-
Build and Run: Navigate to the generated project and follow platform-specific build instructions.
{
"meta": {
"projectName": "super_app", // Project name (used for folder names)
"outputDirectory": "output", // Where generated projects will be placed
"dryRun": false, // Enable dry-run mode (can be overridden by CLI)
"overwriteIfExists": true // Overwrite existing output directory if it exists
}
}Field Descriptions:
projectName(required): Used to generate folder names and project identifiers. Special characters are automatically sanitized (e.g., "My App" becomes "my_app"). This name will appear in generated project folders.outputDirectory(required): Relative path fromconfig.jsonlocation where generated projects will be placed. Default is"output". Generated projects will be in{outputDirectory}/flutter/{projectName}/and{outputDirectory}/rn/{projectName}/.dryRun(optional): Whentrue, no files are created or modified. Useful for testing configuration. Can be overridden by the--dry-runCLI flag. Default isfalse.overwriteIfExists(optional): Controls behavior when output directory already exists. Whenfalse, the tool will throw an error if the output directory exists. Whentrue, it will delete the existing directory and recreate it. Default isfalse.
{
"flavors": ["dev", "stage", "prod"]
}Field Descriptions:
- Defines the list of flavors (build variants) to generate for your application
- Each flavor gets its own configuration (Firebase configs, icons, environment files, package names, etc.)
- Common flavor names:
dev,stage,prod,qa,beta,demo - At least one flavor is required
- Flavor names are case-sensitive and must match exactly in all configuration sections
- Each flavor listed here must have corresponding entries in:
common.appDisplayNamecommon.apiBaseUrl(if used)- Firebase configs (if
useFirebaseis enabled) - Environment files (if
useEnvFilesis enabled) - Icons (if
useCustomIconsis enabled)
{
"common": {
"organization": "company", // Organization name
"appDisplayName": { // App display name per flavor
"dev": "Super App Dev",
"stage": "Super App Stage",
"prod": "Super App"
},
"apiBaseUrl": { // API base URLs per flavor
"dev": "https://api.dev.example.com",
"stage": "https://api.stage.example.com",
"prod": "https://api.example.com"
}
}
}Field Descriptions:
organization(optional): Organization name used in package names and bundle identifiers. Typically your company or organization identifier.appDisplayName(required): The name displayed on the device home screen and app launcher. Must have an entry for each flavor defined in theflavorsarray. This is what users see when they install your app.apiBaseUrl(optional): API base URLs for each flavor. These can be referenced in your environment files or used directly in app configuration. Useful for pointing different flavors to different backend environments.
{
"flutter": {
"enabled": true, // Enable/disable Flutter generation
"baseArchPath": "basearch_flutter", // Local path or Git URL
"baseArchBranch": "main", // Git branch (if using Git URL)
"baseArchUsername": null, // Git username (optional, can use ENV:)
"baseArchPassword": null, // Git password/token (optional, can use ENV:)
"resourcePath": "res_flutter" // Path to Flutter resources
}
}Base Architecture Options:
-
Local Path:
"baseArchPath": "basearch_flutter"- Uses local folder at project root
- Must contain
base_project_flutter/subfolder
-
Git URL with Embedded Credentials:
"baseArchPath": "https://username:token@bitbucket.org/workspace/repo.git", "baseArchBranch": "main"
- Credentials embedded in URL
- Branch specified separately
-
Git URL with Separate Credentials:
"baseArchPath": "https://bitbucket.org/workspace/repo.git", "baseArchBranch": "main", "baseArchUsername": "myuser", "baseArchPassword": "ENV:GIT_TOKEN"
- Use
ENV:VARIABLE_NAMEto read from environment variables - More secure for CI/CD pipelines
- Use
-
SSH URL:
"baseArchPath": "git@bitbucket.org:workspace/repo.git", "baseArchBranch": "main"
- Requires SSH keys to be configured
- No credentials needed in config
{
"dart": {
"organizationImport": "com.company.superapp" // Dart package organization
}
}Details:
- Used in import statements (e.g.,
import 'package:com.company.superapp/core/...') - Should match your organization's package naming convention
{
"android": {
"baseApplicationId": "com.company.superapp", // Base package name
"flavorSuffix": { // Suffix per flavor
"dev": ".dev",
"stage": ".stage",
"prod": ""
},
"minSdk": 24, // Minimum Android SDK version
"targetSdk": 34, // Target Android SDK version
"compileSdk": 34 // Compile SDK version
}
}Details:
baseApplicationId: Base package identifier. Final package will bebaseApplicationId + flavorSuffix- Example:
com.company.superapp.devfor dev flavor
- Example:
flavorSuffix: Added to baseApplicationId for each flavor. Empty string for production.- SDK versions: Must be valid Android SDK versions (typically 24-34)
{
"ios": {
"baseBundleId": "com.company.superapp", // Base bundle identifier
"flavorSuffix": { // Suffix per flavor
"dev": ".dev",
"stage": ".stage",
"prod": ""
},
"deploymentTarget": "13.0", // Minimum iOS version
"teamId": "XXXXXXXXXX" // Apple Developer Team ID
}
}Details:
baseBundleId: Base bundle identifier. Final bundle ID will bebaseBundleId + flavorSuffixdeploymentTarget: Minimum iOS version (e.g., "13.0", "14.0")teamId: Your Apple Developer Team ID (10 characters)
{
"firebase": {
"android": {
"dev": "res_flutter/firebase/dev/google-services.json",
"stage": "res_flutter/firebase/stage/google-services.json",
"prod": "res_flutter/firebase/prod/google-services.json"
},
"ios": {
"dev": "res_flutter/firebase/dev/GoogleService-Info.plist",
"stage": "res_flutter/firebase/stage/GoogleService-Info.plist",
"prod": "res_flutter/firebase/prod/GoogleService-Info.plist"
}
}
}Details:
- Paths are relative to the location of
config.json - Must provide both Android and iOS configs for each flavor if Firebase is enabled
- Files are copied to the appropriate locations in the generated project
{
"env": {
"dev": "res_flutter/env/.env.dev",
"stage": "res_flutter/env/.env.stage",
"prod": "res_flutter/env/.env.prod"
}
}Details:
- Environment files are copied to the project root
- Flutter uses
flutter_dotenvpackage to load these files - Each flavor gets its own
.env.{flavor}file
{
"icons": {
"android": {
"dev": "res_flutter/icons/dev/android",
"stage": "res_flutter/icons/stage/android",
"prod": "res_flutter/icons/prod/android"
},
"ios": {
"dev": "res_flutter/icons/dev/ios",
"stage": "res_flutter/icons/stage/ios",
"prod": "res_flutter/icons/prod/ios"
}
}
}Details:
- Android icons: Directory containing mipmap folders with icon files
- iOS icons: Directory containing
AppIcon.appiconset/with icon assets - Icons are copied to platform-specific locations
{
"assets": {
"copy": [
{
"from": "res_flutter/assets/common",
"to": "assets"
}
]
}
}Details:
from: Source path relative to config.jsonto: Destination path relative to project root- Supports both files and directories
- Multiple copy operations can be specified
{
"features": {
"useFlavors": true, // Enable multi-flavor support
"useFirebase": true, // Enable Firebase integration
"useEnvFiles": true, // Enable environment files
"useCustomIcons": true // Enable custom app icons
}
}Details:
useFlavors: When false, skips flavor-specific entry points and configurationsuseFirebase: When false, skips Firebase file copyinguseEnvFiles: When false, skips environment file copyinguseCustomIcons: When false, skips icon copying
{
"signing": {
"android": {
"dev": {
"storeFile": "res_flutter/signing/android/dev/keystore.jks",
"storePassword": "ENV:FLUTTER_DEV_KEYSTORE_PASSWORD",
"keyAlias": "dev-key",
"keyPassword": "ENV:FLUTTER_DEV_KEY_PASSWORD"
}
},
"ios": {
"dev": {
"teamId": "XXXXXXXXXX",
"provisioningProfile": "res_flutter/signing/ios/dev/profile.mobileprovision"
}
}
}
}Details:
- Android:
storeFile: Path to keystore file (.jks)storePassword: Keystore password (useENV:VARIABLE_NAMEfor security)keyAlias: Key alias namekeyPassword: Key password (useENV:VARIABLE_NAMEfor security)
- iOS:
teamId: Apple Developer Team IDprovisioningProfile: Path to provisioning profile file
React Native configuration follows the same structure as Flutter, with these differences:
- No
dartsection (not applicable) baseArchPathpoints directly to React Native project root (no subfolder needed)- Uses
app.jsonandpackage.jsoninstead ofpubspec.yaml - Uses
react-native-configfor environment variables
Your Flutter base architecture repository should have this structure:
flutter-base-arch/
└── base_project_flutter/ # This folder name is required
├── lib/
│ ├── main.dart
│ └── ...
├── android/
├── ios/
├── pubspec.yaml
└── ...
Important: The Flutter base architecture must contain a base_project_flutter/ subfolder. This is where your Flutter project code lives.
Your React Native base architecture repository should have this structure:
rn-base-arch/ # Root is the project
├── src/
├── android/
├── ios/
├── package.json
├── app.json
└── ...
Important: The React Native base architecture root should be the project root directly (no subfolder needed).
Android (google-services.json):
- Download from Firebase Console
- Place in
res_flutter/firebase/{flavor}/google-services.json - One file per flavor
iOS (GoogleService-Info.plist):
- Download from Firebase Console
- Place in
res_flutter/firebase/{flavor}/GoogleService-Info.plist - One file per flavor
Create .env.{flavor} files with your environment variables:
# res_flutter/env/.env.dev
API_URL=https://api.dev.example.com
API_KEY=dev_key_123
DEBUG=true
The tool will copy these to the project root as .env.dev, .env.stage, .env.prod.
Android Icons:
- Create icons for all densities: mdpi, hdpi, xhdpi, xxhdpi, xxxhdpi
- Place in
res_flutter/icons/{flavor}/android/mipmap-{density}/ - Include adaptive icon files in
mipmap-anydpi-v26/
iOS Icons:
- Create AppIcon.appiconset with all required sizes
- Place in
res_flutter/icons/{flavor}/ios/AppIcon.appiconset/ - Include all sizes from 20x20 to 1024x1024
Android Keystore:
- Generate keystore:
keytool -genkey -v -keystore keystore.jks -keyalg RSA -keysize 2048 -validity 10000 -alias your-alias - Place in
res_flutter/signing/android/{flavor}/keystore.jks - Store passwords securely (use environment variables in config)
iOS Provisioning Profile:
- Download from Apple Developer Portal
- Place in
res_flutter/signing/ios/{flavor}/profile.mobileprovision
When starting a new mobile application project:
- Clone your base architecture repositories (or ensure they're accessible)
- Create a new
config.jsonwith your project details - Set up resource folders with Firebase configs, icons, and environment files
- Run with
--dry-runto validate - Generate the project
- Start development in the generated project
To create dev, stage, and production variants:
- Define all three flavors in the
flavorsarray - Provide separate Firebase configs, icons, and environment files for each
- Configure different package names/bundle IDs using
flavorSuffix - The tool will generate entry points and build configurations for each flavor
For teams working together:
- Store base architectures in Git repositories (recommended)
- Use environment variables for all sensitive data
- Version control
config.json(but not sensitive resource files) - Document resource file requirements in team wiki/docs
- Use consistent naming conventions across the team
For automated project generation:
- Store configuration as code in your repository
- Use CI/CD secrets for all credentials and passwords
- Run validation step with
--dry-runbefore actual generation - Archive generated projects as build artifacts
- Use Git URLs for base architectures to ensure version consistency
{
"meta": {
"projectName": "my_app",
"outputDirectory": "output",
"overwriteIfExists": true
},
"flavors": ["dev", "prod"],
"common": {
"organization": "mycompany",
"appDisplayName": {
"dev": "My App Dev",
"prod": "My App"
}
},
"flutter": {
"enabled": true,
"baseArchPath": "https://user:token@bitbucket.org/workspace/flutter-base.git",
"baseArchBranch": "main",
"resourcePath": "res_flutter",
"android": {
"baseApplicationId": "com.mycompany.myapp",
"flavorSuffix": {
"dev": ".dev",
"prod": ""
}
},
"ios": {
"baseBundleId": "com.mycompany.myapp",
"flavorSuffix": {
"dev": ".dev",
"prod": ""
}
},
"features": {
"useFlavors": true,
"useFirebase": false,
"useEnvFiles": true,
"useCustomIcons": false
}
},
"reactNative": {
"enabled": false
}
}{
"meta": {
"projectName": "rn_app",
"outputDirectory": "output"
},
"flavors": ["dev", "stage", "prod"],
"reactNative": {
"enabled": true,
"baseArchPath": "basearch_rn",
"resourcePath": "res_rn",
"android": {
"baseApplicationId": "com.company.rnapp",
"flavorSuffix": {
"dev": ".dev",
"stage": ".stage",
"prod": ""
}
},
"features": {
"useFirebase": true,
"useEnvFiles": true,
"useCustomIcons": true
}
},
"flutter": {
"enabled": false
}
}{
"meta": {
"projectName": "super_app",
"outputDirectory": "output"
},
"flavors": ["dev", "stage", "prod"],
"common": {
"organization": "company",
"appDisplayName": {
"dev": "Super App Dev",
"stage": "Super App Stage",
"prod": "Super App"
},
"apiBaseUrl": {
"dev": "https://api.dev.example.com",
"stage": "https://api.stage.example.com",
"prod": "https://api.example.com"
}
},
"flutter": {
"enabled": true,
"baseArchPath": "https://user:token@bitbucket.org/workspace/flutter-repo.git",
"baseArchBranch": "main",
"resourcePath": "res_flutter",
"features": {
"useFlavors": true,
"useFirebase": true,
"useEnvFiles": true,
"useCustomIcons": true
},
"signing": {
"android": {
"prod": {
"storeFile": "res_flutter/signing/android/prod/keystore.jks",
"storePassword": "ENV:FLUTTER_PROD_KEYSTORE_PASSWORD",
"keyAlias": "prod-key",
"keyPassword": "ENV:FLUTTER_PROD_KEY_PASSWORD"
}
}
}
},
"reactNative": {
"enabled": true,
"baseArchPath": "https://user:token@bitbucket.org/workspace/rn-repo.git",
"baseArchBranch": "main",
"resourcePath": "res_rn",
"features": {
"useFlavors": true,
"useFirebase": true,
"useEnvFiles": true,
"useCustomIcons": true
}
}
}Problem: The tool cannot find the base architecture folder.
Solutions:
- If using local path: Verify the folder exists at the specified path relative to
config.json - If using Git URL: Check your credentials and repository URL
- For Flutter: Ensure
base_project_flutter/subfolder exists - Verify the path in
config.jsonis correct
Problem: Cannot authenticate with Git repository.
Solutions:
- Verify your Bitbucket App Password is correct (not your account password)
- Check that credentials are properly embedded in URL:
https://username:token@host - For SSH: Ensure SSH keys are configured and added to Bitbucket
- Try using environment variables instead of embedding credentials
Problem: Required resource files are missing.
Solutions:
- Verify
resourcePathin config matches your actual folder name - Ensure all required files exist for enabled features
- Check file paths are relative to
config.jsonlocation - Run with
--dry-runto see which files are missing
Problem: Specified branch doesn't exist in repository.
Solutions:
- Verify branch name is correct (case-sensitive)
- List branches:
git ls-remote --heads <repo-url> - Set
baseArchBranchtonullto use default branch - Check that the branch exists in the remote repository
Problem: Output directory exists and overwriteIfExists is false.
Solutions:
- Set
"overwriteIfExists": truein config - Or delete the existing output directory manually
- Or use a different
outputDirectorypath
Problem: Configuration validation fails.
Solutions:
- Check that all required fields are present
- Verify flavor names match between
flavorsarray and individual configs - Ensure all enabled features have corresponding resource files
- Review error messages for specific missing items
When encountering issues, follow these steps in order:
-
Run with
--dry-runfirst to see what would happen without making changes:node setup-app.js --config config.json --dry-run
-
Check validation errors - The tool provides specific error messages pointing to exact issues. Read them carefully as they usually indicate:
- Missing required fields
- Incorrect file paths
- Missing resource files
- Configuration mismatches
-
Verify file paths - All paths in
config.jsonare relative to theconfig.jsonfile location. Ensure:- Resource paths point to existing files
- Base architecture paths are correct
- All referenced files actually exist
-
Check Git access - If using Git URLs:
# Test HTTPS access git ls-remote https://username:token@bitbucket.org/workspace/repo.git # Test SSH access git ls-remote git@bitbucket.org:workspace/repo.git
-
Verify permissions - Ensure you have:
- Read access to all resource files and base architectures
- Write access to the output directory
- Execute permissions for Node.js and Git
-
Check environment variables - If using
ENV:VARIABLE_NAME:# Verify variable is set echo $GIT_TOKEN # Or on Windows echo %GIT_TOKEN%
-
Review the logs - The tool provides detailed logging. Look for:
- Warning messages about missing optional files
- Error messages about required files
- Success messages confirming operations
Set DEBUG=true environment variable for detailed error output:
DEBUG=true node setup-app.js --config config.jsonThis will show full stack traces for errors, making it easier to identify issues.
-
Always test with
--dry-runfirst before running the actual setup. This helps catch configuration errors early. -
Use environment variables for sensitive data (passwords, tokens, keystore passwords) instead of hardcoding them in
config.json. Use theENV:VARIABLE_NAMEformat. -
Version control your
config.jsonbut exclude sensitive resource files (keystores, provisioning profiles) from version control. Add them to.gitignore. -
Use Git URLs for base architectures to ensure consistency across team members and CI/CD pipelines. This ensures everyone uses the same base architecture version.
-
Organize resources clearly following the directory structure guidelines. Consistent organization makes it easier for team members to find and update resources.
-
Test with minimal features first then enable additional features incrementally. Start with basic configuration, then add Firebase, then icons, then signing.
-
Keep base architectures updated in their repositories. When you update your base architecture, all new projects will automatically use the latest version.
-
Use descriptive project names that reflect the actual application. Avoid generic names like "app" or "test".
-
Document your configuration with comments in JSON (though JSON doesn't support comments, consider maintaining a separate documentation file for complex configurations).
-
Use environment variables in CI/CD for all sensitive data. Set them as secrets in your CI/CD platform.
-
Run validation in CI/CD before generating projects. Use
--dry-runin your CI pipeline to validate configurations. -
Cache base architecture clones in CI/CD if possible to speed up builds, though the tool automatically cleans up temporary clones.
-
Generate projects in isolated environments to avoid conflicts between different project generations.
After running the tool, your generated projects will be in:
output/
├── flutter/
│ └── project_name/ # Flutter project
│ ├── lib/
│ │ ├── main.dart
│ │ ├── main_dev.dart # Flavor-specific entry points
│ │ ├── main_stage.dart
│ │ ├── main_prod.dart
│ │ └── ...
│ ├── android/
│ │ ├── app/
│ │ │ ├── build.gradle
│ │ │ └── src/
│ │ └── ...
│ ├── ios/
│ │ ├── Runner.xcodeproj
│ │ └── ...
│ ├── .env.dev # Environment files
│ ├── .env.stage
│ ├── .env.prod
│ └── pubspec.yaml
└── rn/
└── project_name/ # React Native project
├── src/
├── android/
│ ├── app/
│ └── ...
├── ios/
│ └── ...
├── .env.dev
├── .env.stage
├── .env.prod
├── package.json
└── app.json
-
Navigate to the project directory:
cd output/flutter/project_name -
Install dependencies:
flutter pub get
-
Run the app:
# Development flavor flutter run --flavor dev -t lib/main_dev.dart # Staging flavor flutter run --flavor stage -t lib/main_stage.dart # Production flavor flutter run --flavor prod -t lib/main_prod.dart
-
Build for release:
flutter build apk --flavor prod -t lib/main_prod.dart flutter build ios --flavor prod -t lib/main_prod.dart
-
Navigate to the project directory:
cd output/rn/project_name -
Install dependencies:
npm install # or yarn install -
Run the app:
# Android - Development npx react-native run-android --mode=developmentdebug # Android - Staging npx react-native run-android --mode=stagedebug # Android - Production npx react-native run-android --mode=productionrelease # iOS - Development npx react-native run-ios --scheme=project_name-dev # iOS - Staging npx react-native run-ios --scheme=project_name-stage # iOS - Production npx react-native run-ios --scheme=project_name-prod
-
Build for release:
# Android cd android && ./gradlew assembleProductionRelease # iOS # Use Xcode to build and archive
This tool is designed to work seamlessly in CI/CD pipelines. Here's how to integrate it:
name: Generate Mobile Apps
on:
workflow_dispatch:
inputs:
project_name:
description: 'Project name'
required: true
jobs:
generate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
- name: Generate Flutter App
env:
GIT_TOKEN: ${{ secrets.BITBUCKET_APP_PASSWORD }}
FLUTTER_PROD_KEYSTORE_PASSWORD: ${{ secrets.FLUTTER_KEYSTORE_PASSWORD }}
run: |
node setup-app.js --config config.json
- name: Upload artifacts
uses: actions/upload-artifact@v3
with:
name: generated-apps
path: output/generate_apps:
stage: build
image: node:18
before_script:
- npm install -g git
script:
- node setup-app.js --config config.json
artifacts:
paths:
- output/
expire_in: 1 week
only:
- mainpipeline {
agent any
environment {
GIT_TOKEN = credentials('bitbucket-app-password')
KEYSTORE_PASSWORD = credentials('keystore-password')
}
stages {
stage('Generate Apps') {
steps {
sh 'node setup-app.js --config config.json'
}
}
stage('Archive') {
steps {
archiveArtifacts 'output/**'
}
}
}
}- Set all sensitive values as environment variables or secrets
- Use
--dry-runin a validation stage before actual generation - Cache the tool repository to speed up builds
- Archive generated projects as build artifacts
- Run generation in isolated containers/environments
- Validate configuration files before running the tool
This tool is provided as-is for generating mobile applications from base architectures.