Funktionen und APIs

Android 17 bietet viele neue Funktionen und APIs für Entwickler. In den folgenden Abschnitten werden diese Funktionen zusammengefasst, um Ihnen den Einstieg in die zugehörigen APIs zu erleichtern.

Eine detaillierte Liste der neuen, geänderten und entfernten APIs finden Sie im API-Diff-Bericht. Details zu neuen APIs finden Sie in der Android-API-Referenz. Neue APIs sind zur besseren Übersicht hervorgehoben.

Sie sollten auch Bereiche prüfen, in denen sich Plattformänderungen auf Ihre Apps auswirken könnten. Weitere Informationen finden Sie auf den folgenden Seiten:

Hauptfunktion

Android 17 bietet die folgenden neuen Funktionen im Zusammenhang mit der Android-Kernfunktionalität.

Neue ProfilingManager-Trigger

In Android 17 werden ProfilingManager mehrere neue Systemauslöser hinzugefügt, mit denen Sie detaillierte Daten zur Behebung von Leistungsproblemen erfassen können.

Die neuen Trigger sind:

  • TRIGGER_TYPE_COLD_START: Der Trigger wird beim Kaltstart der App ausgelöst. Die Antwort enthält sowohl ein Beispiel für einen Callstack als auch einen System-Trace.
  • TRIGGER_TYPE_OOM: Der Trigger wird ausgelöst, wenn eine App eine OutOfMemoryError auslöst und als Reaktion darauf einen Java-Heap-Dump bereitstellt.
  • TRIGGER_TYPE_KILL_EXCESSIVE_CPU_USAGE: Der Trigger wird ausgelöst, wenn eine App aufgrund einer ungewöhnlichen und übermäßigen CPU-Nutzung beendet wird. Als Reaktion wird eine Callstack-Stichprobe bereitgestellt.

Informationen zum Einrichten des Systemtriggers finden Sie in der Dokumentation zum triggerbasierten Profiling und zum Abrufen und Analysieren von Profiling-Daten.

JobDebugInfo APIs

Mit Android 17 werden neue JobDebugInfo APIs eingeführt, mit denen Entwickler ihre JobScheduler-Jobs debuggen können. Sie können beispielsweise herausfinden, warum die Jobs nicht ausgeführt werden, wie lange sie ausgeführt wurden und andere aggregierte Informationen abrufen.

Die erste Methode der erweiterten JobDebugInfo-APIs ist getPendingJobReasonStats(). Sie gibt eine Zuordnung der Gründe zurück, warum sich der Job im Status „Ausführung ausstehend“ befand, sowie die entsprechenden kumulativen ausstehenden Ausführungsdauern. Diese Methode kombiniert die getPendingJobReasonsHistory() und getPendingJobReasons() Methoden, um Ihnen Einblicke zu geben, warum ein geplanter Job nicht wie erwartet ausgeführt wird. Sie vereinfacht den Abruf von Informationen, da sowohl die Dauer als auch der Grund für den Job in einer einzigen Methode verfügbar sind.

Für eine bestimmte jobId kann die Methode PENDING_JOB_REASON_CONSTRAINT_CHARGING und eine Dauer von 60000 ms zurückgeben. Das bedeutet, dass der Job 60000 ms lang ausstand, weil die Ladebeschränkung nicht erfüllt war.

Datenschutz

Android 17 enthält die folgenden neuen Funktionen zur Verbesserung des Datenschutzes für Nutzer.

Android-Kontaktauswahl

Die Android-Kontaktauswahl ist eine standardisierte, durchsuchbare Benutzeroberfläche, über die Nutzer Kontakte für Ihre App freigeben können. Sie ist auf Geräten mit Android 17 oder höher verfügbar und bietet eine datenschutzfreundliche Alternative zur umfassenden Berechtigung READ_CONTACTS. Anstatt Zugriff auf das gesamte Adressbuch des Nutzers anzufordern, gibt Ihre App die benötigten Datenfelder an, z. B. Telefonnummern oder E-Mail-Adressen, und der Nutzer wählt bestimmte Kontakte aus, die freigegeben werden sollen. Dadurch erhält Ihre App nur Lesezugriff auf die ausgewählten Daten. So haben Sie eine detaillierte Kontrolle und können gleichzeitig eine einheitliche Nutzererfahrung mit integrierter Suche, Profilwechsel und Mehrfachauswahl bieten, ohne die Benutzeroberfläche entwickeln oder verwalten zu müssen.

Weitere Informationen finden Sie in der Dokumentation zur Kontaktauswahl.

Sicherheit

Android 17 bietet die folgenden neuen Funktionen zur Verbesserung der Geräte- und App-Sicherheit.

Erweiterter Sicherheitsmodus für Android (Android Advanced Protection Mode, AAPM)

Der erweiterte Sicherheitsmodus für Android bietet Android-Nutzern eine Reihe leistungsstarker neuer Sicherheitsfunktionen. Er ist ein wichtiger Schritt, um Nutzer – insbesondere solche mit einem höheren Risiko – vor ausgeklügelten Angriffen zu schützen. AAPM ist als Opt-in-Funktion konzipiert und wird mit einer einzigen Konfigurationseinstellung aktiviert, die Nutzer jederzeit aktivieren können, um eine vordefinierte Reihe von Sicherheitsmaßnahmen anzuwenden.

Zu diesen Kernkonfigurationen gehören das Blockieren der App-Installation aus unbekannten Quellen (Sideloading), das Einschränken der USB-Datensignalisierung und das Erzwingen von Google Play Protect-Scans. Dadurch wird die Angriffsfläche des Geräts erheblich verringert. Entwickler können diese Funktion über die AdvancedProtectionManager API einbinden, um den Status des Modus zu erkennen. So können Anwendungen automatisch eine verstärkte Sicherheitskonfiguration annehmen oder risikoreiche Funktionen einschränken, wenn ein Nutzer sich dafür entschieden hat.

Konnektivität

Mit Android 17 werden die folgenden Funktionen hinzugefügt, um die Geräte- und App-Konnektivität zu verbessern.

Satellitennetzwerke mit eingeschränkter Bandbreite

Implementiert Optimierungen, damit Apps auch in Satellitennetzwerken mit geringer Bandbreite effektiv funktionieren.

Nutzererfahrung und System-UI

Android 17 enthält die folgenden Änderungen zur Verbesserung der Nutzerfreundlichkeit.

Übergabe

Handoff ist eine neue Funktion und API, die in Android 17 eingeführt wird. App-Entwickler können sie integrieren, um ihren Nutzern eine geräteübergreifende Kontinuität zu bieten. Damit kann der Nutzer eine App-Aktivität auf einem Android-Gerät starten und auf ein anderes Android-Gerät übertragen. Handoff wird im Hintergrund auf dem Gerät eines Nutzers ausgeführt und zeigt verfügbare Aktivitäten von den anderen Geräten des Nutzers in der Nähe über verschiedene Einstiegspunkte an, z. B. über den Launcher und die Taskleiste auf dem empfangenden Gerät.

Apps können Handoff so festlegen, dass dieselbe native Android-App gestartet wird, wenn sie auf dem empfangenden Gerät installiert und verfügbar ist. In diesem App-zu-App-Ablauf wird der Nutzer per Deeplink zur entsprechenden Aktivität weitergeleitet. Alternativ kann die Übergabe von Apps an das Web als Fallback-Option angeboten oder direkt mit der URL-Übergabe implementiert werden.

Die Unterstützung für den Wechsel zwischen Geräten wird pro Aktivität implementiert. Rufen Sie zum Aktivieren von Handoff die Methode setHandoffEnabled() für die Aktivität auf. Möglicherweise müssen zusätzliche Daten zusammen mit der Übergabe übergeben werden, damit der entsprechende Status der neu erstellten Aktivität auf dem empfangenden Gerät wiederhergestellt werden kann. Implementieren Sie den onHandoffActivityRequested()-Callback, um ein HandoffActivityData-Objekt zurückzugeben, das Details dazu enthält, wie Handoff die Aktivität auf dem empfangenden Gerät verarbeiten und neu erstellen soll.

Live-Update – Semantische Farb-API

Mit Android 17 werden mit dem Live-Update die Semantic Coloring APIs eingeführt, um Farben mit universeller Bedeutung zu unterstützen.

Die folgenden Klassen unterstützen die semantische Farbgebung:

Farbgebung

  • Grün: Steht für Sicherheit. Diese Farbe sollte verwendet werden, um Nutzern mitzuteilen, dass sie sich in einer sicheren Situation befinden.
  • Orange: Steht für Vorsicht und kennzeichnet physische Gefahren. Diese Farbe sollte verwendet werden in der Situation, in der Nutzer aufmerksam sein müssen, um bessere Schutzeinstellungen festzulegen.
  • Rot: Steht im Allgemeinen für Gefahr oder „Stopp“. Diese Farbe sollte verwendet werden, wenn die Aufmerksamkeit der Nutzer dringend benötigt wird.
  • Blau: Neutrale Farbe für informative Inhalte, die sich von anderen Inhalten abheben sollen.

Im folgenden Beispiel wird gezeigt, wie semantische Stile auf Text in einer Benachrichtigung angewendet werden:

  val ssb = SpannableStringBuilder()
        .append("Colors: ")
        .append("NONE", Notification.createSemanticStyleAnnotation(SEMANTIC_STYLE_UNSPECIFIED), 0)
        .append(", ")
        .append("INFO", Notification.createSemanticStyleAnnotation(SEMANTIC_STYLE_INFO), 0)
        .append(", ")
        .append("SAFE", Notification.createSemanticStyleAnnotation(SEMANTIC_STYLE_SAFE), 0)
        .append(", ")
        .append("CAUTION", Notification.createSemanticStyleAnnotation(SEMANTIC_STYLE_CAUTION), 0)
        .append(", ")
        .append("DANGER", Notification.createSemanticStyleAnnotation(SEMANTIC_STYLE_DANGER), 0)

    Notification.Builder(context, channelId)
          .setSmallIcon(R.drawable.ic_icon)
          .setContentTitle("Hello World!")
          .setContentText(ssb)
          .setOngoing(true)
              .setRequestPromotedOngoing(true)

UWB Downlink-TDoA API für Android 17

Mit der DL-TDoA-Entfernungsmessung (Downlink Time Difference of Arrival) kann ein Gerät seine Position relativ zu mehreren Ankern ermitteln, indem es die relativen Ankunftszeiten von Signalen misst.

Das folgende Snippet zeigt, wie der Ranging Manager initialisiert, die Gerätefunktionen überprüft und eine DL-TDoA-Sitzung gestartet wird:

Kotlin

class RangingApp {

    fun initDlTdoa(context: Context) {
        // Initialize the Ranging Manager
        val rangingManager = context.getSystemService(RangingManager::class.java)

        // Register for device capabilities
        val capabilitiesCallback = object : RangingManager.CapabilitiesCallback {
            override fun onRangingCapabilities(capabilities: RangingCapabilities) {
                // Make sure Dl-TDoA is supported before starting the session
                if (capabilities.uwbCapabilities != null && capabilities.uwbCapabilities!!.isDlTdoaSupported) {
                    startDlTDoASession(context)
                }
            }
        }
        rangingManager.registerCapabilitiesCallback(Executors.newSingleThreadExecutor(), capabilitiesCallback)
    }

    fun startDlTDoASession(context: Context) {

        // Initialize the Ranging Manager
        val rangingManager = context.getSystemService(RangingManager::class.java)

        // Create session and configure parameters
        val executor = Executors.newSingleThreadExecutor()
        val rangingSession = rangingManager.createRangingSession(executor, RangingSessionCallback())
        val rangingRoundIndexes = intArrayOf(0)
        val config: ByteArray = byteArrayOf() // OOB config data
        val params = DlTdoaRangingParams.createFromFiraConfigPacket(config, rangingRoundIndexes)

        val rangingDevice = RangingDevice.Builder().build()
        val rawTagDevice = RawRangingDevice.Builder()
            .setRangingDevice(rangingDevice)
            .setDlTdoaRangingParams(params)
            .build()

        val dtTagConfig = RawDtTagRangingConfig.Builder(rawTagDevice).build()

        val preference = RangingPreference.Builder(DEVICE_ROLE_DT_TAG, dtTagConfig)
            .setSessionConfig(SessionConfig.Builder().build())
            .build()

        // Start the ranging session
        rangingSession.start(preference)
    }
}

private class RangingSessionCallback : RangingSession.Callback {
    override fun onDlTdoaResults(peer: RangingDevice, measurement: DlTdoaMeasurement) {
        // Process measurement results here
    }
}

Java

public class RangingApp {

    public void initDlTdoa(Context context) {

        // Initialize the Ranging Manager
        RangingManager rangingManager = context.getSystemService(RangingManager.class);

        // Register for device capabilities
        RangingManager.CapabilitiesCallback capabilitiesCallback = new RangingManager.CapabilitiesCallback() {
            @Override
            public void onRangingCapabilities(RangingCapabilities capabilities) {
                // Make sure Dl-TDoA is supported before starting the session
                if (capabilities.getUwbCapabilities() != null && capabilities.getUwbCapabilities().isDlTdoaSupported) {
                    startDlTDoASession(context);
                }
            }
        };
        rangingManager.registerCapabilitiesCallback(Executors.newSingleThreadExecutor(), capabilitiesCallback);
    }

    public void startDlTDoASession(Context context) {
        RangingManager rangingManager = context.getSystemService(RangingManager.class);

        // Create session and configure parameters
        Executor executor = Executors.newSingleThreadExecutor();
        RangingSession rangingSession = rangingManager.createRangingSession(executor, new RangingSessionCallback());
        int[] rangingRoundIndexes = new int[] {0};
        byte[] config = new byte[0]; // OOB config data
        DlTdoaRangingParams params = DlTdoaRangingParams.createFromFiraConfigPacket(config, rangingRoundIndexes);

        RangingDevice rangingDevice = new RangingDevice.Builder().build();
        RawRangingDevice rawTagDevice = new RawRangingDevice.Builder()
                .setRangingDevice(rangingDevice)
                .setDlTdoaRangingParams(params)
                .build();

        RawDtTagRangingConfig dtTagConfig = new RawDtTagRangingConfig.Builder(rawTagDevice).build();

        RangingPreference preference = new RangingPreference.Builder(DEVICE_ROLE_DT_TAG, dtTagConfig)
                .setSessionConfig(new SessionConfig.Builder().build())
                .build();

        // Start the ranging session
        rangingSession.start(preference);
    }

    private static class RangingSessionCallback implements RangingSession.Callback {

        @Override
        public void onDlTdoaResults(RangingDevice peer, DlTdoaMeasurement measurement) {
            // Process measurement results here
        }
    }
}

Out-of-Band-Konfigurationen (OOB)

Das folgende Snippet enthält ein Beispiel für DL-TDoA-OOB-Konfigurationsdaten für WLAN und BLE:

Java

// Wifi Configuration
byte[] wifiConfig = {
    (byte) 0xDD, (byte) 0x2D, (byte) 0x5A, (byte) 0x18, (byte) 0xFF, // Header
    (byte) 0x5F, (byte) 0x19, // FiRa Sub-Element
    (byte) 0x02, (byte) 0x00, // Profile ID
    (byte) 0x06, (byte) 0x02, (byte) 0x20, (byte) 0x08, // MAC Address
    (byte) 0x14, (byte) 0x01, (byte) 0x0C, // Preamble Index
    (byte) 0x27, (byte) 0x02, (byte) 0x08, (byte) 0x07, // Vendor ID
    (byte) 0x28, (byte) 0x06, (byte) 0xCA, (byte) 0xC8, (byte) 0xA6, (byte) 0xF7, (byte) 0x6F, (byte) 0x08, // Static STS IV
    (byte) 0x08, (byte) 0x02, (byte) 0x60, (byte) 0x09, // Slot Duration
    (byte) 0x1B, (byte) 0x01, (byte) 0x0A, // Slots per RR
    (byte) 0x09, (byte) 0x04, (byte) 0xE8, (byte) 0x03, (byte) 0x00, (byte) 0x00, // Duration
    (byte) 0x9F, (byte) 0x04, (byte) 0x67, (byte) 0x45, (byte) 0x23, (byte) 0x01  // Session ID
};

// BLE Configuration
byte[] bleConfig = {
    (byte) 0x2D, (byte) 0x16, (byte) 0xF4, (byte) 0xFF, // Header
    (byte) 0x5F, (byte) 0x19, // FiRa Sub-Element
    (byte) 0x02, (byte) 0x00, // Profile ID
    (byte) 0x06, (byte) 0x02, (byte) 0x20, (byte) 0x08, // MAC Address
    (byte) 0x14, (byte) 0x01, (byte) 0x0C, // Preamble Index
    (byte) 0x27, (byte) 0x02, (byte) 0x08, (byte) 0x07, // Vendor ID
    (byte) 0x28, (byte) 0x06, (byte) 0xCA, (byte) 0xC8, (byte) 0xA6, (byte) 0xF7, (byte) 0x6F, (byte) 0x08, // Static STS IV
    (byte) 0x08, (byte) 0x02, (byte) 0x60, (byte) 0x09, // Slot Duration
    (byte) 0x1B, (byte) 0x01, (byte) 0x0A, // Slots per RR
    (byte) 0x09, (byte) 0x04, (byte) 0xE8, (byte) 0x03, (byte) 0x00, (byte) 0x00, // Duration
    (byte) 0x9F, (byte) 0x04, (byte) 0x67, (byte) 0x45, (byte) 0x23, (byte) 0x01  // Session ID
};

Wenn Sie keine OOB-Konfiguration verwenden können, weil sie fehlt, oder wenn Sie Standardwerte ändern müssen, die nicht in der OOB-Konfiguration enthalten sind, können Sie Parameter mit DlTdoaRangingParams.Builder erstellen, wie im folgenden Snippet gezeigt. Sie können diese Parameter anstelle von DlTdoaRangingParams.createFromFiraConfigPacket() verwenden:

Kotlin

val dlTdoaParams = DlTdoaRangingParams.Builder(1)
    .setComplexChannel(UwbComplexChannel.Builder()
            .setChannel(9).setPreambleIndex(10).build())
    .setDeviceAddress(deviceAddress)
    .setSessionKeyInfo(byteArrayOf(0x01, 0x02, 0x03, 0x04))
    .setRangingIntervalMillis(240)
    .setSlotDuration(UwbRangingParams.DURATION_2_MS)
    .setSlotsPerRangingRound(20)
    .setRangingRoundIndexes(byteArrayOf(0x01, 0x05))
    .build()

Java

DlTdoaRangingParams dlTdoaParams = new DlTdoaRangingParams.Builder(1)
    .setComplexChannel(new UwbComplexChannel.Builder()
            .setChannel(9).setPreambleIndex(10).build())
    .setDeviceAddress(deviceAddress)
    .setSessionKeyInfo(new byte[]{0x01, 0x02, 0x03, 0x04})
    .setRangingIntervalMillis(240)
    .setSlotDuration(UwbRangingParams.DURATION_2_MS)
    .setSlotsPerRangingRound(20)
    .setRangingRoundIndexes(new byte[]{0x01, 0x05})
    .build();