Dịch vụ trên nền trước thực hiện các hoạt động mà người dùng có thể nhận thấy.
Dịch vụ trên nền trước hiển thị một thanh trạng thái để giúp người dùng biết rằng ứng dụng đang thực hiện một tác vụ ở nền trước và sử dụng tài nguyên hệ thống.
Sau đây là ví dụ về ứng dụng dùng dịch vụ trên nền trước:
- Một ứng dụng trình phát nhạc có chức năng phát nhạc trong dịch vụ trên nền trước. Thông báo có thể hiển thị bài hát hiện tại đang được phát.
- Một ứng dụng thể dục ghi lại quãng đường chạy của một người dùng trong dịch vụ trên nền trước, sau khi nhận được sự cho phép từ người dùng. Thông báo có thể hiển thị khoảng cách mà người dùng đã đi trong buổi tập thể dục hiện tại.
Chỉ dùng dịch vụ trên nền trước khi ứng dụng của bạn cần thực hiện một nhiệm vụ mà người dùng có thể nhận thấy ngay cả khi họ không tương tác trực tiếp ứng dụng. Nếu hành động có tầm quan trọng đủ thấp mà bạn muốn sử dụng thông báo có mức độ ưu tiên tối thiểu, tạo nền nhiệm vụ.
Tài liệu này mô tả quyền cần thiết để sử dụng các dịch vụ trên nền trước, và cách bắt đầu một dịch vụ trên nền trước cũng như xoá dịch vụ đó khỏi nền. Điều này cũng mô tả cách liên kết một số trường hợp sử dụng với các loại dịch vụ trên nền trước, và các hạn chế truy cập có hiệu lực khi bạn bắt đầu một dịch vụ trên nền trước từ một ứng dụng đang chạy trong nền.
Người dùng có thể đóng thông báo theo mặc định
Kể từ Android 13 (API cấp 33), người dùng có thể đóng thông báo được liên kết với dịch vụ trên nền trước theo mặc định. Để làm được điều này, người dùng sẽ vuốt trên thông báo. Thông thường, thông báo không bị loại bỏ trừ phi dịch vụ trên nền trước bị dừng hoặc xoá từ nền trước.
Nếu bạn muốn người dùng không thể đóng thông báo, hãy chuyển
true
vào setOngoing()
khi bạn tạo thông báo bằng Notification.Builder
.
Những dịch vụ hiện thông báo ngay lập tức
Nếu dịch vụ trên nền trước có ít nhất một trong các đặc điểm sau, thì hệ thống sẽ hiển thị thông báo liên quan ngay sau khi dịch vụ bắt đầu, ngay cả trên thiết bị chạy Android 12 trở lên:
- Dịch vụ được liên kết với một thông báo có hành động các nút.
- Dịch vụ này có
foregroundServiceType
trong tổng sốmediaPlayback
,mediaProjection
hoặcphoneCall
. - Dịch vụ này cung cấp một trường hợp sử dụng liên quan đến cuộc gọi điện thoại, chỉ đường hoặc nội dung nghe nhìn phát, như được xác định trong danh mục của thông báo .
- Dịch vụ đã chọn không tham gia thay đổi về hành vi bằng cách chuyển
FOREGROUND_SERVICE_IMMEDIATE
vàosetForegroundServiceBehavior()
khi thiết lập thông báo.
Trên Android 13 (API cấp 33) trở lên, nếu người dùng từ chối quyền gửi thông báo, họ vẫn thấy các thông báo liên quan đến các dịch vụ trên nền trước trong Trình quản lý tác vụ nhưng không thấy chúng trong ngăn thông báo.
Khai báo dịch vụ trên nền trước trong tệp kê khai
Trong tệp kê khai của ứng dụng, hãy khai báo từng dịch vụ trên nền trước của ứng dụng
có <service>
. Đối với mỗi dịch vụ, hãy sử dụng
Thuộc tính android:foregroundServiceType
để khai báo loại công việc mà dịch vụ thực hiện.
Ví dụ: nếu ứng dụng của bạn tạo một dịch vụ trên nền trước có chức năng phát nhạc, bạn có thể khai báo dịch vụ như sau:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" ...>
<application ...>
<service
android:name=".MyMediaPlaybackService"
android:foregroundServiceType="mediaPlayback"
android:exported="false">
</service>
</application>
</manifest>
Nếu dịch vụ của bạn có nhiều loại, hãy phân tách các loại đó bằng ký tự |
toán tử. Ví dụ: một dịch vụ sử dụng camera và micrô
sẽ khai báo lệnh như sau:
android:foregroundServiceType="camera|microphone"
Yêu cầu quyền sử dụng dịch vụ trên nền trước
Ứng dụng nhắm đến Android 9 (API cấp 28) trở lên và sử dụng dịch vụ trên nền trước
cần yêu cầu
FOREGROUND_SERVICE
trong tệp kê khai ứng dụng, như minh hoạ trong đoạn mã sau. Đây là điều bình thường
quyền truy cập, vì vậy, hệ thống
tự động cấp quyền truy cập đó cho ứng dụng yêu cầu.
Ngoài ra, nếu nhắm đến API cấp 34 trở lên, thì ứng dụng phải yêu cầu
loại quyền thích hợp cho loại công việc mà dịch vụ trên nền trước sẽ
đang làm. Mỗi loại dịch vụ trên nền trước
có loại quyền tương ứng. Ví dụ: nếu ứng dụng khởi chạy một
dịch vụ trên nền trước có sử dụng máy ảnh, bạn phải yêu cầu cả hai
FOREGROUND_SERVICE
và FOREGROUND_SERVICE_CAMERA
quyền truy cập. Đây đều là những quyền thông thường nên hệ thống sẽ cấp cho họ
nếu được liệt kê trong tệp kê khai.
<manifest xmlns:android="http://schemas.android.com/apk/res/android" ...>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_CAMERA"/>
<application ...>
...
</application>
</manifest>
Điều kiện tiên quyết đối với dịch vụ trên nền trước
Kể từ Android 14 (API cấp 34), khi bạn chạy một dịch vụ trên nền trước,
hệ thống sẽ kiểm tra những điều kiện tiên quyết cụ thể dựa trên loại dịch vụ. Ví dụ:
nếu bạn cố chạy một dịch vụ trên nền trước thuộc loại location
, hệ thống sẽ kiểm tra
để đảm bảo ứng dụng của bạn đã có ACCESS_COARSE_LOCATION
hoặc
Quyền ACCESS_FINE_LOCATION
. Nếu không, hệ thống sẽ gửi
SecurityException
.
Vì lý do này, bạn phải xác nhận rằng đã đáp ứng các điều kiện tiên quyết bắt buộc trước khi bắt đầu dịch vụ trên nền trước. Dịch vụ trên nền trước tài liệu về loại liệt kê các điều kiện tiên quyết bắt buộc đối với từng loại dịch vụ trên nền trước.
Bắt đầu dịch vụ trên nền trước
Trước khi bạn yêu cầu hệ thống chạy một dịch vụ dưới dạng dịch vụ trên nền trước, hãy bắt đầu chính dịch vụ đó:
Kotlin
val intent = Intent(...) // Build the intent for the service context.startForegroundService(intent)
Java
Context context = getApplicationContext(); Intent intent = new Intent(...); // Build the intent for the service context.startForegroundService(intent);
Trong dịch vụ, thường là trong onStartCommand()
, bạn có thể yêu cầu
mà dịch vụ của bạn chạy ở nền trước. Để thực hiện việc này, hãy gọi
ServiceCompat.startForeground()
(có trong androidx-core 1.12 trở lên). Phương thức này sẽ thực hiện các bước sau:
thông số:
- Dịch vụ
- Số nguyên dương xác định duy nhất thông báo trên thanh trạng thái
- Chính đối tượng
Notification
- Các loại dịch vụ trên nền trước xác định công việc do dịch vụ thực hiện
Những loại này có thể là một tập hợp con của các loại được khai báo trong tệp kê khai,
tuỳ thuộc vào trường hợp sử dụng cụ thể. Sau đó, nếu cần thêm các loại dịch vụ khác,
bạn có thể gọi lại startForeground()
.
Ví dụ: Giả sử một ứng dụng thể dục chạy dịch vụ trình theo dõi hoạt động chạy luôn
cần thông tin location
, nhưng có thể cần hoặc không cần phát nội dung nghe nhìn. Bạn
sẽ cần khai báo cả location
và mediaPlayback
trong tệp kê khai. Nếu một
người dùng bắt đầu chạy và chỉ muốn theo dõi vị trí của họ, ứng dụng của bạn sẽ gọi
startForeground()
rồi chỉ chuyển quyền ACCESS_FINE_LOCATION
. Sau đó:
nếu người dùng muốn bắt đầu phát âm thanh, hãy gọi lại startForeground()
và
truyền tổ hợp bitwise của tất cả kiểu dịch vụ trên nền trước (trong trường hợp này là
ACCESS_FINE_LOCATION|FOREGROUND_SERVICE_MEDIA_PLAYBACK
).
Dưới đây là một ví dụ khởi chạy dịch vụ máy ảnh trên nền trước:
Kotlin
class MyCameraService: Service() { private fun startForeground() { // Before starting the service as foreground check that the app has the // appropriate runtime permissions. In this case, verify that the user has // granted the CAMERA permission. val cameraPermission = PermissionChecker.checkSelfPermission(this, Manifest.permission.CAMERA) if (cameraPermission != PermissionChecker.PERMISSION_GRANTED) { // Without camera permissions the service cannot run in the foreground // Consider informing user or updating your app UI if visible. stopSelf() return } try { val notification = NotificationCompat.Builder(this, "CHANNEL_ID") // Create the notification to display while the service is running .build() ServiceCompat.startForeground( /* service = */ this, /* id = */ 100, // Cannot be 0 /* notification = */ notification, /* foregroundServiceType = */ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA } else { 0 }, ) } catch (e: Exception) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && e is ForegroundServiceStartNotAllowedException) { // App not in a valid state to start foreground service // (e.g. started from bg) } // ... } } }
Java
public class MyCameraService extends Service { private void startForeground() { // Before starting the service as foreground check that the app has the // appropriate runtime permissions. In this case, verify that the user // has granted the CAMERA permission. int cameraPermission = ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA); if (cameraPermission == PackageManager.PERMISSION_DENIED) { // Without camera permissions the service cannot run in the // foreground. Consider informing user or updating your app UI if // visible. stopSelf(); return; } try { Notification notification = new NotificationCompat.Builder(this, "CHANNEL_ID") // Create the notification to display while the service // is running .build(); int type = 0; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { type = ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA; } ServiceCompat.startForeground( /* service = */ this, /* id = */ 100, // Cannot be 0 /* notification = */ notification, /* foregroundServiceType = */ type ); } catch (Exception e) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && e instanceof ForegroundServiceStartNotAllowedException ) { // App not in a valid state to start foreground service // (e.g started from bg) } // ... } } //... }
Xoá một dịch vụ khỏi nền trước
Để xoá dịch vụ khỏi nền trước, hãy gọi
stopForeground()
.
Phương thức này nhận một giá trị boolean cho biết liệu có nên xoá thanh trạng thái hay không
thông báo. Xin lưu ý rằng dịch vụ sẽ tiếp tục chạy.
Nếu bạn dừng dịch vụ trong khi chạy ở nền trước, thì thông báo của dịch vụ đó sẽ bị xoá.
Xử lý việc dừng các ứng dụng chạy dịch vụ trên nền trước theo yêu cầu của người dùng
Kể từ Android 13 (API cấp 33), người dùng có thể hoàn tất quy trình công việc từ ngăn thông báo để dừng một ứng dụng có các dịch vụ đang chạy trên nền trước, bất kể ứng dụng đó phiên bản SDK mục tiêu. Thành phần tương tác này, được gọi là Task Manager (Trình quản lý tác vụ), hiển thị một danh sách các ứng dụng hiện đang chạy một dịch vụ trên nền trước.
Danh sách này được gắn nhãn Ứng dụng đang hoạt động. Bên cạnh mỗi ứng dụng là nút Stop (Dừng). Hình 1 minh hoạ Quy trình làm việc của Trình quản lý tác vụ trên một thiết bị chạy Android 13.
Khi người dùng nhấn vào nút Stop (Dừng) bên cạnh ứng dụng của bạn trong Task Manager, thì các thao tác sau sẽ diễn ra:
- Hệ thống sẽ xoá ứng dụng của bạn khỏi bộ nhớ. Do đó, toàn bộ ứng dụng của bạn sẽ dừng, chứ không chỉ dịch vụ trên nền trước đang chạy.
- Hệ thống sẽ xoá ngăn xếp lui hoạt động của ứng dụng.
- Mọi quá trình phát nội dung nghe nhìn đều sẽ dừng.
- Thông báo liên kết với dịch vụ trên nền trước sẽ bị xoá.
- Ứng dụng của bạn vẫn còn trong nhật ký.
- Các lệnh đã lên lịch sẽ thực thi vào thời gian đã lên lịch.
- Chuông báo sẽ tắt theo khung thời gian hoặc thời gian đã lên lịch.
Để kiểm tra xem ứng dụng của bạn có hoạt động như dự kiến trong và sau khi người dùng ngừng hãy chạy lệnh ADB sau đây trong cửa sổ dòng lệnh:
adb shell cmd activity stop-app PACKAGE_NAME
Miễn trừ
Hệ thống đưa ra nhiều cấp độ miễn trừ cho một số loại ứng dụng, mà các phần sau đây mô tả.
Các trường hợp miễn trừ được áp dụng theo ứng dụng chứ không phải theo quy trình. Nếu hệ thống miễn trừ một quy trình trong một tất cả các quy trình khác trong ứng dụng đó cũng được miễn trừ.
Miễn xuất hiện trong Trình quản lý tác vụ
Những ứng dụng sau có thể chạy một dịch vụ trên nền trước và không xuất hiện trong Trình quản lý tác vụ:
- Ứng dụng cấp hệ thống
- Ứng dụng an toàn; tức là những ứng dụng có
Vai trò
ROLE_EMERGENCY
- Thiết bị trong chế độ minh hoạ
Miễn trừ khỏi việc người dùng có thể dừng hoạt động
Khi những loại ứng dụng sau đây chạy một dịch vụ trên nền trước, những ứng dụng đó sẽ xuất hiện trong Trình quản lý tác vụ, nhưng không có nút Stop (Dừng) bên cạnh tên ứng dụng để người dùng nhấn vào:
- Ứng dụng của chủ sở hữu thiết bị
- Chủ sở hữu trang doanh nghiệp ứng dụng
- Ứng dụng cố định
- Ứng dụng có
Vai trò
ROLE_DIALER
Dùng API được thiết kế riêng cho từng mục đích thay vì dịch vụ trên nền trước
Trong nhiều trường hợp sử dụng, bạn có thể dùng API nền tảng hoặc API Jetpack để thực hiện công việc mà bạn có thể dùng dịch vụ trên nền trước. Nếu có được thiết kế cho một mục đích nhất định, nên hầu như lúc nào bạn cũng nên sử dụng API này thay vì dùng một nền trước . Các API được thiết kế theo mục đích thường cung cấp thêm các trường hợp sử dụng cụ thể những khả năng mà bạn lẽ ra phải tự xây dựng. Ví dụ: Bubbles API xử lý logic giao diện người dùng phức tạp để ứng dụng nhắn tin cần triển khai các tính năng bong bóng trò chuyện.
Tài liệu về danh sách các loại dịch vụ trên nền trước các phương án thay thế phù hợp thay cho dịch vụ trên nền trước.
Các hạn chế khi bắt đầu dịch vụ trên nền trước từ chế độ nền
Ứng dụng nhắm đến Android 12 trở lên không thể khởi động ở chế độ nền trước
trong khi ứng dụng đang chạy ở chế độ nền, ngoại trừ một vài dịch vụ
trường hợp. Nếu một ứng dụng cố khởi động một
dịch vụ trên nền trước trong khi ứng dụng chạy trong nền và nền trước
không đáp ứng được một trong các trường hợp ngoại lệ, hệ thống sẽ gửi ra một
ForegroundServiceStartNotAllowedException
.
Ngoài ra, nếu một ứng dụng muốn khởi chạy một dịch vụ trên nền trước cần các quyền trong khi sử dụng (ví dụ: quyền đối với cảm biến cơ thể, máy ảnh, micrô hoặc vị trí quyền), thì dịch vụ không thể tạo dịch vụ trong khi ứng dụng đang chạy trong nền. ngay cả khi ứng dụng thuộc một trong các trường hợp miễn trừ khỏi chế độ khởi động ở chế độ nền hạn chế. Lý do cho điều này được giải thích trong phần Hạn chế về bắt đầu các dịch vụ trên nền trước cần dùng trong khi sử dụng quyền truy cập.
Miễn khỏi các hạn chế về khởi động ở chế độ nền
Trong những trường hợp sau, ứng dụng của bạn có thể bắt đầu các dịch vụ trên nền trước ngay cả khi ứng dụng của bạn chạy ở chế độ nền:
- Ứng dụng của bạn chuyển đổi từ trạng thái hiển thị cho người dùng, chẳng hạn như hoạt động.
- Ứng dụng của bạn có thể bắt đầu một hoạt động trên nền, ngoại trừ trường hợp nơi ứng dụng có một hoạt động trong ngăn xếp lui của một nhiệm vụ hiện tại.
Ứng dụng của bạn nhận được thông báo có mức độ ưu tiên cao bằng Firebase Cloud Nhắn tin.
Người dùng thực hiện một thao tác trên một thành phần trên giao diện người dùng liên quan đến ứng dụng của bạn. Ví dụ: họ có thể tương tác với một bong bóng trò chuyện thông báo, tiện ích hoặc hoạt động.
Ứng dụng của bạn gọi thông báo chính xác để hoàn tất hành động mà người dùng yêu cầu.
Ứng dụng của bạn là phương thức nhập hiện tại của thiết bị .
Ứng dụng của bạn nhận được một sự kiện liên quan đến khoanh vùng địa lý hoặc hoạt động chuyển đổi nhận dạng.
Sau khi thiết bị khởi động lại và nhận được
ACTION_BOOT_COMPLETED
!ACTION_LOCKED_BOOT_COMPLETED
, hoặcACTION_MY_PACKAGE_REPLACED
thao tác theo ý định trong broadcast receiver.Ứng dụng của bạn nhận được
ACTION_TIMEZONE_CHANGED
!ACTION_TIME_CHANGED
, hoặcACTION_LOCALE_CHANGED
thao tác theo ý định trong broadcast receiver.Ứng dụng của bạn nhận được
ACTION_TRANSACTION_DETECTED
sự kiện từNfcService
.Ứng dụng có vai trò hoặc quyền nhất định trên hệ thống, chẳng hạn như thiết bị chủ sở hữu và hồ sơ chủ sở hữu.
Ứng dụng của bạn sử dụng Trình quản lý thiết bị đồng hành và khai báo
REQUEST_COMPANION_START_FOREGROUND_SERVICES_FROM_BACKGROUND
hoặcREQUEST_COMPANION_RUN_IN_BACKGROUND
quyền. Bất cứ khi nào có thể, hãy sử dụngREQUEST_COMPANION_START_FOREGROUND_SERVICES_FROM_BACKGROUND
.Ứng dụng của bạn có
SYSTEM_ALERT_WINDOW
quyền.Người dùng tắt tính năng tối ưu hoá pin cho ứng dụng của bạn.
Quy định hạn chế về việc khởi động những dịch vụ trên nền trước cần có quyền trong khi sử dụng
Trên Android 14 (API cấp 34) trở lên, bạn cần lưu ý một số tình huống đặc biệt nếu bạn đang bắt đầu một dịch vụ trên nền trước cần quyền trong khi sử dụng.
Nếu ứng dụng của bạn nhắm đến Android 14 trở lên, thì hệ điều hành
kiểm tra khi bạn tạo dịch vụ trên nền trước để đảm bảo ứng dụng có tất cả
quyền thích hợp cho loại dịch vụ đó. Ví dụ: khi bạn tạo một
loại dịch vụ trên nền trước
micrô, chức năng điều hành
xác minh rằng ứng dụng của bạn hiện có
RECORD_AUDIO
quyền. Nếu bạn không có quyền đó, hệ thống sẽ gửi ra một
SecurityException
.
Đối với các quyền khi đang sử dụng, việc này có thể gây ra vấn đề. Nếu ứng dụng của bạn có
khi đang sử dụng, ứng dụng chỉ có quyền đó khi đang ở
nền trước. Tức là nếu ứng dụng của bạn chạy ở chế độ nền và cố gắng tạo
dịch vụ trên nền trước thuộc loại camera, vị trí hoặc micrô, hệ thống sẽ nhận thấy
rằng ứng dụng của bạn hiện không có các quyền cần thiết và ứng dụng sẽ gửi ra
SecurityException
.
Tương tự, nếu ứng dụng chạy ở chế độ nền và tạo ra một
dịch vụ sức khoẻ cần quyền BODY_SENSORS_BACKGROUND
, ứng dụng
hiện không có quyền đó và hệ thống sẽ gửi ra ngoại lệ.
(Điều này không áp dụng nếu đó là một dịch vụ y tế cần các quyền khác nhau,
như ACTIVITY_RECOGNITION
.) Gọi điện
PermissionChecker.checkSelfPermission()
không ngăn chặn được sự cố này. Nếu ứng dụng có quyền đang sử dụng và
phương thức này sẽ gọi checkSelfPermission()
để kiểm tra xem nó có quyền đó hay không.
sẽ trả về PERMISSION_GRANTED
ngay cả khi ứng dụng đang chạy trong nền. Khi
phương thức trả về PERMISSION_GRANTED
, tức là "ứng dụng của bạn có quyền này
khi ứng dụng đang được dùng."
Vì lý do này, nếu dịch vụ trên nền trước của bạn cần có quyền trong khi sử dụng, bạn
phải gọi Context.startForegroundService()
hoặc Context.bindService()
trong khi
ứng dụng của bạn có hoạt động rõ ràng, trừ phi dịch vụ đó thuộc một trong
các trường hợp miễn trừ được xác định.
Miễn khỏi các hạn chế về quyền trong khi sử dụng
Trong một số trường hợp, ngay cả khi dịch vụ trên nền trước được khởi động trong khi ứng dụng chạy ở chế độ nền, ứng dụng vẫn có thể truy cập vào thông tin vị trí máy ảnh và micrô trong khi ứng dụng chạy ở nền trước ("trong khi sử dụng").
Trong cùng các trường hợp này, nếu dịch vụ khai báo
loại dịch vụ trên nền trước là location
và do một ứng dụng bắt đầu
có
ACCESS_BACKGROUND_LOCATION
thì dịch vụ này luôn có thể truy cập vào thông tin vị trí, ngay cả khi
ứng dụng chạy trong nền.
Danh sách sau đây chứa những trường hợp sau:
- Một thành phần hệ thống khởi động dịch vụ.
- Dịch vụ bắt đầu bằng cách tương tác với ứng dụng các tiện ích.
- Dịch vụ bắt đầu bằng cách tương tác với một thông báo.
- Dịch vụ bắt đầu dưới dạng
PendingIntent
được gửi từ ứng dụng khác nhau. - Dịch vụ bắt đầu bởi một ứng dụng là chính sách thiết bị bộ điều khiển chạy ở chế độ chủ sở hữu thiết bị.
- Dịch vụ này bắt đầu bằng một ứng dụng cung cấp
VoiceInteractionService
. - Dịch vụ bắt đầu bằng một ứng dụng có
Quyền đặc quyền của
START_ACTIVITIES_FROM_BACKGROUND
.
Xác định những dịch vụ bị ảnh hưởng trong ứng dụng của bạn
Khi kiểm thử ứng dụng, hãy bắt đầu các dịch vụ trên nền trước. Nếu một dịch vụ đã bắt đầu giới hạn quyền truy cập vào vị trí, micrô và máy ảnh, thông báo sau xuất hiện trong Logcat:
Foreground service started from background can not have \ location/camera/microphone access: service SERVICE_NAME