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 Bericht zu API-Unterschieden. 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:

Hauptfunktion

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

Neue ProfilingManager-Trigger

Android 17 向 ProfilingManager 添加了多个新的系统触发器,以 帮助您收集深入数据来调试性能问题。

新触发器包括:

如需了解如何设置系统触发器,请参阅有关 基于触发器的性能分析的文档以及有关如何检索和分析性能分析数据 的文档

应用异常的性能分析触发器

Android 17 引入了一项设备端异常检测服务,用于监控资源密集型行为和潜在的兼容性回归。此服务与ProfilingManager集成,可让您的应用接收由特定系统检测到的事件触发的性能分析工件。

使用 TRIGGER_TYPE_ANOMALY 触发器检测系统性能问题 例如 binder 调用过多和内存用量过高。当应用违反操作系统定义的内存限制时,异常触发器允许开发者接收特定于应用的堆转储,以帮助识别和修复内存问题。此外,对于 binder 垃圾内容过多,异常触发器会提供有关 binder 事务的堆栈抽样分析报告。

此 API 回调发生在系统强制执行任何操作之前。例如,它可以帮助开发者在应用因超出内存限制而被系统终止之前收集调试数据。

val profilingManager =
    applicationContext.getSystemService(ProfilingManager::class.java)
val triggers = ArrayList<ProfilingTrigger>()
triggers.add(ProfilingTrigger.Builder(ProfilingTrigger.TRIGGER_TYPE_ANOMALY))
val mainExecutor: Executor = Executors.newSingleThreadExecutor()
val resultCallback = Consumer<ProfilingResult> { profilingResult ->
    if (profilingResult.errorCode != ProfilingResult.ERROR_NONE) {
        // upload profile result to server for further analysis
        setupProfileUploadWorker(profilingResult.resultFilePath)
    }
    profilingManager.registerForAllProfilingResults(mainExecutor,
                                                    resultCallback)
    profilingManager.addProfilingTriggers(triggers)
}

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 Wartezeiten. 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 beispielsweise 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 Wake Locks mit Listener-Unterstützung für Alarme vom Typ „allow-while-idle“

In Android 17 wird eine neue Variante von AlarmManager.setExactAndAllowWhileIdle eingeführt, die anstelle von PendingIntent ein OnAlarmListener akzeptiert. Dieser neue Callback-basierte Mechanismus eignet sich ideal für Apps, die derzeit auf kontinuierliche Wakelocks angewiesen sind, um regelmäßige Aufgaben auszuführen, z. B. Messaging-Apps, die Socket-Verbindungen 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)

Mit Android 17 wird die Plattformunterstützung für Encrypted Client Hello (ECH) eingeführt, eine erhebliche Verbesserung des Datenschutzes für die Netzwerkkommunikation. ECH ist eine TLS 1.3-Erweiterung, die den Server Name Indication (SNI) während des ersten TLS-Handshakes verschlüsselt. Diese Verschlüsselung trägt zum Schutz der Privatsphäre der Nutzer bei, da es für Netzwerkvermittler schwieriger wird, die spezifische Domain zu identifizieren, mit der eine App eine Verbindung herstellt.

Die Plattform enthält jetzt die erforderlichen APIs für Netzwerkbibliotheken, um ECH zu implementieren. Dazu gehören neue Funktionen in DnsResolver zum Abfragen von HTTPS-DNS-Einträgen mit ECH-Konfigurationen und neue Methoden in den SSLEngines und SSLSockets von Conscrypt, um ECH zu aktivieren, indem diese Konfigurationen beim Herstellen einer Verbindung zu einer Domain übergeben werden. Entwickler können ECH-Einstellungen konfigurieren, z. B. die optionale Aktivierung oder die obligatorische Verwendung, über das neue <domainEncryption> Element in der Konfigurationsdatei für die Netzwerksicherheit, die global oder pro Domain angewendet werden kann.

Es wird erwartet, dass beliebte Netzwerkbibliotheken wie HttpEngine, WebView und OkHttp diese Plattform-APIs in zukünftigen Updates integrieren, wodurch es für Apps einfacher wird, ECH zu übernehmen und den Datenschutz für Nutzer zu verbessern.

Weitere Informationen finden Sie in der Dokumentation zu Encrypted Client Hello.

Android-Kontaktauswahl

Die Android-Kontaktauswahl ist eine standardisierte, durchsuchbare Oberfläche, über die Nutzer Kontakte für Ihre App freigeben können. Sie ist auf Geräten mit Android 17 (API‑Level 37) 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 selbst entwickeln oder verwalten zu müssen.

Weitere Informationen finden Sie in der Dokumentation zur Kontaktauswahl.

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 der potenziellen Bedrohung durch Angriffe zu schützen, bei denen Quantencomputer zum Einsatz kommen. 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 Post-Quanten-Kryptografie-Algorithmus (PQC) (ML-DSA) kombinieren können.

Dieser hybride Ansatz sorgt dafür, dass Ihre App auch in Zukunft vor Quantenangriffen geschützt ist und gleichzeitig die volle Abwärtskompatibilität mit älteren Android-Versionen und Geräten, die auf klassische Signaturprüfung angewiesen sind, erhalten bleibt.

Auswirkungen auf Entwickler

  • Apps mit Play App-Signatur:Wenn Sie die Play App-Signatur verwenden, können Sie warten, bis Google Play Ihnen die Möglichkeit gibt, eine Hybridsignatur mit einem von Google Play generierten PQC-Schlüssel zu aktualisieren. So ist Ihre App geschützt, ohne dass eine manuelle Schlüsselverwaltung erforderlich ist.
  • 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, die einen PQC-Schlüssel mit einem neuen klassischen Schlüssel kombiniert. 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

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

Nutzererfahrung und System-UI

Android 17 enthält die folgenden Änderungen, um die Nutzererfahrung zu verbessern.

Dedizierter Lautstärkestream für Assistant

In Android 17 wird ein dedizierter Assistant-Lautstärkestream für Assistant-Apps eingeführt, der mit USAGE_ASSISTANT wiedergegeben werden kann. Durch diese Änderung wird die Audioausgabe von Assistant vom Standard-Medienstream entkoppelt. Nutzer können die Lautstärke beider Streams unabhängig voneinander regeln. So können Sie beispielsweise die Medienwiedergabe stummschalten, während Assistant-Antworten weiterhin hörbar sind, und umgekehrt.

Assistant-Apps mit Zugriff auf den neuen Audiomodus MODE_ASSISTANT_CONVERSATION 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 außerhalb der aktiven USAGE_ASSISTANT-Wiedergabe oder mit verbundenen Bluetooth-Peripheriegeräten gesteuert werden.

Handoff

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

Apps können Handoff so konfigurieren, 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 App-zu-Web-Handoff als Fallback-Option angeboten oder direkt mit URL-Handoff implementiert werden.

Die Handoff-Unterstützung wird pro Aktivität implementiert. Um Handoff zu aktivieren, rufen Sie die setHandoffEnabled() Methode für die Aktivität auf. Möglicherweise müssen zusätzliche Daten mit der Übergabe weitergegeben werden, damit der entsprechende Status der neu erstellten Aktivität auf dem empfangenden Gerät wiederhergestellt werden kann. Implementieren Sie den onHandoffActivityDataRequested() 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

在 Android 17 中,实时更新启动了语义着色 API,以支持具有通用含义的颜色。

以下类支持语义着色:

填色游戏

  • 绿色:与安全相关。此颜色应在以下情况下使用:让别人知道您处于安全状态。
  • 橙色:用于表示警告和标记物理危险。在用户需要注意以设置更好的保护设置的情况下,应使用此颜色。
  • 红色:通常表示危险、停止。它应在需要人们紧急关注的情况下显示。
  • 蓝色:中性颜色,适用于信息性内容,应与其他内容区分开来。

以下示例展示了如何将语义样式应用于通知中的文本:

  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

下行链路到达时间差 (DL-TDoA) 测距技术可让设备通过测量信号的相对到达时间来确定其相对于多个锚点的位置。

以下代码段演示了如何初始化 Ranging Manager、验证设备功能并启动 DL-TDoA 会话:

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.RangingCapabilitiesCallback {
            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 = byteArrayOf(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.RangingCapabilitiesCallback() {
            @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());
        byte[] rangingRoundIndexes = new byte[] {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
        }
    }
}

带外 (OOB) 配置

以下代码段提供了 Wi-Fi 和 BLE 的 DL-TDoA OOB 配置数据示例:

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

如果您无法使用 OOB 配置(因为缺少该配置),或者需要更改不在 OOB 配置中的默认值,则可以使用 DlTdoaRangingParams.Builder 构建参数,如以下代码段所示。您可以使用以下参数代替 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();