The migration to Android Gradle Plugin (AGP) 8.0 represents a significant shift in the Android build ecosystem. For Flutter developers upgrading their android/ directory—often to support newer Java versions or meet Play Store requirements—the build process frequently terminates with this error:
> Task :app:processDebugMainManifest FAILED
Execution failed for task ':app:processDebugMainManifest'.
> com.android.builder.errors.EvalIssueException: Namespace not specified.
Please specify a namespace in the module's build.gradle file like so:
android {
namespace 'com.example.myapp'
}
This error is not a suggestion; it is a breaking change enforcement. This post outlines the architectural reason for this shift and details the exact implementation required to resolve it in a Flutter environment.
The Root Cause: Manifest vs. Gradle decoupling
Historically, the package attribute in AndroidManifest.xml served two distinct purposes:
- Application ID: Uniquely identifying the app on the Google Play Store (e.g.,
com.example.app). - Java Package Structure: Telling the build tools which Java package to use for generating the
R.java(resources) andBuildConfig.javaclasses.
As of AGP 8.0, these responsibilities have been strictly decoupled to improve build performance and modularity. Gradle is now the single source of truth for build configuration. Relying on an XML parser to determine the Java package for code generation introduced unnecessary latency and ambiguity during the configuration phase.
Therefore, the package attribute in the Manifest is deprecated for build logic. You must now explicitly define a namespace in your build.gradle file.
The Fix
To resolve this, you must migrate the package definition from the Manifest to the Gradle build script.
Step 1: Update android/app/build.gradle
Open your application-level build file located at android/app/build.gradle. Locate the android block. You need to inject the namespace property.
Usually, this value matches your original package name.
plugins {
id "com.android.application"
id "kotlin-android"
// The Flutter Gradle Plugin must apply after the Android and Kotlin plugins.
id "dev.flutter.flutter-gradle-plugin"
}
android {
// AGP 8.0+ REQUIREMENT:
// Define the namespace explicitly here. This is used for R.java generation.
namespace "com.example.myflutterapp"
compileSdk flutter.compileSdkVersion
ndkVersion flutter.ndkVersion
compileOptions {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = '17'
}
defaultConfig {
// This remains your Play Store ID.
// In many Flutter apps, this matches the namespace, but they are technically distinct.
applicationId "com.example.myflutterapp"
// ... rest of config
minSdkVersion flutter.minSdkVersion
targetSdkVersion flutter.targetSdkVersion
versionCode flutter.versionCode
versionName flutter.versionName
}
buildTypes {
release {
signingConfig signingConfigs.debug
}
}
}
flutter {
source '../..'
}
Step 2: Clean up AndroidManifest.xml
Once the namespace is defined in Gradle, the package attribute in your Manifest becomes redundant for build generation purposes. While AGP may tolerate it temporarily, it is best practice to remove it to avoid ambiguity.
Open android/app/src/main/AndroidManifest.xml:
Before:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myflutterapp">
<application
android:label="my_flutter_app"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
<!-- ... -->
</application>
</manifest>
After:
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- The 'package' attribute is removed.
Gradle handles the namespace now. -->
<application
android:label="my_flutter_app"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
<!-- ... -->
</application>
</manifest>
Step 3: Handle Flutter Plugins (If You Maintain One)
If you are a plugin author or maintain a local module in your android/ directory, the logic is identical, but the file location changes. In a library module, you generally do not have an applicationId, but you must have a namespace.
File: android/local_module/build.gradle (or the plugin's build.gradle)
android {
// Critical for library modules in AGP 8.0+
namespace "com.example.my_local_plugin"
compileSdk flutter.compileSdkVersion
defaultConfig {
minSdkVersion flutter.minSdkVersion
}
// ...
}
Why This Works
By explicitly setting the namespace in the Gradle DSL:
- R.java Generation: The build tool immediately knows where to generate the resource class (
com.example.myflutterapp.R) without waiting to parse XML files. - Decoupled Identity: You are now free to change your
applicationId(public ID) for different build flavors (e.g.,com.example.app.debugvscom.example.app) without breaking the internal Java imports used in your code, which will remain consistent with thenamespace. - Future Proofing: This aligns your Flutter project with the strict compilation boundaries enforced by Gradle 8.0, ensuring compatibility with future optimizations in the Android build chain.
Conclusion
The "Namespace not specified" error is a mandatory migration step for the modern Android stack. By moving the package definition from XML to Gradle, you not only fix the build failure but also optimize your project structure for faster, deterministic builds. Make this change in your app/build.gradle and any local library modules immediately upon upgrading AGP.