Building for Android
1. Understanding Android Project Structure
| Directory | Description | Contents |
|---|---|---|
| android/ | Root directory for Android-specific files | build.gradle, gradle.properties, settings.gradle |
| android/app/ | Flutter app's Android-specific code | AndroidManifest.xml, MainActivity.kt/java |
| android/app/src/main/ | Main Android app source directory | AndroidManifest.xml, MainActivity.kt/java, res/ |
| android/app/src/main/res/ | Resources for the Android app | mipmap-, drawable-, values- folders |
| android/app/src/main/AndroidManifest.xml | App metadata and permissions | Package name, app name, permissions |
Example: AndroidManifest.xml snippet
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:name="io.flutter.app.FlutterApplication"
android:label="my_flutter_app"
android:icon="@mipmap/ic_launcher">
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<meta-data
android:name="io.flutter.app.android.SplashScreenUntilFirstFrame"
android:value="true" />
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
2. Configuring build.gradle Files
| Property | Values | Description |
|---|---|---|
| compileSdkVersion | 34 |
SDK version to compile against |
| targetSdkVersion | 34 |
SDK version to target for runtime behavior |
| minSdkVersion | 21 |
Minimum Android API level supported |
Example: build.gradle (Module: app)
android {
compileSdk 34
defaultConfig {
applicationId "com.example.myapp"
minSdk 21
targetSdk 34
versionCode 1
versionName "1.0"
}
}
Example: build.gradle (Project)
buildscript {
ext.kotlin_version = "1.9.22"
repositories {
google()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:8.1.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
3. Setting Application ID and Version
| Field | Value | Description |
|---|---|---|
| applicationId | com.example.myapp |
Unique identifier for the app on Android |
| versionName | 1.0.0 |
User-facing version string |
| versionCode | 1 |
Internal version number for Play Store |
Example: AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myapp">
<application
android:label="MyApp"
android:icon="@mipmap/ic_launcher">
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop"
android:theme="@style/LaunchTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>
Example: build.gradle (Module: app)
android {
compileSdk 34
defaultConfig {
applicationId "com.example.myapp"
minSdk 21
targetSdk 34
versionCode 1
versionName "1.0.0"
}
}
4. Configuring Minimum SDK Version
| Property | Value | Description |
|---|---|---|
| minSdkVersion | 21 |
Minimum Android SDK version required to run the app |
| targetSdkVersion | 33 |
Target Android SDK version for the app |
Example: Setting minSdkVersion in build.gradle
android {
compileSdk 33
defaultConfig {
applicationId "com.example.myapp"
minSdkVersion 21
targetSdkVersion 33
versionCode 1
versionName "1.0"
}
}
5. Using Build Variants
Build variants in Flutter allow you to customize the app's behavior, configuration, and resources for different environments like development, staging, or production.
| Variant | Description | Configuration File | Usage |
|---|---|---|---|
| debug | Used for development and debugging. Includes debug logs and enables hot reload. | debug |
Default when running flutter run |
| release | Optimized for production. Strips debug information and enables tree-shaking. | release |
Used when building for distribution |
| profile | Used for performance profiling. Includes performance metrics but not debug logs. | profile |
Used when running flutter run --profile |
Example: Setting up build variants in Gradle
android {
defaultConfig {
applicationId "com.example.myapp"
minSdkVersion 21
targetSdkVersion 33
}
buildTypes {
debug {
applicationIdSuffix ".debug"
versionNameSuffix "-debug"
}
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
profile {
initWith debug
applicationIdSuffix ".profile"
}
}
}
Note: Build variants are managed in the
build.gradle file for Android, and can be extended to support custom configurations like staging or QA environments.
6. Building APK
| Option | Values | Description |
|---|---|---|
| --release | true |
Builds a release version of the app |
| --build-number | 1 |
Build number for the APK (must be incremented) |
| --build-name | 1.0.0 |
Version name for the APK |
| --target | lib/main.dart |
Entry point for the app |
Note: Ensure that you have configured signing keys before building a release APK.
Warning: The
--release flag is required for production builds.
7. Building App Bundle
| Option | Values | Description |
|---|---|---|
| flutter build appbundle | flutter build appbundle |
Builds the Android App Bundle for publishing to Google Play |
| --release | --release |
Builds a release version of the app bundle |
| --target-platform | android-arm64, android-arm |
Specifies the target architecture for the app bundle |
| --build-number | 1 |
Sets the build number for the app bundle |
Note: The app bundle is a new format for publishing Android apps that allows Google Play to generate optimized APKs for different devices.
8. Configuring ProGuard/R8
Example: Basic ProGuard Configuration
-keep class com.example.myapp.** { *; }
-keep class io.flutter.** { *; }
| Option | Description | Default |
|---|---|---|
| proguard-rules.pro | Path to ProGuard configuration file | android/app/proguard-rules.pro |
| minifyEnabled | Enables code shrinking and obfuscation | false |
| shrinkResources | Removes unused resources | false |
Note: R8 is the default code shrinker in Android Gradle Plugin 3.4.0+ and replaces ProGuard.
Warning: Incorrect ProGuard rules can break your app at runtime.
Key Considerations
- Keep Flutter framework classes with
-keep class io.flutter.** { *; } - Keep your application classes with
-keep class com.example.myapp.** { *; } - Use
-keepnamesfor debugging purposes - Test thoroughly after enabling minification
9. Using Build Flavors
Build flavors in Flutter allow you to customize your app for different environments or configurations, such as development, staging, and production. They are particularly useful for managing different API endpoints, app names, or branding.
| Flavor | Description | Configuration |
|---|---|---|
| dev | Development environment with debug features and local API endpoints. | Uses dev configuration in pubspec.yaml. |
| staging | Staging environment for testing before production. | Uses staging configuration in pubspec.yaml. |
| prod | Production environment with optimized settings. | Uses prod configuration in pubspec.yaml. |
Example: Defining Build Flavors in pubspec.yaml
flutter:
uses-material-design: true
# Define build flavors
flavor_strings:
dev:
app_name: "MyApp Dev"
api_url: "https://api.dev.example.com"
staging:
app_name: "MyApp Staging"
api_url: "https://api.staging.example.com"
prod:
app_name: "MyApp"
api_url: "https://api.example.com"
Example: Using Flavor Configuration in Code
class AppConfig {
static String get appName => _getFlavorString('app_name');
static String get apiUrl => _getFlavorString('api_url');
static String _getFlavorString(String key) {
// This is a simplified example; actual implementation depends on
// how you load flavor configuration.
return 'default_value';
}
}
Note: Build flavors are managed via the
flavor_strings in pubspec.yaml. You can define different configurations for each flavor and access them in your app code.
10. Configuring App Signing
App signing is required for publishing Flutter apps to the Google Play Store. Flutter uses the Android build system to handle app signing.
| Property | Description | Default Value |
|---|---|---|
| keyAlias | Alias of the signing key in the keystore | flutter |
| keyPassword | Password for the signing key | None |
| storeFile | Path to the keystore file | None |
| storePassword | Password for the keystore | None |
Example: Setting up app signing in gradle.properties
storePassword=your_store_password
keyPassword=your_key_password
keyAlias=your_key_alias
storeFile=../path/to/keystore.jks
Note: The keystore file should be stored securely and never committed to version control.
Warning: If you lose your keystore, you won't be able to update your app on the Play Store.