Özellikler ve API'ler

Android 17, geliştiriciler için harika yeni özellikler ve API'ler sunuyor. Aşağıdaki bölümlerde, ilgili API'leri kullanmaya başlamanıza yardımcı olmak için bu özellikler özetlenmiştir.

Yeni, değiştirilmiş ve kaldırılmış API'lerin ayrıntılı listesi için API farklılıkları raporunu inceleyin. Yeni API'lerle ilgili ayrıntılar için Android API referansını ziyaret edin. Yeni API'ler görünürlük için vurgulanmıştır.

Platform değişikliklerinin uygulamalarınızı etkileyebileceği alanları da incelemeniz gerekir. Daha fazla bilgi için aşağıdaki sayfalara göz atın:

Temel işlevler

Android 17, temel Android işlevleriyle ilgili aşağıdaki yeni özellikleri ekler.

Yeni ProfilingManager tetikleyicileri

Android 17 adds several new system triggers to ProfilingManager to help you collect in-depth data to debug performance issues.

The new triggers are:

To understand how to set up the system trigger, see the documentation on trigger-based profiling and how to retrieve and analyze profiling data documentation.

Profiling trigger for app anomalies

Android 17 introduces an on-device anomaly detection service that monitors for resource-intensive behaviors and potential compatibility regressions. Integrated with ProfilingManager, this service allows your app to receive profiling artifacts triggered by specific system-detected events.

Use the TRIGGER_TYPE_ANOMALY trigger to detect system performance issues such as excessive binder calls and excessive memory usage. When an app breaches OS-defined memory limits, the anomaly trigger allows developers to receive app-specific heap dumps to help identify and fix memory issues. Additionally, for excessive binder spam, the anomaly trigger provides a stack sampling profile on binder transactions.

This API callback occurs prior to any system imposed enforcements. For example, it can help developers collect debug data before the app is terminated by the system for exceeding memory limits.

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 API'leri

Android 17 introduces new JobDebugInfo APIs to help developers debug their JobScheduler jobs--why they aren't running, how long they ran for, and other aggregated information.

The first method of the expanded JobDebugInfo APIs is getPendingJobReasonStats(), which returns a map of reasons why the job was in a pending execution state and their respective cumulative pending durations. This method joins the getPendingJobReasonsHistory() and getPendingJobReasons() methods to give you insight into why a scheduled job is not running as expected, but simplifies information retrieval by making both duration and job reason available in a single method.

For example, for a specified jobId, the method might return PENDING_JOB_REASON_CONSTRAINT_CHARGING and a duration of 60000 ms, indicating the job was pending for 60000ms due to the charging constraint not being satisfied.

Boşta kalma sırasında izin verilen alarmlar için dinleyici desteğiyle uyandırma kilitlerini azaltma

Android 17, PendingIntent yerine OnAlarmListener kabul eden yeni bir AlarmManager.setExactAndAllowWhileIdle varyantını kullanıma sunar. Bu yeni geri çağırmaya dayalı mekanizma, şu anda soket bağlantılarını koruyan mesajlaşma uygulamaları gibi periyodik görevleri gerçekleştirmek için sürekli uyandırma kilitlerine dayanan uygulamalar için idealdir.

Gizlilik

Android 17, kullanıcı gizliliğini iyileştirmek için aşağıdaki yeni özellikleri içerir.

Encrypted Client Hello (ECH) platform desteği

Android 17, ağ iletişimlerinde önemli bir gizlilik iyileştirmesi olan Encrypted Client Hello (ECH) için platform desteği sunuyor. ECH, ilk TLS el sıkışması sırasında Sunucu Adı Göstergesi'ni (SNI) şifreleyen bir TLS 1.3 uzantısıdır. Bu şifreleme, bir uygulamanın bağlandığı alanın ağ aracıları tarafından tanımlanmasını zorlaştırarak kullanıcı gizliliğinin korunmasına yardımcı olur.

Platform artık ağ kitaplıklarının ECH'yi uygulaması için gerekli API'leri içeriyor. Buna, ECH yapılandırmaları içeren HTTPS DNS kayıtlarını sorgulamak için DnsResolver'daki yeni özellikler ve bir alana bağlanırken bu yapılandırmaları ileterek ECH'yi etkinleştirmek için Conscrypt'in SSLEngines ve SSLSockets'indeki yeni yöntemler dahildir. Geliştiriciler, ECH tercihlerini (ör. fırsatçı bir şekilde etkinleştirme veya kullanımını zorunlu kılma) yeni <domainEncryption> öğesi aracılığıyla yapılandırabilir. Bu öğe, Ağ Güvenliği Yapılandırma dosyası içinde yer alır ve global olarak veya alan bazında geçerlidir.

HttpEngine, WebView ve OkHttp gibi popüler ağ kitaplıklarının gelecekteki güncellemelerde bu platform API'lerini entegre etmesi bekleniyor. Bu sayede uygulamaların ECH'yi benimsemesi ve kullanıcı gizliliğini artırması kolaylaşacak.

Daha fazla bilgi için Şifrelenmiş İstemci Merhaba belgesine bakın.

Android kişi seçici

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.

Güvenlik

Android 17, cihaz ve uygulama güvenliğini artırmak için aşağıdaki yeni özellikleri ekler.

Android Gelişmiş Koruma Modu (AAPM)

Android Advanced Protection Mode offers Android users a powerful new set of security features, marking a significant step in safeguarding users—particularly those at higher risk—from sophisticated attacks. Designed as an opt-in feature, AAPM is activated with a single configuration setting that users can turn on at any time to apply an opinionated set of security protections.

These core configurations include blocking app installation from unknown sources (sideloading), restricting USB data signaling, and mandating Google Play Protect scanning, which significantly reduces the device's attack surface area. Developers can integrate with this feature using the AdvancedProtectionManager API to detect the mode's status, enabling applications to automatically adopt a hardened security posture or restrict high-risk functionality when a user has opted in.

PQC APK İmzalama

Android artık uygulamanızın imza kimliğini, kuantum bilgisayarlardan yararlanan saldırıların olası tehdidine karşı korumak için hibrit bir APK imza şemasını destekliyor. Bu özellik, klasik bir imzalama anahtarını (ör. RSA veya EC) yeni bir kuantum sonrası kriptografi (PQC) algoritmasıyla (ML-DSA) eşleştirmenize olanak tanıyan yeni bir APK İmza Şeması sunar.

Bu karma yaklaşım, uygulamanızın gelecekteki kuantum saldırılarına karşı güvenli kalmasını sağlarken eski Android sürümleri ve klasik imza doğrulamayı kullanan cihazlarla tam geriye dönük uyumluluğu korur.

Geliştiriciler üzerindeki etkisi

  • Play Uygulama İmzalama'yı kullanan uygulamalar: Play Uygulama İmzalama'yı kullanıyorsanız Google Play'in, Google Play tarafından oluşturulan bir PQC anahtarı kullanarak karma imzayı yükseltme seçeneğini sunmasını bekleyebilirsiniz. Bu sayede, manuel anahtar yönetimi gerektirmeden uygulamanızın korunmasını sağlayabilirsiniz.
  • Kendi kendine yönetilen anahtarları kullanan uygulamalar: Kendi imzalama anahtarlarını yöneten geliştiriciler, PQC anahtarını yeni bir klasik anahtarla birleştiren hibrit kimliğe geçmek için güncellenmiş Android derleme araçlarını (ör. apksigner) kullanabilir. (Yeni bir klasik anahtar oluşturmanız gerekir, eski anahtarı yeniden kullanamazsınız.)

Bağlantı

Android 17, cihaz ve uygulama bağlantısını iyileştirmek için aşağıdaki özellikleri ekler.

Kısıtlanmış uydu ağları

Uygulamaların düşük bant genişliğine sahip uydu ağlarında etkili bir şekilde çalışmasını sağlamak için optimizasyonlar uygular.

Kullanıcı deneyimi ve sistem arayüzü

Android 17, kullanıcı deneyimini iyileştirmek için aşağıdaki değişiklikleri içerir.

Özel Asistan ses akışı

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, Android 17'de kullanıma sunulacak yeni bir özellik ve API'dir. Uygulama geliştiriciler, kullanıcılarına cihazlar arası süreklilik sağlamak için bu özelliği entegre edebilir. Kullanıcının bir Android cihazda uygulama etkinliği başlatmasına ve bunu başka bir Android cihaza aktarmasına olanak tanır. Devretme, kullanıcının cihazının arka planında çalışır ve kullanıcının yakındaki diğer cihazlarındaki kullanılabilir etkinlikleri, alıcı cihazdaki başlatıcı ve görev çubuğu gibi çeşitli giriş noktaları üzerinden gösterir.

Uygulamalar, Handoff'u kullanarak aynı yerel Android uygulamasını başlatabilir. Bunun için uygulamanın, alıcı cihaza yüklenmiş ve kullanılabilir olması gerekir. Bu uygulama içi akışta, kullanıcı belirlenen etkinliğe derin bağlantıyla yönlendirilir. Alternatif olarak, uygulamadan web'e geçiş, yedek seçenek olarak sunulabilir veya doğrudan URL ile geçiş ile uygulanabilir.

Aktarma desteği, etkinlik bazında uygulanır. Devretme'yi etkinleştirmek için etkinliğin setHandoffEnabled() yöntemini çağırın. Devretme işlemiyle birlikte ek verilerin de aktarılması gerekebilir. Böylece, alıcı cihazda yeniden oluşturulan etkinlik uygun durumu geri yükleyebilir. Devretme özelliğinin, etkinliği alıcı cihazda nasıl işleyip yeniden oluşturacağını belirten ayrıntıları içeren bir HandoffActivityData nesnesi döndürmek için onHandoffActivityDataRequested() geri çağırma işlevini uygulayın.

Canlı güncelleme - Anlamsal renk API'si

With Android 17, Live Update launches the Semantic Coloring APIs to support colors with universal meaning.

The following classes support semantic coloring:

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)

Android 17 için UWB Downlink-TDoA API'si

Aşağı bağlantı geliş zamanı farkı (DL-TDoA) aralığı, bir cihazın sinyallerin göreli geliş zamanlarını ölçerek birden fazla sabite göre konumunu belirlemesine olanak tanır.

Aşağıdaki snippet'te Ranging Manager'ın nasıl başlatılacağı, cihaz özelliklerinin nasıl doğrulanacağı ve DL-TDoA oturumunun nasıl başlatılacağı gösterilmektedir:

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

Bant dışı (OOB) yapılandırmalar

Aşağıdaki snippet'te, Wi-Fi ve BLE için DL-TDoA OOB yapılandırma verilerine dair bir örnek verilmiştir:

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

Eksik olduğu için OOB yapılandırmasını kullanamıyorsanız veya OOB yapılandırmasında olmayan varsayılan değerleri değiştirmeniz gerekiyorsa aşağıdaki snippet'te gösterildiği gibi DlTdoaRangingParams.Builder ile parametreler oluşturabilirsiniz. DlTdoaRangingParams.createFromFiraConfigPacket() yerine aşağıdaki parametreleri kullanabilirsiniz:

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