Before: Backend URLs were hardcoded and visible to anyone who reverse-engineers the APK After: URLs are environment-based and can be obfuscated during build
class AppConfig {
static const String _baseUrl = String.fromEnvironment(
'API_BASE_URL',
defaultValue: 'https://api.skillsocket.dev/api',
);
static String get baseUrl => _baseUrl;
static String get socketUrl => _socketUrl;
// ... other endpoints
}flutter build apk --release \
--dart-define=API_BASE_URL=https://skillsocket-backend.onrender.com/api \
--dart-define=SOCKET_BASE_URL=https://skillsocket-backend.onrender.com/flutter build apk --debug \
--dart-define=API_BASE_URL=http://localhost:3000/api \
--dart-define=SOCKET_BASE_URL=http://localhost:3000/All services now use AppConfig:
// Before (❌ Insecure)
static const String baseUrl = 'https://skillsocket-backend.onrender.com/api';
// After (✅ Secure)
static String get baseUrl => AppConfig.userUrl;- URLs are not hardcoded in source code
- Compile-time constants make reverse engineering harder
- Environment-specific builds possible
- Different URLs for dev/staging/production
- No sensitive URLs in version control
- Build scripts handle environment injection
- Code Obfuscation:
--obfuscateflag during build - ProGuard: Minifies and obfuscates Android code
- Certificate Pinning: Can be added for extra security
# Run development build script
build_development.bat
# Or use Flutter directly
flutter run --dart-define=API_BASE_URL=http://localhost:3000/api# Run production build script
build_production.bat
# Or use Flutter directly with obfuscation
flutter build apk --release --obfuscate --split-debug-info=debug-info/ \
--dart-define=API_BASE_URL=https://skillsocket-backend.onrender.com/apiclass SecureHttpClient {
static final HttpClient client = HttpClient()
..badCertificateCallback = (cert, host, port) {
// Verify certificate against pinned certificates
return verifyCertificate(cert, host);
};
}class ApiKeyManager {
static String getEncryptedApiKey() {
// Decrypt API key at runtime
return decryptApiKey(encryptedKey);
}
}class RequestSigner {
static Map<String, String> signRequest(Map<String, dynamic> data) {
final signature = generateHMAC(data, secretKey);
return {'signature': signature, ...headers};
}
}| Aspect | Before (❌) | After (✅) |
|---|---|---|
| URL Visibility | Hardcoded in source | Environment-based |
| Reverse Engineering | Easy to extract URLs | Harder to find URLs |
| Environment Management | Single hardcoded URL | Multiple environments |
| Build Security | No obfuscation | Optional obfuscation |
| Configuration | Manual URL changes | Automated via builds |
Solution: Check environment variables in build command
Solution: Use --obfuscate flag and ensure environment variables are used
Solution: Use different app IDs for different environments
- All hardcoded URLs removed from source code
- AppConfig class implemented
- All services updated to use AppConfig
- Build scripts created for different environments
- Production build uses obfuscation
- Environment variables not committed to git
- Test both development and production builds
- Verify URLs are not easily visible in APK
- Never commit real URLs to version control
- Use different domains for different environments
- Implement certificate pinning for production
- Use build-time constants instead of runtime configuration
- Test security by reverse engineering your own APK
- Monitor for leaked credentials in logs/crashes
# Secure production build
flutter build apk --release \
--obfuscate \
--split-debug-info=debug-info/ \
--dart-define=API_BASE_URL=https://your-production-api.com/api \
--dart-define=SOCKET_BASE_URL=https://your-production-api.com/This approach significantly improves security while maintaining flexibility for different environments! 🔐✨