Bỏ qua để đến nội dung

AndroidManifest.xml

AndroidManifest.xml là file cấu hình bắt buộc cho mọi ứng dụng Android. File này cung cấp thông tin thiết yếu về ứng dụng cho hệ thống Android, bao gồm:

  • Package name: Định danh duy nhất của ứng dụng
  • Components: Các Activity, Service, BroadcastReceiver, ContentProvider
  • Permissions: Quyền truy cập tài nguyên hệ thống
  • Hardware/Software features: Yêu cầu phần cứng/phần mềm
  • API levels: Phiên bản Android được hỗ trợ

Vị trí file: app/src/main/AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<!-- Permissions - Quyền truy cập -->
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.MyApp"
tools:targetApi="31">
<activity android:name=".MainActivity" ... />
</application>
</manifest>
Namespace Mục đích
xmlns:android Chứa các thuộc tính Android chuẩn
xmlns:tools Chứa các thuộc tính chỉ dùng cho build time, không đi vào APK

Loại Mô tả Ví dụ
Normal Cấp tự động, không cần hỏi user INTERNET, VIBRATE
Dangerous Phải xin quyền runtime từ Android 6.0+ CAMERA, LOCATION
Signature Chỉ cấp cho apps có cùng signature BIND_DEVICE_ADMIN
<uses-permission android:name="android.permission.INTERNET" />

Khi nào cần?

  • Gọi API REST/GraphQL
  • Tải ảnh từ internet (Glide, Coil, Picasso)
  • WebView load URL
  • Firebase, Analytics, Ads
  • Real-time messaging (WebSocket)

Ví dụ thực tế: App tin tức cần load danh sách bài viết từ server.


<uses-permission android:name="android.permission.CAMERA" />

Khi nào cần?

  • Chụp ảnh/quay video trực tiếp trong app
  • Quét QR code/barcode
  • AR (Augmented Reality) features
  • Video call

Ví dụ thực tế: App ngân hàng cần quét mã QR để thanh toán.

⚠️ Lưu ý: Đây là Dangerous permission - cần xin quyền runtime từ Android 6.0+

// Request permission at runtime
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
arrayOf(Manifest.permission.CAMERA), REQUEST_CODE)
}

<!-- Vị trí chính xác (GPS) - độ chính xác cao -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!-- Vị trí xấp xỉ (Network) - tiết kiệm pin -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!-- Foreground location (Android 10+) -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" />
<!-- Background location (Android 10+) - cần giải thích rõ cho user -->
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />

Sự khác biệt:

Permission Độ chính xác Use case
FINE_LOCATION ~1-10m (GPS) Bản đồ điều hướng, giao nhận
COARSE_LOCATION ~100m (Network) Thời tiết, tin tức địa phương
BACKGROUND_LOCATION Cả 2 Fitness tracking, geo-fencing

Ví dụ thực tế:

  • Grab/Gojek: Cần FINE_LOCATION + BACKGROUND_LOCATION để tracking realtime
  • Weather app: Chỉ cần COARSE_LOCATION để lấy thời tiết thành phố

<!-- Đọc file từ bộ nhớ -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="32" />
<!-- Ghi file vào bộ nhớ -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="29" />
<!-- Android 13+ (API 33): Media permissions chi tiết -->
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />

Thay đổi qua các phiên bản Android:

Android Cách tiếp cận Storage
≤ 9 (API 28) READ/WRITE_EXTERNAL_STORAGE
10 (API 29) Scoped Storage + requestLegacyExternalStorage
11-12 (API 30-32) Scoped Storage bắt buộc
13+ (API 33) READ_MEDIA_* permissions

Ví dụ thực tế: App gallery cần đọc ảnh từ thư viện máy.

// Android 13+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
requestPermissions(arrayOf(Manifest.permission.READ_MEDIA_IMAGES))
} else {
requestPermissions(arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE))
}

<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />

Khi nào cần?

  • Push notifications
  • Local notifications (nhắc nhở, alarm)
  • Download progress notifications
  • Music playback controls

Lưu ý: Từ Android 13, notifications cũng cần xin quyền runtime!

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS)
}
}

<!-- Rung điện thoại -->
<uses-permission android:name="android.permission.VIBRATE" />
<!-- Giữ màn hình sáng -->
<uses-permission android:name="android.permission.WAKE_LOCK" />
<!-- Nhận sự kiện boot completed -->
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<!-- Bluetooth -->
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" /> <!-- Android 12+ -->
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" /> <!-- Android 12+ -->
<!-- Đọc contacts -->
<uses-permission android:name="android.permission.READ_CONTACTS" />
<!-- Gọi điện -->
<uses-permission android:name="android.permission.CALL_PHONE" />
<!-- Đọc trạng thái điện thoại -->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<!-- Ghi âm -->
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<!-- Biometric (vân tay, face) -->
<uses-permission android:name="android.permission.USE_BIOMETRIC" />

<application
android:name=".MyApplication"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.MyApp"
android:networkSecurityConfig="@xml/network_security_config"
android:usesCleartextTraffic="false"
android:largeHeap="false">
<!-- Components here -->
</application>
Thuộc tính Mô tả Ví dụ khi cần
android:name Class Application tùy chỉnh Khởi tạo DI (Hilt/Koin), Firebase, Timber
android:allowBackup Cho phép backup data lên Google Drive false cho apps banking/sensitive
android:icon Icon hiển thị trên launcher Mọi app
android:roundIcon Icon tròn cho các launcher hỗ trợ Pixel, Samsung One UI
android:label Tên app hiển thị Mọi app
android:theme Theme mặc định cho app Material Theme
android:supportsRtl Hỗ trợ ngôn ngữ Right-to-Left Arabic, Hebrew
android:networkSecurityConfig Cấu hình bảo mật mạng Debug với localhost
android:usesCleartextTraffic Cho phép HTTP không mã hóa false cho production
android:largeHeap Yêu cầu heap memory lớn hơn Xử lý ảnh/video lớn
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
// Khởi tạo các libraries
if (BuildConfig.DEBUG) {
Timber.plant(Timber.DebugTree())
}
// Firebase
FirebaseApp.initializeApp(this)
// Crash reporting
FirebaseCrashlytics.getInstance().setCrashlyticsCollectionEnabled(!BuildConfig.DEBUG)
}
}

<activity
android:name=".MainActivity"
android:exported="true"
android:label="@string/app_name"
android:theme="@style/Theme.MyApp"
android:launchMode="singleTop"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

Giải thích Intent Filter:

  • action.MAIN: Đây là entry point của app
  • category.LAUNCHER: Hiển thị icon trên launcher/app drawer
Thuộc tính Giá trị Mô tả Khi nào dùng
exported true/false Cho phép components khác khởi động true cho launcher, deep link
launchMode standard Tạo instance mới mỗi lần Default
singleTop Dùng lại nếu đang ở top stack Notification click
singleTask Chỉ 1 instance trong task Main screen
singleInstance Instance riêng biệt Incoming call screen
screenOrientation portrait Chỉ dọc Form nhập liệu
landscape Chỉ ngang Game, video player
fullSensor Theo sensor Gallery viewer
windowSoftInputMode adjustResize Resize layout khi keyboard xuất hiện Chat input
adjustPan Pan lên để hiện input Login form
configChanges orientation|screenSize Không recreate khi config change Video player
<activity
android:name=".DetailActivity"
android:exported="false"
android:parentActivityName=".MainActivity"
android:theme="@style/Theme.MyApp">
<!-- Enable Up navigation automatically -->
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".MainActivity" />
</activity>

Khi nào dùng exported="false"?

  • Activity chỉ được mở từ trong app
  • Không cần deep link hay external access
  • Bảo mật: ngăn apps khác khởi động activity này
<activity
android:name=".ProductActivity"
android:exported="true">
<!-- App Links (HTTPS - verified) -->
<intent-filter android:autoVerify="true">
<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="www.mystore.com"
android:pathPrefix="/product" />
</intent-filter>
<!-- Custom Scheme (không cần verify) -->
<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="myapp"
android:host="product" />
</intent-filter>
</activity>

Các loại Deep Link:

Loại Scheme Verify Ví dụ URL
App Links https Cần verify domain https://mystore.com/product/123
Deep Links http/https Không http://mystore.com/product/123
Custom Scheme Custom Không myapp://product/123

Ví dụ thực tế:

  • E-commerce: https://shopee.vn/product/123 → mở app Shopee
  • Email verification: myapp://verify?token=abc → mở màn hình verify
class ProductActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Handle deep link
handleIntent(intent)
}
override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)
intent?.let { handleIntent(it) }
}
private fun handleIntent(intent: Intent) {
val data: Uri? = intent.data
data?.let {
val productId = it.lastPathSegment // "123" from /product/123
loadProduct(productId)
}
}
}

<service
android:name=".DownloadService"
android:exported="false"
android:enabled="true" />

Khi nào cần?

  • Download/upload files trong background
  • Sync data với server
  • Các tác vụ không cần UI
<service
android:name=".MusicPlayerService"
android:foregroundServiceType="mediaPlayback"
android:exported="false" />
<service
android:name=".LocationTrackingService"
android:foregroundServiceType="location"
android:exported="false" />
<service
android:name=".UploadService"
android:foregroundServiceType="dataSync"
android:exported="false" />

Foreground Service Types (Android 10+):

Type Permission cần thêm Ví dụ
camera FOREGROUND_SERVICE_CAMERA Video recording
connectedDevice FOREGROUND_SERVICE_CONNECTED_DEVICE Bluetooth device
dataSync FOREGROUND_SERVICE_DATA_SYNC Cloud sync
health FOREGROUND_SERVICE_HEALTH Fitness tracking
location FOREGROUND_SERVICE_LOCATION GPS tracking
mediaPlayback FOREGROUND_SERVICE_MEDIA_PLAYBACK Music player
mediaProjection FOREGROUND_SERVICE_MEDIA_PROJECTION Screen recording
microphone FOREGROUND_SERVICE_MICROPHONE Voice recording
phoneCall FOREGROUND_SERVICE_PHONE_CALL VoIP
remoteMessaging FOREGROUND_SERVICE_REMOTE_MESSAGING Push notifications
shortService - Quick tasks < 3 mins
specialUse FOREGROUND_SERVICE_SPECIAL_USE Other cases

Ví dụ thực tế - Music Player:

class MusicPlayerService : Service() {
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
val notification = createNotification()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
startForeground(NOTIFICATION_ID, notification,
ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK)
} else {
startForeground(NOTIFICATION_ID, notification)
}
// Play music...
return START_STICKY
}
}
<service
android:name=".MessengerService"
android:exported="false">
<intent-filter>
<action android:name="com.example.messenger.BIND" />
</intent-filter>
</service>

Khi nào dùng?

  • Cần giao tiếp hai chiều giữa Activity và Service
  • Multiple clients bind to same service
  • AIDL cho inter-process communication

<receiver
android:name=".BootCompletedReceiver"
android:exported="true"
android:enabled="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>

Khi nào dùng Static?

  • Nhận broadcasts khi app không chạy
  • System broadcasts: BOOT_COMPLETED, PACKAGE_ADDED
  • Cần guaranteed delivery
<!-- Khi device boot xong -->
<receiver android:name=".BootReceiver" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<!-- Khi timezone/time thay đổi -->
<receiver android:name=".TimeChangeReceiver" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.TIMEZONE_CHANGED" />
<action android:name="android.intent.action.TIME_SET" />
</intent-filter>
</receiver>
<!-- Khi battery low -->
<receiver android:name=".BatteryReceiver" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BATTERY_LOW" />
<action android:name="android.intent.action.BATTERY_OKAY" />
</intent-filter>
</receiver>
<!-- Khi network thay đổi (deprecated, dùng NetworkCallback) -->
<receiver android:name=".NetworkReceiver" android:exported="true">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>

Lưu ý Android 8.0+: Nhiều implicit broadcasts bị hạn chế. Nên dùng:

  • Dynamic registration (trong code)
  • JobScheduler / WorkManager
class MainActivity : AppCompatActivity() {
private val screenReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
when (intent.action) {
Intent.ACTION_SCREEN_ON -> handleScreenOn()
Intent.ACTION_SCREEN_OFF -> handleScreenOff()
}
}
}
override fun onResume() {
super.onResume()
val filter = IntentFilter().apply {
addAction(Intent.ACTION_SCREEN_ON)
addAction(Intent.ACTION_SCREEN_OFF)
}
registerReceiver(screenReceiver, filter)
}
override fun onPause() {
super.onPause()
unregisterReceiver(screenReceiver)
}
}

<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>

File res/xml/file_paths.xml:

<?xml version="1.0" encoding="utf-8"?>
<paths>
<!-- Internal app storage: /data/data/com.example/files/ -->
<files-path name="internal_files" path="." />
<!-- Internal cache: /data/data/com.example/cache/ -->
<cache-path name="cache" path="." />
<!-- External files: /storage/emulated/0/Android/data/com.example/files/ -->
<external-files-path name="external_files" path="." />
<!-- External cache -->
<external-cache-path name="external_cache" path="." />
<!-- External storage root (deprecated) -->
<external-path name="external" path="." />
<!-- Specific subdirectory -->
<files-path name="images" path="images/" />
</paths>

Ví dụ thực tế - Share image:

fun shareImage(context: Context, imageFile: File) {
val uri = FileProvider.getUriForFile(
context,
"${context.packageName}.fileprovider",
imageFile
)
val shareIntent = Intent(Intent.ACTION_SEND).apply {
type = "image/*"
putExtra(Intent.EXTRA_STREAM, uri)
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
}
context.startActivity(Intent.createChooser(shareIntent, "Share via"))
}
<provider
android:name=".data.NotesProvider"
android:authorities="com.example.app.provider"
android:exported="true"
android:permission="com.example.app.READ_NOTES">
<path-permission
android:pathPrefix="/notes"
android:readPermission="com.example.app.READ_NOTES"
android:writePermission="com.example.app.WRITE_NOTES" />
</provider>

Khi nào cần Custom Provider?

  • Chia sẻ data với apps khác
  • Sync data với system (Contacts, Calendar)
  • Search integration

<!-- Camera bắt buộc - app sẽ không hiện trên devices không có camera -->
<uses-feature
android:name="android.hardware.camera"
android:required="true" />
<!-- Camera tùy chọn - app vẫn hiện nhưng có thể kiểm tra runtime -->
<uses-feature
android:name="android.hardware.camera"
android:required="false" />
<!-- GPS -->
<uses-feature
android:name="android.hardware.location.gps"
android:required="false" />
<!-- Bluetooth -->
<uses-feature
android:name="android.hardware.bluetooth"
android:required="false" />
<!-- NFC -->
<uses-feature
android:name="android.hardware.nfc"
android:required="false" />
<!-- Fingerprint -->
<uses-feature
android:name="android.hardware.fingerprint"
android:required="false" />
<!-- Telephony (cho phone apps) -->
<uses-feature
android:name="android.hardware.telephony"
android:required="false" />
<!-- Microphone -->
<uses-feature
android:name="android.hardware.microphone"
android:required="true" />

Kiểm tra feature runtime:

fun hasCameraFeature(context: Context): Boolean {
return context.packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA)
}
fun hasNfcFeature(context: Context): Boolean {
return context.packageManager.hasSystemFeature(PackageManager.FEATURE_NFC)
}

Ví dụ thực tế:

  • QR Scanner app: camera required = true
  • E-commerce app: camera required = false (có thể dùng để scan QR nhưng không bắt buộc)

<supports-screens
android:smallScreens="true"
android:normalScreens="true"
android:largeScreens="true"
android:xlargeScreens="true"
android:anyDensity="true"
android:resizeable="true" />

Ý nghĩa:

Thuộc tính Screen size Ví dụ device
smallScreens < 3” Smartwatch (hiếm)
normalScreens 3” - 5” Hầu hết phones
largeScreens 5” - 7” Tablets nhỏ
xlargeScreens 7”+ Tablets lớn

Compatible screens (giới hạn devices):

<compatible-screens>
<!-- Chỉ hỗ trợ normal screens với hdpi, xhdpi, xxhdpi -->
<screen android:screenSize="normal" android:screenDensity="hdpi" />
<screen android:screenSize="normal" android:screenDensity="xhdpi" />
<screen android:screenSize="normal" android:screenDensity="xxhdpi" />
</compatible-screens>

<application>
<!-- Google Maps API Key -->
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="${MAPS_API_KEY}" />
<!-- Google Play Services version check -->
<meta-data
android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />
</application>
<application>
<!-- Default notification icon -->
<meta-data
android:name="com.google.firebase.messaging.default_notification_icon"
android:resource="@drawable/ic_notification" />
<!-- Default notification color -->
<meta-data
android:name="com.google.firebase.messaging.default_notification_color"
android:resource="@color/colorAccent" />
<!-- Default notification channel -->
<meta-data
android:name="com.google.firebase.messaging.default_notification_channel_id"
android:value="default_channel" />
</application>
<application>
<meta-data
android:name="com.facebook.sdk.ApplicationId"
android:value="@string/facebook_app_id" />
<meta-data
android:name="com.facebook.sdk.ClientToken"
android:value="@string/facebook_client_token" />
</application>
<application>
<meta-data
android:name="com.google.android.gms.ads.APPLICATION_ID"
android:value="ca-app-pub-xxxxxxxx~xxxxxxxx" />
</application>

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<!-- Base config cho tất cả domains -->
<base-config cleartextTrafficPermitted="false">
<trust-anchors>
<certificates src="system" />
</trust-anchors>
</base-config>
<!-- Cho phép cleartext cho localhost (development) -->
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="true">localhost</domain>
<domain includeSubdomains="true">10.0.2.2</domain>
<domain includeSubdomains="true">192.168.1.0</domain>
</domain-config>
<!-- Debug-only: trust user-installed certificates -->
<debug-overrides>
<trust-anchors>
<certificates src="user" />
<certificates src="system" />
</trust-anchors>
</debug-overrides>
</network-security-config>
<application
android:networkSecurityConfig="@xml/network_security_config">

Khi nào cần?

Scenario Config
Development với localhost cleartextTrafficPermitted="true" cho localhost
Production cleartextTrafficPermitted="false" (chỉ HTTPS)
Certificate pinning Thêm <pin-set>
Charles Proxy debugging debug-overrides với user certificates
<domain-config>
<domain includeSubdomains="true">api.myapp.com</domain>
<pin-set expiration="2025-12-31">
<pin digest="SHA-256">base64EncodedPublicKeyHash1=</pin>
<pin digest="SHA-256">base64EncodedPublicKeyHash2=</pin>
</pin-set>
</domain-config>

Từ Android 11, cần khai báo package visibility:

<queries>
<!-- Specific packages -->
<package android:name="com.facebook.katana" />
<package android:name="com.twitter.android" />
<!-- Apps that handle specific intents -->
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="https" />
</intent>
<!-- Apps that handle sharing -->
<intent>
<action android:name="android.intent.action.SEND" />
<data android:mimeType="image/*" />
</intent>
<!-- Apps that can take photos -->
<intent>
<action android:name="android.media.action.IMAGE_CAPTURE" />
</intent>
</queries>

Khi nào cần?

  • Kiểm tra app khác có được cài không (isPackageInstalled)
  • Mở app khác (startActivity với package name)
  • Share content tới specific apps

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<!-- Permissions -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" />
<!-- Features -->
<uses-feature android:name="android.hardware.camera" android:required="false" />
<uses-feature android:name="android.hardware.location.gps" android:required="false" />
<!-- Package visibility (Android 11+) -->
<queries>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="https" />
</intent>
</queries>
<application
android:name=".MyApplication"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.MyApp"
android:networkSecurityConfig="@xml/network_security_config"
tools:targetApi="34">
<!-- Main Activity -->
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop"
android:theme="@style/Theme.MyApp.Splash">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<!-- Deep Links -->
<intent-filter android:autoVerify="true">
<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="myapp.com" />
</intent-filter>
</activity>
<!-- Other Activities -->
<activity
android:name=".DetailActivity"
android:exported="false"
android:parentActivityName=".MainActivity" />
<!-- Services -->
<service
android:name=".LocationService"
android:foregroundServiceType="location"
android:exported="false" />
<!-- Receivers -->
<receiver
android:name=".BootReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<!-- Providers -->
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
<!-- Meta-data -->
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="${MAPS_API_KEY}" />
<meta-data
android:name="com.google.firebase.messaging.default_notification_icon"
android:resource="@drawable/ic_notification" />
</application>
</manifest>

Element Mục đích Ví dụ thực tế
<uses-permission> Khai báo quyền cần thiết Internet, Camera, Location
<uses-feature> Khai báo yêu cầu hardware Camera required/optional
<application> Cấu hình app toàn cục Icon, theme, Application class
<activity> Màn hình UI Launcher, Deep links
<service> Background processing Music player, Downloads
<receiver> Nhận broadcasts Boot completed, Battery
<provider> Chia sẻ data FileProvider cho sharing
<meta-data> Config bổ sung API keys, Firebase
<queries> Package visibility (API 30+) Check installed apps
  1. Chỉ khai báo permissions thực sự cần - ít permission = ít risk
  2. Dùng android:required="false" cho features tùy chọn
  3. Set exported="false" cho components internal
  4. Sử dụng Network Security Config đúng cách cho production
  5. Khai báo <queries> cho Android 11+ nếu cần package visibility