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-Vergleichsbericht. Details zu neuen APIs finden Sie in der Android API-Refer1enz. Neue APIs sind zur besseren Sichtbarkeit hervorgehoben.
Sie sollten sich auch die Bereiche ansehen, in denen sich Plattformänderungen auf Ihre Apps auswirken können. Weitere Informationen finden Sie auf den folgenden Seiten:
- Verhaltensänderungen, die sich auf Apps auswirken, wenn sie auf Android 17 ausgerichtet sind
- Verhaltensänderungen, die sich unabhängig von
targetSdkVersionauf alle Apps auswirken
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 eineOutOfMemoryErrorauslö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.
Weniger Aktivierungssperren mit Listener-Unterstützung für Alarme im Leerlaufmodus
Mit Android 17
wird eine neue Variante von AlarmManager.setExactAndAllowWhileIdle eingeführt, die
anstelle von PendingIntent einen OnAlarmListener akzeptiert. Dieser neue callbackbasierte Mechanismus ist ideal für Apps, die derzeit auf kontinuierliche Wakelocks angewiesen sind, um regelmäßig Aufgaben auszuführen, z. B. Messaging-Apps, die Socketverbindungen aufrechterhalten.
Datenschutz
Android 17 enthält die folgenden neuen Funktionen, um den Datenschutz für Nutzer zu verbessern.
Plattformunterstützung für Encrypted Client Hello (ECH)
Android 17 introduces platform support for Encrypted Client Hello (ECH), a significant privacy enhancement for network communications. ECH is a TLS 1.3 extension that encrypts the Server Name Indication (SNI) during the initial TLS handshake. This encryption helps protect user privacy by making it more difficult for network intermediaries to identify the specific domain an app is connecting to.
The platform now includes the necessary APIs for networking libraries to
implement ECH. This includes new capabilities in DnsResolver to query for
HTTPS DNS records containing ECH configurations, and new methods in Conscrypt's
SSLEngines and SSLSockets to enable ECH by passing in these configurations when
connecting to a domain. Developers can configure ECH preferences, such as
enabling it opportunistically or mandating its use, through the new
<domainEncryption> element within the Network Security Configuration file,
applicable globally or on a per-domain basis.
Popular networking libraries such as HttpEngine, WebView, and OkHttp are expected to integrate these platform APIs in future updates, making it easier for apps to adopt ECH and enhance user privacy.
For more information, see the Encrypted Client Hello documentation.
Android-Kontaktauswahl
The Android Contact Picker is a standardized, browsable interface for users to
share contacts with your app. Available on devices running
Android 17 (API level 37) or higher, the picker offers a privacy-preserving
alternative to the broad READ_CONTACTS permission. Instead of requesting
access to the user's entire address book, your app specifies the data fields it
needs, such as phone numbers or email addresses, and the user selects specific
contacts to share. This grants your app read access to only the selected data,
ensuring granular control while providing a consistent user experience with
built-in search, profile switching, and multi-selection capabilities without
having to build or maintain the UI.
For more information, see the contact picker documentation.
Sicherheit
Android 17 bietet die folgenden neuen Funktionen, um die Sicherheit von Geräten und Apps zu verbessern.
Erweiterter Sicherheitsprogramm-Modus 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.
PQC-APK-Signierung
Android unterstützt jetzt ein hybrides APK-Signaturschema, um die Signaturidentität Ihrer App vor potenziellen Angriffen zu schützen, die Quantencomputer nutzen. Mit dieser Funktion wird ein neues APK-Signaturschema eingeführt, mit dem Sie einen klassischen Signaturschlüssel (z. B. RSA oder EC) mit einem neuen Algorithmus für die Post-Quantum-Kryptografie (PQC) (ML-DSA) kombinieren können.
Dieser hybride Ansatz sorgt dafür, dass Ihre App auch in Zukunft vor Quantenangriffen geschützt ist. Gleichzeitig wird die vollständige Abwärtskompatibilität mit älteren Android-Versionen und Geräten beibehalten, die auf der klassischen Signaturprüfung basieren.
Auswirkungen auf Entwickler
- Apps mit der Google Play App-Signatur:Wenn Sie die Google Play App-Signatur verwenden, können Sie warten, bis Google Play Ihnen die Möglichkeit bietet, eine hybride Signatur mit einem von Google Play generierten PQC-Schlüssel zu aktualisieren. So ist Ihre App geschützt, ohne dass Sie die Schlüssel manuell verwalten müssen.
- Apps mit selbst verwalteten Schlüsseln:Entwickler, die ihre eigenen Signaturschlüssel verwalten, können aktualisierte Android-Build-Tools (z. B. apksigner) verwenden, um zu einer hybriden Identität zu wechseln, indem sie einen PQC-Schlüssel mit einem neuen klassischen Schlüssel kombinieren. Sie müssen einen neuen klassischen Schlüssel erstellen. Der alte kann nicht wiederverwendet werden.
Konnektivität
Android 17 bietet die folgenden Funktionen, um die Konnektivität von Geräten und Apps zu verbessern.
Eingeschränkte Satellitennetzwerke
Implements optimizations to enable apps to function effectively over low-bandwidth satellite networks.
Nutzererfahrung und System-UI
Android 17 enthält die folgenden Änderungen, um die Nutzererfahrung zu verbessern.
Dedizierter Lautstärkestream für Assistant
Mit Android 17 wird ein eigener Lautstärkestream für Assistant-Apps eingeführt,
der für die Wiedergabe mit USAGE_ASSISTANT verwendet wird. Durch diese Änderung wird die Audioausgabe des Assistant vom Standard-Mediastream entkoppelt, sodass Nutzer die Lautstärke beider Streams unabhängig voneinander steuern können. So können sie beispielsweise die Medienwiedergabe stummschalten, während die Antworten des Assistant weiterhin hörbar sind, und umgekehrt.
Assistant-Apps mit Zugriff auf den neuen MODE_ASSISTANT_CONVERSATION Audio
modus können die Konsistenz der Lautstärkeregelung weiter verbessern. Assistant-Apps können diesen Modus verwenden, um dem System einen Hinweis auf eine aktive Assistant-Sitzung zu geben. So kann der Assistant-Stream auch außerhalb der aktiven USAGE_ASSISTANT-Wiedergabe oder mit verbundenen Bluetooth-Peripheriegeräten gesteuert werden.
Handoff
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:
NotificationNotification.MetricNotification.ProgressStyle.PointNotification.ProgressStyle.Segment
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
Downlink Time Difference of Arrival (DL-TDoA) ranging lets a device determine its position relative to multiple anchors by measuring the relative arrival times of signals.
The following snippet demonstrates how to initialize the Ranging Manager, verify device capabilities, and start a DL-TDoA session:
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 (OOB) Configurations
The following snippet provides an example of DL-TDoA OOB configuration data for Wi-Fi and 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
};
If you can't use an OOB configuration because it is missing, or if you need to
change default values that aren't in the OOB config, you can build parameters
with DlTdoaRangingParams.Builder as shown in the following snippet. You can use
these parameters in place of DlTdoaRangingParams.createFromFiraConfigPacket():
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();