Для чего нужен атрибут android:exported у компонентов в AndroidManifest.xml?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
android:exported в AndroidManifest.xml
Определение
android:exported — атрибут, который определяет, могут ли другие приложения взаимодействовать с вашим компонентом (Activity, Service, Broadcast Receiver, Content Provider). Это критический атрибут безопасности, введённый в Android 12 (API 31).
Почему это нужно
В Android 12 Google обязал разработчиков явно указывать, какие компоненты доступны другим приложениям. Это защита от:
- Несанкционированного доступа к компонентам
- Утечек данных через Content Providers
- Несанкционированного запуска Services
Правило простое
<!-- ОТКРЫТО для других приложений -->
<activity android:exported="true" />
<!-- ЗАКРЫТО для других приложений -->
<activity android:exported="false" />
Когда использовать true/false
1. Activity (обычно false)
<!-- НЕПРАВИЛЬНО: забыли android:exported -->
<!-- В Android 12+ это вызовет ошибку при запуске -->
<activity android:name=".MainActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- ПРАВИЛЬНО -->
<activity android:name=".MainActivity"
android:exported="true"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
Правило: если есть <intent-filter>, то обычно нужен exported="true"
2. Service (обычно false)
// НЕПРАВИЛЬНО: другие приложения смогут вызвать
<service android:name=".MyService" />
// ПРАВИЛЬНО: недоступен другим приложениям
<service android:name=".MyService"
android:exported="false" />
// ПРАВИЛЬНО: если нужен доступ (например, для привязки)
<service android:name=".MyService"
android:exported="true">
<intent-filter>
<action android:name="com.example.myaction" />
</intent-filter>
</service>
3. Broadcast Receiver (обычно false)
<!-- НЕПРАВИЛЬНО -->
<receiver android:name=".MyReceiver" />
<!-- ПРАВИЛЬНО: защита от других приложений -->
<receiver android:name=".MyReceiver"
android:exported="false" />
<!-- ПРАВИЛЬНО: если нужно получать системные события -->
<receiver android:name=".MyReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
4. Content Provider (обычно false)
<!-- НЕПРАВИЛЬНО: утечка данных! -->
<provider
android:name=".MyContentProvider"
android:authorities="com.example.provider" />
<!-- ПРАВИЛЬНО: данные защищены -->
<provider
android:name=".MyContentProvider"
android:authorities="com.example.provider"
android:exported="false" />
<!-- ПРАВИЛЬНО: если нужен общий доступ -->
<provider
android:name=".MyContentProvider"
android:authorities="com.example.provider"
android:exported="true"
android:permission="com.example.READ_PROVIDER" />
</provider>
Автоматический расчёт (если забыли)
До Android 12 система сама определяла exported:
- Есть
<intent-filter>→ exported="true" - Нет
<intent-filter>→ exported="false"
С Android 12: нужно указывать явно, иначе ошибка при компиляции!
Реальный пример: Deep Linking
<!-- Приложение с Deep Linking —ДОЛЖНО быть exported=true -->
<activity android:name=".DetailActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="https"
android:host="example.com"
android:path="/detail" />
</intent-filter>
</activity>
Этот компонент открывается через ссылку → ДОЛЖЕН быть exported="true"
Реальный пример: внутренний сервис
<!-- Сервис только для своего приложения —exported=false -->
<service android:name=".BackgroundSyncService"
android:exported="false" />
Другие приложения не смогут вызвать этот сервис.
Пример Activity с проверкой permission
<!-- Экспортируем, но с защитой через permission -->
<activity android:name=".SecureActivity"
android:exported="true"
android:permission="com.example.SECURE_ACCESS">
<intent-filter>
<action android:name="com.example.SECURE_ACTION" />
</intent-filter>
</activity>
Другие приложения могут только если у них есть permission SECURE_ACCESS.
Проверка в коде (тесты)
// Проверяем, что компонент экспортируется
@Test
fun testMainActivityExported() {
val context = ApplicationProvider.getApplicationContext<Context>()
val packageName = context.packageName
val packageInfo = context.packageManager.getPackageInfo(
packageName,
PackageManager.GET_ACTIVITIES
)
// Проверяем наличие MAIN activity
val activityFound = packageInfo.activities?.any {
it.name.contains("MainActivity")
} ?: false
assertTrue(activityFound)
}
Чеклист безопасности
- ✅ Все компоненты имеют android:exported
- ✅ Только необходимые компоненты exported="true"
- ✅ Чувствительные компоненты с android:permission
- ✅ Никогда не открывайте Content Providers без нужды
- ✅ Используйте Signature permission для внутриприложенческого взаимодействия
Типичные ошибки
<!-- ❌ Забыли android:exported -->
<service android:name=".MyService">
<intent-filter>
<action android:name="com.example.ACTION" />
</intent-filter>
</service>
<!-- ✅ Правильно -->
<service android:name=".MyService"
android:exported="true">
<intent-filter>
<action android:name="com.example.ACTION" />
</intent-filter>
</service>
Вывод
android:exported — это обязательный атрибут безопасности в Android 12+. Правило просто:
- Есть
intent-filter→ обычноexported="true" - Нет
intent-filter→ обычноexported="false" - Всегда думайте о безопасности и доступе других приложений