Android 17 introduce nuove fantastiche funzionalità e API per gli sviluppatori. Le sezioni seguenti riepilogano queste funzionalità per aiutarti a iniziare a utilizzare le API correlate.
Per un elenco dettagliato delle API nuove, modificate e rimosse, leggi il report diff API. Per informazioni dettagliate sulle nuove API, visita il Riferimento API Android. Le nuove API sono evidenziate per una maggiore visibilità.
Devi anche esaminare le aree in cui le modifiche alla piattaforma potrebbero influire sulle tue app. Per maggiori informazioni, consulta le seguenti pagine:
- Modifiche al comportamento che interessano le app quando hanno come target Android 17
- Modifiche al comportamento che interessano tutte le app indipendentemente da
targetSdkVersion.
Funzionalità di base
Android 17 aggiunge le seguenti nuove funzionalità relative alle funzionalità principali di Android.
Nuovi trigger ProfilingManager
Android 17 aggiunge diversi nuovi trigger di sistema a ProfilingManager per
aiutarti a raccogliere dati approfonditi per eseguire il debug dei problemi di rendimento.
I nuovi attivatori sono:
TRIGGER_TYPE_COLD_START: il trigger si verifica durante l'avvio a freddo dell'app. Fornisce sia un campione dello stack di chiamate sia una traccia di sistema nella risposta.TRIGGER_TYPE_OOM: il trigger si attiva quando un'app genera un erroreOutOfMemoryErrore fornisce un dump dell'heap Java in risposta.TRIGGER_TYPE_KILL_EXCESSIVE_CPU_USAGE: il trigger si attiva quando un'app viene chiusa a causa di un utilizzo anomalo ed eccessivo della CPU e fornisce un esempio di stack di chiamate in risposta.TRIGGER_TYPE_ANOMALY: rileva anomalie delle prestazioni del sistema, ad esempio chiamate binder eccessive e memoria utilizzata eccessiva.
Per capire come configurare il trigger di sistema, consulta la documentazione sulla profilazione basata su trigger e su come recuperare e analizzare i dati di profilazione.
Trigger di profilazione per le anomalie delle app
Android 17
introduce un servizio di rilevamento delle anomalie on-device che monitora
comportamenti che richiedono molte risorse e potenziali regressioni della compatibilità. Integrato
con ProfilingManager, questo servizio consente alla tua app di ricevere artefatti di profilazione
attivati da eventi specifici rilevati dal sistema.
Utilizza il trigger TRIGGER_TYPE_ANOMALY per rilevare problemi di prestazioni del sistema
come chiamate binder eccessive e memoria utilizzata eccessiva. Quando un'app viola
i limiti di memoria definiti dal sistema operativo, il trigger di anomalie consente agli sviluppatori di ricevere
dump dell'heap specifici dell'app per identificare e risolvere i problemi di memoria. Inoltre,
per lo spam eccessivo del binder, il trigger di anomalia fornisce un profilo di campionamento dello stack
sulle transazioni del binder.
Questo callback API si verifica prima di qualsiasi applicazione imposta dal sistema. Ad esempio, può aiutare gli sviluppatori a raccogliere dati di debug prima che l'app venga terminata dal sistema per superamento dei limiti di memoria.
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)
}
API JobDebugInfo
Android 17 introduce nuove API JobDebugInfo per aiutare gli sviluppatori a eseguire il debug
dei job JobScheduler: perché non vengono eseguiti, per quanto tempo sono stati eseguiti e
altre informazioni aggregate.
Il primo metodo delle API JobDebugInfo estese è
getPendingJobReasonStats(), che restituisce una mappa dei motivi per cui il job era in
uno stato di esecuzione in attesa e le rispettive durate cumulative in attesa. Questo metodo si unisce ai metodi getPendingJobReasonsHistory() e
getPendingJobReasons() per fornirti informazioni sul motivo per cui un job pianificato
non viene eseguito come previsto, ma semplifica il recupero delle informazioni rendendo
disponibili sia la durata che il motivo del job in un unico metodo.
Ad esempio, per un jobId specificato, il metodo potrebbe restituire
PENDING_JOB_REASON_CONSTRAINT_CHARGING e una durata di 60.000 ms, indicando
che il job è rimasto in attesa per 60.000 ms perché il vincolo di ricarica non è stato
soddisfatto.
Ridurre i wakelock con il supporto del listener per le sveglie consentite in modalità Inattiva
Android 17
introduce una nuova variante di AlarmManager.setExactAndAllowWhileIdle che
accetta un OnAlarmListener anziché un PendingIntent. Questo nuovo meccanismo basato su callback è ideale per le app che attualmente si basano su wakelock continui per eseguire attività periodiche, come le app di messaggistica che mantengono le connessioni socket.
Privacy
Android 17 include le seguenti nuove funzionalità per migliorare la privacy degli utenti.
Supporto della piattaforma Encrypted Client Hello (ECH)
Android 17 introduce il supporto della piattaforma per Encrypted Client Hello (ECH), un miglioramento significativo della privacy per le comunicazioni di rete. ECH è un'estensione TLS 1.3 che cripta l'indicazione del nome del server (SNI) durante l'handshake TLS iniziale. Questa crittografia contribuisce a proteggere la privacy degli utenti rendendo più difficile per gli intermediari di rete identificare il dominio specifico a cui si connette un'app.
La piattaforma ora include le API necessarie per le librerie di networking per
implementare ECH. Sono incluse nuove funzionalità in DnsResolver per eseguire query per
record DNS HTTPS contenenti configurazioni ECH e nuovi metodi in SSLEngines e SSLSockets di Conscrypt per attivare ECH passando queste configurazioni quando
ci si connette a un dominio. Gli sviluppatori possono configurare le preferenze ECH, ad esempio
abilitandole in modo opportunistico o rendendone obbligatorio l'utilizzo, tramite il nuovo
elemento <domainEncryption> all'interno del file di configurazione della sicurezza di rete,
applicabile a livello globale o per singolo dominio.
È previsto che le librerie di rete più diffuse, come HttpEngine, WebView e OkHttp, integrino queste API della piattaforma negli aggiornamenti futuri, semplificando l'adozione di ECH da parte delle app e migliorando la privacy degli utenti.
Per saperne di più, consulta la documentazione relativa a Encrypted Client Hello.
Selettore di contatti Android
Il Selettore di contatti Android è un'interfaccia standardizzata e sfogliabile che consente agli utenti di condividere i contatti con la tua app. Disponibile sui dispositivi con Android 17 (livello API 37) o versioni successive, il selettore offre un'alternativa che rispetta la privacy all'ampia autorizzazione READ_CONTACTS. Anziché richiedere
l'accesso all'intera rubrica dell'utente, la tua app specifica i campi di dati di cui
ha bisogno, ad esempio numeri di telefono o indirizzi email, e l'utente seleziona contatti specifici
da condividere. In questo modo, la tua app avrà accesso in lettura solo ai dati selezionati, garantendo un controllo granulare e fornendo un'esperienza utente coerente con
funzionalità di ricerca, cambio profilo e selezione multipla integrate senza
dover creare o gestire la UI.
Per saperne di più, consulta la documentazione del selettore di contatti.
Sicurezza
Android 17 aggiunge le seguenti nuove funzionalità per migliorare la sicurezza di dispositivi e app.
Modalità di protezione avanzata di Android (AAPM)
La modalità di protezione avanzata di Android offre agli utenti Android un nuovo e potente insieme di funzionalità di sicurezza, segnando un passo significativo nella salvaguardia degli utenti, in particolare di quelli a rischio più elevato, da attacchi sofisticati. Progettato come funzionalità di attivazione, AAPM viene attivato con una singola impostazione di configurazione che gli utenti possono attivare in qualsiasi momento per applicare un insieme di protezioni di sicurezza.
Queste configurazioni di base includono il blocco dell'installazione di app da origini sconosciute
(sideloading), la limitazione della segnalazione dei dati USB e l'obbligo di scansione di Google Play Protect, che riduce notevolmente la superficie di attacco del dispositivo.
Gli sviluppatori possono integrarsi con questa funzionalità utilizzando l'API
AdvancedProtectionManager per rilevare lo stato della modalità, consentendo
alle applicazioni di adottare automaticamente una postura di sicurezza rafforzata o limitare
le funzionalità ad alto rischio quando un utente ha attivato la funzionalità.
Firma dell'APK PQC
Android now supports a hybrid APK signature scheme to future-proof your app's signing identity against the potential threat of attacks that make use of quantum computing. This feature introduces a new APK Signature Scheme, which lets you pair a classical signing key (such as RSA or EC) with a new post-quantum cryptography (PQC) algorithm (ML-DSA).
This hybrid approach ensures your app remains secure against future quantum attacks while maintaining full backward compatibility with older Android versions and devices that rely on classical signature verification.
Impact on developers
- Apps using Play App Signing: If you use Play App Signing, you can wait for Google Play to give you the option to upgrade a hybrid signature using a PQC key generated by Google Play, ensuring your app is protected without requiring manual key management.
- Apps using self-managed keys: Developers who manage their own signing keys can utilize updated Android build tools (like apksigner) to rotate to a hybrid identity, combining a PQC key with a new classical key. (You must create a new classical key, you cannot reuse the older one.)
Connettività
Android 17 aggiunge le seguenti funzionalità per migliorare la connettività di dispositivi e app.
Reti satellitari con limitazioni
Implementa ottimizzazioni per consentire alle app di funzionare in modo efficace su reti satellitari a bassa larghezza di banda.
Esperienza utente e UI di sistema
Android 17 include le seguenti modifiche per migliorare l'esperienza utente.
Stream del volume dell'assistente dedicato
Android 17 introduces a dedicated Assistant volume stream for Assistant apps,
for playback with USAGE_ASSISTANT. This change decouples Assistant audio
from the standard media stream, providing users with isolated control over both
volumes. This enables scenarios such as muting media playback while maintaining
audibility for Assistant responses, and the other way around.
Assistant apps with access to the new MODE_ASSISTANT_CONVERSATION audio
mode can further improve the volume control consistency. Assistant apps can use
this mode to provide a hint to the system about an active Assistant session,
ensuring the Assistant stream can be controlled outside of the active
USAGE_ASSISTANT playback or with connected Bluetooth peripherals.
Handoff
Handoff is a new feature and API coming to Android 17 that app developers can integrate with to provide cross-device continuity for their users. It allows the user to start an app activity on one Android device and transition it to another Android device. Handoff runs in the background of a user's device and surfaces available activities from the user's other nearby devices through various entry points, like the launcher and taskbar, on the receiving device.
Apps can designate Handoff to launch the same native Android app, if it is installed and available on the receiving device. In this app-to-app flow, the user is deep-linked to the designated activity. Alternatively, app-to-web Handoff can be offered as a fallback option or directly implemented with URL Handoff.
Handoff support is implemented on a per-activity basis. To enable Handoff, call
the
setHandoffEnabled()
method for the activity. Additional data may need to be passed along with the
handoff so the recreated activity on the receiving device can restore
appropriate state. Implement the
onHandoffActivityDataRequested()
callback to return a
HandoffActivityData object which
contains details that specify how Handoff should handle and recreate the
activity on the receiving device.
Aggiornamento in tempo reale - API dei colori semantici
With Android 17, Live Update launches the Semantic Coloring APIs to support colors with universal meaning.
The following classes support semantic coloring:
NotificationNotification.MetricNotification.ProgressStyle.PointNotification.ProgressStyle.Segment
Coloring
- Green: Associated with safety. This color should be used for the case where it lets people know you are in the safe situation.
- Orange: For designating caution and marking physical hazards. This color should be used in the situation where users need to pay attention to set better protection setting.
- Red: Generally indicates danger, stop. It should be presented for the case where need people's attention urgently.
- Blue: Neutral color for content that is informational and should stand out from other content.
The following example shows how to apply semantic styles to text in a notification:
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)
API UWB Downlink-TDoA per Android 17
La misurazione della distanza tramite la differenza di tempo di arrivo del downlink (DL-TDoA) consente a un dispositivo di determinare la sua posizione rispetto a più punti di ancoraggio misurando i tempi di arrivo relativi dei segnali.
Il seguente snippet mostra come inizializzare Ranging Manager, verificare le funzionalità del dispositivo e avviare una sessione 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
}
}
}
Configurazioni fuori banda (OOB)
Lo snippet seguente fornisce un esempio di dati di configurazione OOB DL-TDoA per Wi-Fi e 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
};
Se non puoi utilizzare una configurazione OOB perché non è presente o se devi modificare i valori predefiniti che non sono presenti nella configurazione OOB, puoi creare parametri con DlTdoaRangingParams.Builder come mostrato nel seguente snippet. Puoi utilizzare
questi parametri al posto di 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();