← Назад к вопросам

Для чего нужен атрибут android:exported у компонентов в AndroidManifest.xml?

2.0 Middle🔥 171 комментариев
#Android компоненты

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

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"
  • Всегда думайте о безопасности и доступе других приложений
Для чего нужен атрибут android:exported у компонентов в AndroidManifest.xml? | PrepBro