Usługi działające na pierwszym planie

Usługi działające na pierwszym planie wykonują działania widoczne dla użytkownika.

Usługi działające na pierwszym planie wyświetlają powiadomienie na pasku stanu, aby poinformować użytkowników, że aplikacja wykonuje zadanie na pierwszym planie i zużywa zasoby systemowe.

Oto przykłady aplikacji, które korzystają z usług działających na pierwszym planie:

  • Aplikacja odtwarzacza muzyki, która odtwarza muzykę w usłudze na pierwszym planie. Może ono zawierać informacje o aktualnie odtwarzanym utworze.
  • Aplikacja do fitnessu, która rejestruje uruchamianie użytkownika w usłudze na pierwszym planie po otrzymaniu od niego zgody. W powiadomieniu może być widoczna odległość, jaką pokonał użytkownik podczas bieżącej sesji fitness.

Usługi na pierwszym planie należy używać tylko wtedy, gdy aplikacja musi wykonać zadanie widoczne dla użytkownika, nawet wtedy, gdy nie wchodzi on w bezpośrednią interakcję z aplikacją. Jeśli działanie jest na tyle mało ważne, że chcesz użyć powiadomienia o minimalnym priorytecie, utwórz zadanie w tle.

W tym dokumencie opisano wymagane uprawnienia do korzystania z usług działających na pierwszym planie oraz sposoby uruchamiania takich usług i usuwania ich z tle. Opisuje on także sposób powiązania określonych przypadków użycia z typami usług na pierwszym planie oraz ograniczenia dostępu, które obowiązują po uruchomieniu takiej usługi z aplikacji działającej w tle.

Domyślnie użytkownik może zamknąć powiadomienie

Od Androida 13 (poziom interfejsu API 33) użytkownicy mogą domyślnie zamykać powiadomienie powiązane z usługą na pierwszym planie. Aby to zrobić, użytkownik wykonuje gest przesuwania powiadomienia. Zazwyczaj powiadomienie nie jest zamykane, chyba że usługa na pierwszym planie zostanie zatrzymana lub usunięta.

Jeśli chcesz, aby użytkownik nie mógł zamknąć powiadomienia, przekaż właściwość true do metody setOngoing() podczas tworzenia powiadomienia za pomocą metody Notification.Builder.

Usługi, które wyświetlają powiadomienia natychmiast

Jeśli usługa na pierwszym planie ma co najmniej 1 z tych cech, system wyświetla powiązane powiadomienie natychmiast po jej uruchomieniu, nawet na urządzeniach z Androidem 12 lub nowszym:

Jeśli na Androidzie 13 (poziom interfejsu API 33) lub nowszym użytkownik odmówi przyznania uprawnień do powiadomień, nadal będzie widzieć w Menedżerze zadań powiadomienia związane z usługami na pierwszym planie, ale nie będzie ich widzieć w panelu powiadomień.

Deklarowanie usług działających na pierwszym planie w pliku manifestu

W pliku manifestu aplikacji zadeklaruj każdą usługę na pierwszym planie za pomocą elementu <service>. W przypadku każdej usługi użyj atrybutu android:foregroundServiceType, aby zadeklarować rodzaj jej działania.

Jeśli na przykład aplikacja tworzy usługę na pierwszym planie, która odtwarza muzykę, możesz ją zadeklarować w ten sposób:

<manifest xmlns:android="http://schemas.android.com/apk/res/android" ...>

    <service
        android:name=".MyMediaPlaybackService"
        android:foregroundServiceType="mediaPlayback"
        android:exported="false">
    </service>
</manifest>

Jeśli do Twojej usługi ma zastosowanie wiele typów, rozdziel je za pomocą operatora |. Na przykład usługa, która używa kamery i mikrofonu, zadeklarowałaby to tak:

android:foregroundServiceType="camera|microphone"

Wysyłanie prośby o uprawnienia do korzystania z usługi na pierwszym planie

Aplikacje kierowane na Androida 9 (poziom interfejsu API 28) lub nowszego i korzystające z usług działających na pierwszym planie muszą wysyłać żądania FOREGROUND_SERVICE w manifeście aplikacji, jak widać w tym fragmencie kodu. Jest to normalne uprawnienie, więc system automatycznie przyznaje je aplikacji, która wysłała żądanie.

Dodatkowo, jeśli aplikacja jest kierowana na interfejs API na poziomie 34 lub wyższym, musi prosić o odpowiedni typ uprawnień do pracy wykonywanej przez usługę na pierwszym planie. Każdy typ usługi na pierwszym planie ma odpowiedni typ uprawnień. Jeśli na przykład aplikacja uruchamia usługę na pierwszym planie, która używa aparatu, musisz poprosić zarówno o uprawnienia FOREGROUND_SERVICE, jak i FOREGROUND_SERVICE_CAMERA. Są to wszystkie normalne uprawnienia, więc system przyznaje je automatycznie, jeśli znajdują się one w pliku manifestu.

<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>

Wymagania wstępne usługi na pierwszym planie

Począwszy od Androida 14 (poziom interfejsu API 34), gdy uruchamiasz usługę na pierwszym planie, system sprawdza, czy spełnione są wymagania wstępne na podstawie typu usługi. Jeśli na przykład próbujesz uruchomić usługę działającą na pierwszym planie typu location, system sprawdza, czy aplikacja ma już uprawnienie ACCESS_COARSE_LOCATION lub ACCESS_FINE_LOCATION. Jeśli tak się nie stanie, system zgłosi SecurityException.

Dlatego przed uruchomieniem usługi na pierwszym planie musisz potwierdzić, że spełniasz wymagania wstępne. Dokumentacja typu usługi na pierwszym planie zawiera wymagania wstępne dotyczące poszczególnych typów takich usług.

Uruchamianie usługi na pierwszym planie

Zanim poprosisz system o uruchomienie usługi jako usługi na pierwszym planie, uruchom samą usługę:

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);

W usłudze, zwykle w obrębie onStartCommand(), możesz poprosić o działanie na pierwszym planie. Aby to zrobić, wywołaj metodę ServiceCompat.startForeground() (dostępne w Androidzie 1.12 i nowszych). Ta metoda pobiera te parametry:

W zależności od konkretnego przypadku użycia te typy mogą być podzbiorem typów zadeklarowanych w pliku manifestu. Jeśli następnie zechcesz dodać więcej typów usług, możesz ponownie wywołać startForeground().

Załóżmy np., że aplikacja do fitnessu obsługuje usługę śledzenia biegowego, która zawsze potrzebuje informacji o parametrze location, ale może nie wymagać odtwarzania multimediów. Musisz zadeklarować w pliku manifestu zarówno location, jak i mediaPlayback. Jeśli użytkownik rozpocznie bieg i chce tylko śledzić jego lokalizację, aplikacja powinna wywołać metodę startForeground() i przekazać tylko uprawnienie ACCESS_FINE_LOCATION. Jeśli użytkownik chce rozpocząć odtwarzanie dźwięku, wywołaj ponownie polecenie startForeground() i przekaż bitową kombinację wszystkich typów usług na pierwszym planie (w tym przypadku ACCESS_FINE_LOCATION|FOREGROUND_SERVICE_MEDIA_PLAYBACK).

Oto przykład uruchamiania usługi aparatu na pierwszym planie:

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 =
            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 {
        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)
            }
            // ...
        }
    }

    //...
}

Usuwanie usługi z pierwszego planu

Aby usunąć usługę z pierwszego planu, wywołaj stopForeground(). Ta metoda przyjmuje wartość logiczną, która wskazuje, czy usunąć także powiadomienie na pasku stanu. Pamiętaj, że usługa będzie nadal działać.

Jeśli zatrzymasz usługę działającą na pierwszym planie, jej powiadomienie zostanie usunięte.

Obsługa inicjowanego przez użytkownika zatrzymywania aplikacji działających na pierwszym planie

Na dole szuflady powiadomień znajduje się przycisk wskazujący liczbę aplikacji, które obecnie działają w tle. Gdy go naciśniesz, pojawi się okno z listą nazw różnych aplikacji. Przycisk Zatrzymaj znajduje się po prawej stronie każdej aplikacji
Rysunek 1. Przepływ pracy Menedżera zadań na urządzeniach z Androidem 13 lub nowszym.

Począwszy od Androida 13 (poziom interfejsu API 33) użytkownicy mogą za pomocą panelu powiadomień zatrzymać aplikację z aktywnymi usługami na pierwszym planie bez względu na jej docelową wersję pakietu SDK. Ten harmonogram, nazywany Menedżerem zadań, zawiera listę aplikacji, które obecnie działają jako usługa na pierwszym planie.

Ta lista jest oznaczona jako Aktywne aplikacje. Obok każdej aplikacji znajduje się przycisk Zatrzymaj. Rysunek 1 przedstawia przepływ pracy Menedżera zadań na urządzeniu z Androidem 13.

Gdy użytkownik kliknie przycisk Zatrzymaj obok aplikacji w Menedżerze zadań, zostaną podjęte te działania:

  • System usunie aplikację z pamięci. Dlatego cała aplikacja zatrzymuje się, a nie tylko uruchomiona usługa na pierwszym planie.
  • System usunie stos wsteczny aktywności aplikacji.
  • Odtwarzanie multimediów zostanie zatrzymane.
  • Powiadomienie powiązane z usługą na pierwszym planie zostanie usunięte.
  • Aplikacja pozostanie w historii.
  • Zaplanowane zadania są wykonywane w zaplanowanym czasie.
  • Alarmy uruchamiają się o zaplanowanej godzinie lub w określonym przedziale czasu.

Aby sprawdzić, czy aplikacja zachowuje się zgodnie z oczekiwaniami, zarówno wtedy, gdy użytkownik zatrzymuje aplikację, jak i po jej zatrzymaniu, uruchom w oknie terminala to polecenie ADB:

adb shell cmd activity stop-app PACKAGE_NAME

Zwolnienia

System umożliwia kilka poziomów wykluczeń określonych typów aplikacji. Opisaliśmy je w sekcjach poniżej.

Wykluczenia dotyczą konkretnej aplikacji, a nie procesu. Jeśli system wykluczy jeden proces w aplikacji, pozostałe procesy w aplikacji również będą wykluczone.

Zwolnienia z wyświetlania w menedżerze zadań

Te aplikacje mogą działać w ramach usługi na pierwszym planie i w ogóle nie są wyświetlane w Menedżerze zadań:

Wykluczenia, których nie można zatrzymać przez użytkowników

Jeśli wymienione poniżej typy aplikacji uruchamiają usługę na pierwszym planie, pojawiają się w Menedżerze zadań, ale obok nazwy aplikacji nie ma przycisku Zatrzymaj, który użytkownik może kliknąć:

Używaj wyspecjalizowanych interfejsów API zamiast usług działających na pierwszym planie

W wielu przypadkach istnieją interfejsy API platformy lub Jetpack, które można wykorzystać do pracy, którą można wykorzystać jako usługę na pierwszym planie. Jeśli istnieje odpowiedni interfejs API o odpowiednim działaniu, powinien on być niemal zawsze używany zamiast usługi na pierwszym planie. Interfejsy API opracowane pod kątem określonych celów często zapewniają dodatkowe możliwości specyficzne dla danego przypadku, które w przeciwnym razie należałoby stworzyć samodzielnie. Na przykład Bubbles API obsługuje złożoną logikę UI na potrzeby aplikacji do przesyłania wiadomości, które wymagają zaimplementowania funkcji dymków czatu.

Dokumentacja typów usług na pierwszym planie zawiera listę dobrych alternatyw do stosowania zamiast usług działających na pierwszym planie.

Ograniczenia dotyczące uruchamiania usługi na pierwszym planie z poziomu tła

Aplikacje kierowane na Androida 12 lub nowszego nie mogą uruchamiać usług działających na pierwszym planie, gdy działają w tle. Wyjątkiem są kilka szczególnych przypadków. Jeśli aplikacja próbuje uruchomić usługę na pierwszym planie, gdy działa w tle, a usługa na pierwszym planie nie spełni jednego z wyjątkowych przypadków, system zwróci błąd ForegroundServiceStartNotAllowedException.

Poza tym jeśli aplikacja chce uruchomić usługę na pierwszym planie, która wymaga uprawnień podczas używania (np. dostępu do czujnika na ciele, aparatu, mikrofonu lub lokalizacji), nie może utworzyć tej usługi, gdy aplikacja działa w tle, nawet jeśli podlega jedno z wyjątków z ograniczeń uruchamiania w tle. Wyjaśniamy to w sekcji Ograniczenia dotyczące uruchamiania usług na pierwszym planie, które wymagają uprawnień podczas używania.

Zwolnienia z ograniczeń uruchamiania w tle

W tych sytuacjach aplikacja może uruchamiać usługi na pierwszym planie nawet wtedy, gdy działa w tle:

Ograniczenia dotyczące uruchamiania usług działających na pierwszym planie, które wymagają uprawnień podczas używania

W przypadku Androida 14 (poziom interfejsu API 34) lub nowszego istnieją specjalne sytuacje, w których uruchamiasz usługę na pierwszym planie, która wymaga uprawnień podczas używania.

Jeśli Twoja aplikacja jest kierowana na Androida 14 lub nowszego, system operacyjny sprawdza, czy tworzysz usługę na pierwszym planie, aby mieć pewność, że ma ona wszystkie odpowiednie uprawnienia dla danego typu usługi. Jeśli na przykład utworzysz usługę na pierwszym planie typu microphone, system operacyjny sprawdzi, czy Twoja aplikacja ma obecnie odpowiednie uprawnienie RECORD_AUDIO. Jeśli nie masz tych uprawnień, system wygeneruje SecurityException.

W przypadku uprawnień używanych podczas korzystania z nich może to powodować potencjalne problemy. Jeśli Twoja aplikacja ma uprawnienie użytkowe, ma je tylko gdy znajduje się na pierwszym planie. Oznacza to, że jeśli aplikacja działa w tle i próbuje utworzyć usługę na pierwszym planie typu aparat, lokalizacja lub mikrofon, system wykryje, że aplikacja obecnie nie ma wymaganych uprawnień, i zwraca SecurityException.

Jeśli aplikacja działa w tle i tworzy usługę stanu, która wymaga uprawnienia BODY_SENSORS_BACKGROUND, to aplikacja nie ma obecnie tego uprawnienia i system zgłasza wyjątek. (Nie dotyczy to służby zdrowia, która wymaga innych uprawnień, np. ACTIVITY_RECOGNITION). Wywołanie ContextCompat.checkSelfPermission() nie zapobiega temu problemowi. Jeśli aplikacja ma uprawnienia danego użytkownika, które wywołuje funkcję checkSelfPermission(), aby sprawdzić, czy ma to uprawnienie, metoda zwróci wartość PERMISSION_GRANTED, nawet jeśli aplikacja działa w tle. Jeśli metoda zwraca wartość PERMISSION_GRANTED, oznacza to, że „aplikacja ma to uprawnienie gdy aplikacja jest używana”.

Jeśli więc usługa na pierwszym planie wymaga uprawnień podczas używania, musisz wywołać Context.startForegroundService() lub Context.bindService(), gdy aplikacja ma widoczną aktywność, chyba że należy ona do jednego ze zdefiniowanych wykluczeń.

Zwolnienia z ograniczeń dotyczących uprawnień podczas używania

W niektórych sytuacjach, nawet jeśli usługa na pierwszym planie jest uruchamiana w tle, może mieć dostęp do informacji o lokalizacji, kamerze i mikrofonu, gdy aplikacja działa na pierwszym planie („podczas używania”).

W tych samych sytuacjach, jeśli usługa deklaruje typ usługi na pierwszym planie o wartości location i jest uruchamiana przez aplikację, która ma uprawnienia ACCESS_BACKGROUND_LOCATION, ma ona dostęp do informacji o lokalizacji przez cały czas, nawet gdy aplikacja działa w tle.

Poniższa lista obejmuje następujące sytuacje:

  • Komponent systemu uruchamia usługę.
  • Usługa rozpoczyna działanie od interakcji z widżetami aplikacji.
  • Usługa rozpoczyna działanie od interakcji z powiadomieniem.
  • Usługa zaczyna się jako PendingIntent wysyłana z innej, widocznej aplikacji.
  • Usługa jest uruchamiana przez aplikację będącą kontrolerem zasad dotyczących urządzeń, która działa w trybie właściciela urządzenia.
  • Usługa uruchamia się przez aplikację, która udostępnia VoiceInteractionService.
  • Usługa uruchamia się przez aplikację, która ma uprawnienie START_ACTIVITIES_FROM_BACKGROUND.
Sprawdzanie w aplikacji, których usług dotyczy ta zmiana

Podczas testowania aplikacji uruchom jej usługi na pierwszym planie. Jeśli uruchomiona usługa ograniczyła dostęp do lokalizacji, mikrofonu i aparatu, w Logcat pojawi się następujący komunikat:

Foreground service started from background can not have \
location/camera/microphone access: service SERVICE_NAME