---
name: flutter-cross-architecture-build
description: Build Flutter apps when the development environment architecture doesn't match Flutter SDK support (e.g., ARM64 Linux). Use GitHub Actions or CI/CD to cross-compile on x86_64 runners.
trigger:
  - "Flutter ARM64"
  - "build Flutter on ARM"
  - "cross-compile Flutter"
  - "Flutter Linux aarch64"
  - "GitHub Actions Flutter build"
---

# Flutter Cross-Architecture Build

Flutter **does not provide official ARM64 Linux SDK**. If you're on ARM64 (aarch64) Linux, you cannot run the Flutter tool locally.

## The Problem

- Flutter SDK downloads are x86_64 only for Linux
- `flutter doctor`, `flutter build`, etc. fail with "Exec format error"
- Common on: OCI Ampere (ARM64), AWS Graviton, Raspberry Pi 64-bit

## Solution: GitHub Actions CI/CD

Use GitHub's x86_64 runners to build your Flutter app automatically.

### Workflow Setup\n\n**Critical**: If your Flutter project lacks proper structure (missing `android/`, `ios/`, `pubspec.yaml` not at root), use the **backup-restore pattern**:\n\n```yaml\nname: Build Flutter App\n\non:\n  push:\n    branches: [ master, main ]\n  workflow_dispatch:\n\njobs:\n  build-android:\n    runs-on: ubuntu-latest  # x86_64 runner\n    steps:\n    - uses: actions/checkout@v4\n    - name: Setup Flutter\n      uses: subosito/flutter-action@v2\n      with:\n        flutter-version: '3.29.0'\n        channel: 'stable'\n    \n    - name: Backup custom code\n      run: |\n        mkdir -p /tmp/flutter_app_backup/lib/pages\n        cp -r frontend/lib/* /tmp/flutter_app_backup/lib/ || true\n        cp frontend/pubspec.yaml /tmp/flutter_app_backup/ || true\n        # VERIFY: Ensure you backup from the correct directory (frontend/, not frontend_backup/)\n    \n    - name: Remove old frontend and create new Flutter project\n      run: |\n        rm -rf frontend\n        flutter create --org com.example --project-name my_app frontend\n    \n    - name: Restore custom code\n      run: |\n        cp -r /tmp/flutter_app_backup/lib/* frontend/lib/ || true\n        cp /tmp/flutter_app_backup/pubspec.yaml frontend/pubspec.yaml || true\n    \n    - name: Update API endpoints (replace localhost)\n      run: |\n        # Replace localhost with your backend IP for testing\n        sed -i 's|http://localhost:8000|http://YOUR_OCI_IP:8000|g' frontend/lib/pages/*.dart || true\n    \n    - name: Get dependencies\n      working-directory: ./frontend\n      run: flutter pub get\n    \n    - name: Build APK\n      working-directory: ./frontend\n      run: flutter build apk --release\n    \n    - name: Upload APK\n      uses: actions/upload-artifact@v4\n      with:\n        name: app-release-apk\n        path: frontend/build/app/outputs/flutter-apk/app-release.apk\n\n  build-web:\n    runs-on: ubuntu-latest\n    steps:\n    - uses: actions/checkout@v4\n    - name: Setup Flutter\n      uses: subosito/flutter-action@v2\n      with:\n        flutter-version: '3.29.0'\n        channel: 'stable'\n    \n    - name: Backup custom code\n      run: |\n        mkdir -p /tmp/flutter_app_backup/lib/pages\n        cp -r frontend/lib/* /tmp/flutter_app_backup/lib/ || true\n        cp frontend/pubspec.yaml /tmp/flutter_app_backup/ || true\n    \n    - name: Remove old frontend and create new Flutter project\n      run: |\n        rm -rf frontend\n        flutter create --org com.example --project-name my_app frontend\n    \n    - name: Restore custom code\n      run: |\n        cp -r /tmp/flutter_app_backup/lib/* frontend/lib/ || true\n        cp /tmp/flutter_app_backup/pubspec.yaml frontend/pubspec.yaml || true\n    \n    - name: Update API endpoints\n      run: |\n        sed -i 's|http://localhost:8000|http://YOUR_OCI_IP:8000|g' frontend/lib/pages/*.dart || true\n    \n    - name: Get dependencies\n      working-directory: ./frontend\n      run: flutter pub get\n    \n    - name: Build Web\n      working-directory: ./frontend\n      run: flutter build web --release\n    \n    - name: Upload Web Build\n      uses: actions/upload-artifact@v4\n      with:\n        name: web-release\n        path: frontend/build/web/\n```

### Usage

1. Commit the workflow file to your repo
2. Go to **Actions** tab in GitHub
3. Select workflow → "Run workflow"
4. Download artifacts (APK or Web build) after ~5-10 minutes

## Alternative: Local x86_64 Machine

If you have a local x86_64 machine (Windows/Mac/Linux), build there:

```bash
git clone <your-repo>
cd frontend
flutter pub get
flutter build apk  # or flutter build web
```

## Pitfalls

- **Don't waste time on box64/emulation**: Flutter toolchain is complex; emulation often fails
- **Dart SDK inside Flutter is x86_64 only**: Even if you get the shell scripts running, the Dart binary will fail
- **GitHub Actions free tier**: 2000 minutes/month for private repos, unlimited for public
- **sed command may not work reliably in CI**: The `sed -i` command to replace API endpoints (e.g., `localhost` → backend IP) can silently fail or not execute. **Better approach**: Modify the source code directly *before* committing, commit both the workflow and updated source code together. Verify the artifact contains the correct API endpoint.
- **Always verify the artifact**: After workflow runs, download the artifact and check that:
  1. It's not the default Flutter counter app (backup/restore worked)
  2. API endpoints point to your actual backend IP, not `localhost`
- **Counter app problem**: If the artifact shows Flutter's default counter app instead of your custom app, the backup/restore steps in the workflow failed. Check that you're backing up from the correct directory (e.g., `frontend/lib/`, not `frontend_backup/`).
- **Backup directory confusion**: When using the backup-restore pattern, ensure you backup from the *actual source directory* (e.g., `frontend/lib/`), not a backup directory. In one session, the workflow incorrectly referenced `frontend_backup/` which didn't exist in the CI environment, causing the restore to fail silently and resulting in the default counter app.
- **Web compatibility issues**: When building for Web, remember:
  - `dart:io` is **not available** on Web platform
  - `MultipartFile.fromPath()` requires `dart:io` → use `MultipartFile.fromBytes()` instead
  - `File` class from `dart:io` → use `XFile` from `package:image_picker`
  - Display selected image on Web: use `Image.network(image.path)` (XFile.path is a blob URL on Web)
  - See "Flutter Web Compatibility" section below

## Flutter Web Compatibility

When building Flutter apps for Web, you'll encounter platform-specific issues. Here's how to handle them:

### File Upload (Critical for Web)

**Problem**: `package:http` MultipartFile.fromPath() requires `dart:io` which is unavailable on Web.

**Solution**: Use `MultipartFile.fromBytes()` with XFile

```dart
// ❌ This fails on Web
import 'dart:io';
File? _selectedImage;
request.files.add(
  await http.MultipartFile.fromPath('file', _selectedImage!.path),
);

// ✅ This works on Web and mobile
import 'package:image_picker/image_picker.dart';  // No dart:io needed
XFile? _selectedImage;  // Use XFile instead of File
final bytes = await _selectedImage!.readAsBytes();
request.files.add(
  http.MultipartFile.fromBytes('file', bytes, filename: _selectedImage!.name),
);
```

### Displaying Selected Images

```dart
// ❌ Web doesn't support FileImage or File
Image.file(File(image.path))

// ✅ Works on Web (XFile.path is a blob: URL on Web)
Image.network(image.path)
```

### Deprecated API Warnings

You may see: `Intl.v8BreakIterator is deprecated. Please use Intl.Segmenter instead.`
- This is just a warning, not an error
- Doesn't affect functionality
- Will be fixed in future Flutter versions

## Verification

After workflow runs:
- Check Actions tab for green checkmark
- Download APK and test on Android device
- For web build, serve with `python3 -m http.server` in the build/web folder
