A new Flutter project.
This document explains how to build the Bitcoin Silver Wallet with RPC credentials for production.
NEVER commit RPC credentials to version control. The app uses environment variables during build time to inject credentials securely.
For RPC credentials please contact @mrvistos or @janosraul in BTCS official Tg: https://t.me/official_bitcoinsilver
flutter build apk --dart-define=RPC_URL=http://YOUR_RPC_URL:PORT \
--dart-define=RPC_USER=your_rpc_user \
--dart-define=RPC_PASSWORD=your_rpc_passwordFor iOS:
flutter build ios --dart-define=RPC_URL=http://YOUR_RPC_URL:PORT \
--dart-define=RPC_USER=your_rpc_user \
--dart-define=RPC_PASSWORD=your_rpc_passwordCreate a file named dart_defines.json (add to .gitignore):
{
"RPC_URL": "http://YOUR_RPC_URL:PORT",
"RPC_USER": "your_rpc_user",
"RPC_PASSWORD": "your_rpc_password"
}Then use:
flutter build apk --dart-define-from-file=dart_defines.jsonflutter run --dart-define-from-file=dart_defines.jsonCreate a build.sh script:
#!/bin/bash
# Load from environment or .env file
source .env # or export variables manually
flutter build apk \
--dart-define=RPC_URL="$RPC_URL" \
--dart-define=RPC_USER="$RPC_USER" \
--dart-define=RPC_PASSWORD="$RPC_PASSWORD"For development without credentials (will need manual RPC setup in app):
flutter run
# or
flutter build apk- name: Build APK
env:
RPC_URL: ${{ secrets.RPC_URL }}
RPC_USER: ${{ secrets.RPC_USER }}
RPC_PASSWORD: ${{ secrets.RPC_PASSWORD }}
run: |
flutter build apk \
--dart-define=RPC_URL="$RPC_URL" \
--dart-define=RPC_USER="$RPC_USER" \
--dart-define=RPC_PASSWORD="$RPC_PASSWORD"build:
script:
- flutter build apk
--dart-define=RPC_URL="$RPC_URL"
--dart-define=RPC_USER="$RPC_USER"
--dart-define=RPC_PASSWORD="$RPC_PASSWORD"
variables:
RPC_URL: $CI_RPC_URL
RPC_USER: $CI_RPC_USER
RPC_PASSWORD: $CI_RPC_PASSWORDAfter building, the credentials will be stored securely in the device's secure storage and retrieved at runtime.
- β Never commit credentials to git
- β Use environment variables or secure CI/CD secrets
- β
Add
dart_defines.jsonto.gitignore - β Rotate credentials regularly
- β Use different credentials for development/staging/production
# Build AAB with RPC credentials
flutter build appbundle \
--dart-define=RPC_URL=http://your-rpc-url:port \
--dart-define=RPC_USER=your_username \
--dart-define=RPC_PASSWORD=your_passwordOr using config file:
flutter build appbundle --dart-define-from-file=dart_defines.jsonGoogle Play will manage your app signing key.
- Generate upload keystore:
keytool -genkey -v -keystore ~/upload-keystore.jks \
-keyalg RSA -keysize 2048 -validity 10000 \
-alias upload- Create
android/key.properties:
storePassword=your_store_password
keyPassword=your_key_password
keyAlias=upload
storeFile=/path/to/upload-keystore.jks- Update
android/app/build.gradle:
def keystoreProperties = new Properties()
def keystorePropertiesFile = rootProject.file('key.properties')
if (keystorePropertiesFile.exists()) {
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
}
android {
...
signingConfigs {
release {
keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
storePassword keystoreProperties['storePassword']
}
}
buildTypes {
release {
signingConfig signingConfigs.release
minifyEnabled true
shrinkResources true
}
}
}Let Google Play manage everything - just upload and they handle signing.
Edit pubspec.yaml:
version: 1.0.3+3 # 1.0.3 is version name, 3 is version codeEdit android/app/build.gradle:
android {
...
defaultConfig {
applicationId "com.bitcoinsilver.wallet" # Your unique ID
minSdkVersion 21
targetSdkVersion 34
versionCode 3
versionName "1.0.3"
}
}flutter build appbundle --release \
--dart-define=RPC_URL=http://your-rpc-url:port \
--dart-define=RPC_USER=your_username \
--dart-define=RPC_PASSWORD=your_passwordflutter build appbundle --release \
--obfuscate \
--split-debug-info=build/app/outputs/symbols \
--dart-define=RPC_URL=http://your-rpc-url:port \
--dart-define=RPC_USER=your_username \
--dart-define=RPC_PASSWORD=your_password# Create dart_defines.json with your credentials
flutter build appbundle --release \
--obfuscate \
--split-debug-info=build/app/outputs/symbols \
--dart-define-from-file=dart_defines.json
flutter build appbundle --release --obfuscate --split-debug-info=build/app/outputs/symbols --dart-define-from-file=dart_defines.jsonThe AAB file will be created at:
build/app/outputs/bundle/release/app-release.aab
- Go to Google Play Console
- Select your app (or create new app)
- Go to Production β Create new release
- Upload
app-release.aab - Fill in release notes
- Review and roll out
Create build_playstore.sh:
#!/bin/bash
# Load environment variables
if [ -f .env ]; then
export $(cat .env | xargs)
fi
# Clean previous builds
flutter clean
flutter pub get
# Build AAB with obfuscation
flutter build appbundle --release \
--obfuscate \
--split-debug-info=build/app/outputs/symbols \
--dart-define=RPC_URL="$RPC_URL" \
--dart-define=RPC_USER="$RPC_USER" \
--dart-define=RPC_PASSWORD="$RPC_PASSWORD"
echo "β
Build complete!"
echo "π¦ AAB location: build/app/outputs/bundle/release/app-release.aab"Make executable:
chmod +x build_playstore.sh
./build_playstore.sh.github/workflows/release.yml:
name: Release to Play Store
on:
push:
tags:
- 'v*'
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-java@v3
with:
distribution: 'zulu'
java-version: '17'
- uses: subosito/flutter-action@v2
with:
flutter-version: '3.35.3'
- name: Decode keystore
run: |
echo "${{ secrets.KEYSTORE_BASE64 }}" | base64 -d > android/app/keystore.jks
- name: Create key.properties
run: |
echo "storePassword=${{ secrets.KEYSTORE_PASSWORD }}" > android/key.properties
echo "keyPassword=${{ secrets.KEY_PASSWORD }}" >> android/key.properties
echo "keyAlias=${{ secrets.KEY_ALIAS }}" >> android/key.properties
echo "storeFile=keystore.jks" >> android/key.properties
- name: Build AAB
run: |
flutter pub get
flutter build appbundle --release \
--obfuscate \
--split-debug-info=build/app/outputs/symbols \
--dart-define=RPC_URL="${{ secrets.RPC_URL }}" \
--dart-define=RPC_USER="${{ secrets.RPC_USER }}" \
--dart-define=RPC_PASSWORD="${{ secrets.RPC_PASSWORD }}"
- name: Upload to Play Store
uses: r0adkll/upload-google-play@v1
with:
serviceAccountJsonPlainText: ${{ secrets.PLAY_STORE_JSON }}
packageName: com.bitcoinsilver.wallet
releaseFiles: build/app/outputs/bundle/release/app-release.aab
track: productionSolution: Make sure to use --release flag
Solution: Set up signing config in build.gradle
Solution: Increment version in pubspec.yaml
Solution: Verify dart-define values are set correctly
Before uploading to Play Store:
- RPC credentials set via --dart-define (not hardcoded)
- Keystore file is secure and backed up
- key.properties is in .gitignore
- Obfuscation enabled for production
- Version code incremented
- Test the AAB on a real device before upload
- ProGuard rules configured if needed
- APK: Larger, includes all architectures
- AAB: Smaller, Google Play optimizes per device
- Typical AAB: 20-50% smaller than APK
- Build AAB with credentials
- Test on real device (install from AAB)
- Upload to Play Store Internal Testing
- Graduate to Production when ready
The Bitcoin Silver Wallet uses a secure, production-ready approach for managing RPC node credentials:
- β No hardcoded credentials in source code
- β Environment-based configuration during build time
- β Encrypted storage on device using platform-specific secure storage
- β Runtime retrieval from secure storage
- Build Time: Credentials are injected via
--dart-defineflags - First Launch: Credentials are stored in encrypted secure storage (Keychain/KeyStore)
- Runtime: Credentials are retrieved securely from device storage
- Protection: All credentials protected by device security (biometrics/PIN)
Quick start:
# Copy and configure environment
cp .env.example .env
# Edit .env with your credentials
# Build with credentials
flutter build apk \
--dart-define-from-file=dart_defines.json- iOS: Uses Keychain Services
- Android: Uses Android KeyStore
- Encrypted at rest
- Optional biometric lock on app launch
- Re-authentication on app resume from background
- Configurable in Settings
- Stored in Flutter Secure Storage
- Never logged or transmitted
- Optional biometric protection before display
- All RPC communications use authenticated requests
- Credentials never exposed in UI or logs
When deploying to production:
- Build with
--dart-defineflags (never use hardcoded values) - Store credentials in CI/CD secrets (GitHub Actions, GitLab CI, etc.)
- Enable biometric authentication for users
- Use HTTPS for RPC endpoints when possible
- Rotate RPC credentials regularly
- Different credentials for dev/staging/production
- Review
.gitignoreto ensure no credential files committed
If you discover a security vulnerability, please email [security contact] instead of using the issue tracker.
- GDPR: No personal data collected or transmitted
- Data Privacy: All sensitive data encrypted at rest
- Open Source: Full transparency of security implementation