What it means
Before Android 12, a component with an intent filter was exported by default, so any other app could start it. Since Android 12, Android's documentation states that an app targeting Android 12 or higher that contains activities, services or broadcast receivers using intent filters must explicitly declare android:exported; otherwise the app can't be installed on a device running Android 12 or higher.
The check reads the manifest of the built file, which is the merged manifest: the components declared by your libraries count too.
Deadline
No store date: this is a platform rule that applies as soon as your targetSdkVersion is 31 or higher. Since Google Play requires a recent target API level, every app on the store is concerned.
How to fix it
1. Set the attribute on your own components
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver
android:name=".BootReceiver"
android:exported="false">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>Use true only when other apps or the system must reach the component (the launcher activity, deep-link activities, a share target). Use false for everything internal.
2. Override components that come from libraries
When the component belongs to a dependency, upgrading the dependency is the clean fix. Otherwise, redeclare it in your manifest with the attribute and let the manifest merger combine both:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<application>
<receiver
android:name="com.example.sdk.SomeReceiver"
android:exported="false"
tools:node="merge" />
</application>
</manifest>3. Read the merged manifest
Android Studio's Merged Manifest tab shows which library contributed each component. The store check lists every offending component by name.
Check before you submit
Upload the APK, AAB or split-APK set (XAPK, APKS, APKM) on the store check page. It runs PLAY-EXPORTED against the dates on this page, then deletes the file: nothing about the app is kept. The same engine runs offline in the Narvy CLI, and exits with code 1 when a blocker is found, so it can gate a CI job.
narvy store-check app-release.aabFAQ
Should the attribute be true or false?
true makes the component reachable by other apps, false keeps it private to your app (and apps with the same user ID). Exporting a component that does not need it widens the attack surface, so default to false.
My targetSdk is below 31. Does this apply?
Not this rule: the store check reports it as not applicable. But Google Play's target API requirement will make you raise the target, and the rule applies as soon as you do.
Does it apply to components without an intent filter?
No. Without an intent filter the default is already false, and the check only looks at activities, services and receivers that declare one.