diff --git a/DEVELOPER.md b/DEVELOPER.md
index a0b731d..193411c 100644
--- a/DEVELOPER.md
+++ b/DEVELOPER.md
@@ -800,33 +800,104 @@ The app uses a **clean, release-triggered workflow** that rebuilds from scratch
## Build & Development Setup
### Prerequisites
-- **Flutter SDK**: Latest stable version
-- **Xcode**: For iOS builds (macOS only)
-- **Android Studio**: For Android builds
-- **Git**: For version control
+
+**macOS** (required for iOS builds; Android-only contributors can use macOS or Linux):
+
+| Tool | Install | Notes |
+|------|---------|-------|
+| **Homebrew** | [brew.sh](https://brew.sh) | Package manager for macOS |
+| **Flutter SDK 3.35+** | `brew install --cask flutter` | Installs Flutter + Dart (3.35+ required for RadioGroup widget) |
+| **Xcode** | Mac App Store | Required for iOS builds |
+| **CocoaPods** | `brew install cocoapods` | Required for iOS plugin resolution |
+| **Android SDK** | See below | Required for Android builds |
+| **Java 17+** | `brew install --cask temurin` | Required by Android toolchain (skip if already installed) |
+
+After installing, verify with:
+```bash
+flutter doctor # All checks should be green
+```
+
+### Android SDK Setup (without Android Studio)
+
+You don't need the full Android Studio IDE. Install the command-line tools and let Flutter's build system pull what it needs:
+
+```bash
+# 1. Install command-line tools
+brew install --cask android-commandlinetools
+
+# 2. Create the SDK directory and install required components
+mkdir -p ~/Library/Android/sdk/licenses
+# Write license acceptance hashes
+printf "\n24333f8a63b6825ea9c5514f83c2829b004d1fee" > ~/Library/Android/sdk/licenses/android-sdk-license
+printf "\n84831b9409646a918e30573bab4c9c91346d8abd" > ~/Library/Android/sdk/licenses/android-sdk-preview-license
+
+# 3. Install platform tools and the SDK platform Flutter needs
+"$(brew --prefix android-commandlinetools)/cmdline-tools/latest/bin/sdkmanager" \
+ --sdk_root="$HOME/Library/Android/sdk" \
+ "platform-tools" "platforms;android-36" "build-tools;35.0.0"
+
+# 4. Copy cmdline-tools into the SDK root (Flutter expects them there)
+mkdir -p ~/Library/Android/sdk/cmdline-tools
+cp -R "$(brew --prefix android-commandlinetools)/cmdline-tools/latest" \
+ ~/Library/Android/sdk/cmdline-tools/latest
+
+# 5. Point Flutter at the SDK and accept licenses
+flutter config --android-sdk ~/Library/Android/sdk
+yes | flutter doctor --android-licenses
+```
+
+> **Note:** The first `flutter build apk` will auto-download additional components it needs (NDK, CMake, etc). This is normal and only happens once.
### OAuth2 Setup
-**Required registrations:**
+To run the app with working OSM authentication, register OAuth2 applications:
+
1. **Production OSM**: https://www.openstreetmap.org/oauth2/applications
2. **Sandbox OSM**: https://master.apis.dev.openstreetmap.org/oauth2/applications
-**Configuration:**
+For local builds, create `build_keys.conf` (gitignored):
```bash
-cp lib/keys.dart.example lib/keys.dart
-# Edit keys.dart with your OAuth2 client IDs
+cp build_keys.conf.example build_keys.conf
+# Edit build_keys.conf with your OAuth2 client IDs
```
-### iOS Setup
+You can also pass keys directly via `--dart-define`:
```bash
-cd ios && pod install
+flutter run --dart-define=OSM_PROD_CLIENTID=your_id --dart-define=OSM_SANDBOX_CLIENTID=your_id
```
+### First Build
+
+```bash
+# 1. Install dependencies
+flutter pub get
+
+# 2. Generate icons and splash screens (gitignored, must be regenerated)
+./gen_icons_splashes.sh
+
+# 3. Build Android
+flutter build apk --debug \
+ --dart-define=OSM_PROD_CLIENTID=your_id \
+ --dart-define=OSM_SANDBOX_CLIENTID=your_id
+
+# 4. Build iOS (macOS only, no signing needed for testing)
+flutter build ios --no-codesign \
+ --dart-define=OSM_PROD_CLIENTID=your_id \
+ --dart-define=OSM_SANDBOX_CLIENTID=your_id
+```
+
+> **Important:** You must run `./gen_icons_splashes.sh` before the first build. The generated icons and splash screen assets are gitignored, so the build will fail without this step.
+
### Running
+
```bash
-flutter pub get
-./gen_icons_splashes.sh
-flutter run --dart-define=OSM_PROD_CLIENT_ID=[your OAuth2 client ID]
+# Run on connected device or simulator
+flutter run --dart-define=OSM_PROD_CLIENTID=your_id --dart-define=OSM_SANDBOX_CLIENTID=your_id
+
+# Or use the build script (reads keys from build_keys.conf)
+./do_builds.sh # Both platforms
+./do_builds.sh --android # Android only
+./do_builds.sh --ios # iOS only
```
### Testing
diff --git a/README.md b/README.md
index 1f98124..d9a7364 100644
--- a/README.md
+++ b/README.md
@@ -90,12 +90,16 @@ A comprehensive Flutter app for mapping public surveillance infrastructure with
- Code organization and contribution guidelines
- Debugging tips and troubleshooting
-**Quick setup:**
+**Quick setup (macOS with Homebrew):**
```shell
-flutter pub get
-cp lib/keys.dart.example lib/keys.dart
-# Add OAuth2 client IDs, then: flutter run
+brew install --cask flutter # Install Flutter SDK
+brew install cocoapods # Required for iOS
+flutter pub get # Install dependencies
+./gen_icons_splashes.sh # Generate icons & splash screens (required before first build)
+cp build_keys.conf.example build_keys.conf # Add your OSM OAuth2 client IDs
+./do_builds.sh # Build both platforms
```
+See [DEVELOPER.md](DEVELOPER.md) for cross-platform instructions and Android SDK setup.
**Releases**: The app uses GitHub's release system for automated building and store uploads. Simply create a GitHub release and use the "pre-release" checkbox to control whether builds go to app stores - checked for beta releases, unchecked for production releases.
diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts
index 6b9f9c4..339fc1c 100644
--- a/android/app/build.gradle.kts
+++ b/android/app/build.gradle.kts
@@ -39,7 +39,7 @@ android {
// ────────────────────────────────────────────────────────────
// oauth2_client 4.x & flutter_web_auth_2 5.x require minSdk 23
// ────────────────────────────────────────────────────────────
- minSdk = 23
+ minSdk = maxOf(flutter.minSdkVersion, 23)
targetSdk = 36
// Flutter tool injects these during `flutter build`
diff --git a/ios/Flutter/AppFrameworkInfo.plist b/ios/Flutter/AppFrameworkInfo.plist
index 7c56964..1dc6cf7 100644
--- a/ios/Flutter/AppFrameworkInfo.plist
+++ b/ios/Flutter/AppFrameworkInfo.plist
@@ -21,6 +21,6 @@
CFBundleVersion
1.0
MinimumOSVersion
- 12.0
+ 13.0
diff --git a/ios/Podfile b/ios/Podfile
index e549ee2..620e46e 100644
--- a/ios/Podfile
+++ b/ios/Podfile
@@ -1,5 +1,5 @@
# Uncomment this line to define a global platform for your project
-# platform :ios, '12.0'
+# platform :ios, '13.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj
index 86f3226..691d14c 100644
--- a/ios/Runner.xcodeproj/project.pbxproj
+++ b/ios/Runner.xcodeproj/project.pbxproj
@@ -455,7 +455,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 12.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 13.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
@@ -588,7 +588,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 12.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 13.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
@@ -639,7 +639,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 12.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 13.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
diff --git a/pubspec.yaml b/pubspec.yaml
index 1a50411..5e05501 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -4,7 +4,7 @@ publish_to: "none"
version: 2.6.4+47 # The thing after the + is the version code, incremented with each release
environment:
- sdk: ">=3.5.0 <4.0.0" # oauth2_client 4.x needs Dart 3.5+
+ sdk: ">=3.8.0 <4.0.0" # RadioGroup widget requires Dart 3.8+ (Flutter 3.35+)
dependencies:
flutter: