Ö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, performans sorunlarında hata ayıklamak için ayrıntılı veriler toplamanıza yardımcı olmak amacıyla ProfilingManager'a çeşitli yeni sistem tetikleyicileri ekler.

Yeni tetikleyiciler:

  • TRIGGER_TYPE_COLD_START: Tetikleyici, uygulamanın soğuk başlatılması sırasında gerçekleşir. Yanıt hem çağrı yığını örneği hem de sistem izi içerir.
  • TRIGGER_TYPE_OOM: Bir uygulama OutOfMemoryError oluşturduğunda ve buna yanıt olarak Java Heap Dump sağladığında tetikleyici gerçekleşir.
  • TRIGGER_TYPE_KILL_EXCESSIVE_CPU_USAGE: Tetikleyici, bir uygulama anormal ve aşırı CPU kullanımı nedeniyle kapatıldığında gerçekleşir ve yanıt olarak bir çağrı yığını örneği sağlar.

Sistem tetikleyicisinin nasıl ayarlanacağını öğrenmek için tetikleyici tabanlı profilleme ve profilleme verilerini alma ve analiz etme ile ilgili dokümanlara bakın.

JobDebugInfo API'leri

Android 17, geliştiricilerin JobScheduler işlerinde hata ayıklamasına yardımcı olmak için yeni JobDebugInfo API'leri sunar. Bu API'ler, işlerin neden çalışmadığı, ne kadar süre çalıştığı ve diğer toplu bilgilerle ilgili veriler sağlar.

Genişletilmiş JobDebugInfo API'lerinin ilk yöntemi olan getPendingJobReasonStats(), işin neden bekleyen yürütme durumunda olduğuna dair nedenlerin ve ilgili kümülatif bekleyen sürelerin haritasını döndürür. Bu yöntem, planlanmış bir işin neden beklendiği gibi çalışmadığına dair bilgi edinmenizi sağlamak için getPendingJobReasonsHistory() ve getPendingJobReasons() yöntemlerini birleştirir. Ancak hem süreyi hem de iş nedenini tek bir yöntemde kullanılabilir hale getirerek bilgi almayı kolaylaştırır.

Örneğin, belirtilen bir jobId için yöntem, PENDING_JOB_REASON_CONSTRAINT_CHARGING ve 60.000 ms'lik bir süre döndürebilir. Bu, şarj kısıtlaması karşılanmadığı için işin 60.000 ms boyunca beklemede olduğunu gösterir.

Gizlilik

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

Android kişi seçici

Android Kişi Seçici, kullanıcıların kişilerle ilgili bilgileri uygulamanızla paylaşması için standartlaştırılmış ve gözatılabilir bir arayüzdür. Android 17 (API düzeyi 37) veya sonraki sürümlerin yüklü olduğu cihazlarda kullanılabilen seçici, geniş kapsamlı READ_CONTACTS iznine gizliliği korumaya yönelik bir alternatif sunar. Uygulamanız, kullanıcının tüm adres defterine erişim isteğinde bulunmak yerine ihtiyaç duyduğu veri alanlarını (ör. telefon numaraları veya e-posta adresleri) belirtir ve kullanıcı, paylaşılacak belirli kişileri seçer. Bu sayede uygulamanız yalnızca seçilen verilere okuma erişimi kazanır. Böylece, kullanıcı arayüzünü oluşturmak veya bakımını yapmak zorunda kalmadan yerleşik arama, profil değiştirme ve çoklu seçim özellikleri sayesinde tutarlı bir kullanıcı deneyimi sunarken ayrıntılı kontrol de sağlanır.

Daha fazla bilgi için kişi seçici dokümanlarına bakın.

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 Gelişmiş Koruma Modu, Android kullanıcılarına güçlü bir yeni güvenlik özellikleri paketi sunarak kullanıcıları, özellikle de daha yüksek risk altındaki kullanıcıları gelişmiş saldırılardan koruma konusunda önemli bir adım atıyor. İsteğe bağlı bir özellik olarak tasarlanan AAPM, kullanıcıların istediği zaman etkinleştirerek güvenlik korumaları uygulayabileceği tek bir yapılandırma ayarıyla etkinleştirilir.

Bu temel yapılandırmalar arasında bilinmeyen kaynaklardan uygulama yüklenmesini engelleme (yan yükleme), USB veri sinyalini kısıtlama ve Google Play Protect taramasını zorunlu kılma yer alır. Bu yapılandırmalar, cihazın saldırı yüzey alanını önemli ölçüde azaltır. Geliştiriciler, modun durumunu algılamak için AdvancedProtectionManager API'sini kullanarak bu özellikle entegrasyon yapabilir. Böylece, kullanıcı modu etkinleştirdiğinde uygulamalar otomatik olarak daha sıkı bir güvenlik duruşu benimseyebilir veya yüksek riskli işlevleri kısıtlayabilir.

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 karma 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ı

Implements optimizations to enable apps to function effectively over low-bandwidth satellite networks.

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ışı

Test edilebilir mi? (Gerekli derleme) Evet (Android 17 Beta 1 veya sonraki sürümler)
targetSDKVersion değiştirilmesi mi gerekiyor? (API düzeyi) Hayır (Geçersiz)
compileSDKVersion değiştirilmesi mi gerekiyor? (API düzeyi) Hayır (Geçersiz)

Android 17, USAGE_ASSISTANT ile oynatma için Asistan uygulamalarına özel bir Asistan ses akışı sunar. Bu değişiklik, Asistan sesini standart medya akışından ayırarak kullanıcılara her iki ses düzeyi üzerinde de ayrı ayrı kontrol imkanı sunar. Bu sayede, Asistan yanıtlarının duyulabilirliğini korurken medya oynatmayı sessize alma veya tam tersi gibi senaryolar mümkün olur.

Yeni MODE_ASSISTANT_CONVERSATION ses moduna erişimi olan asistan uygulamaları, ses kontrolünün tutarlılığını daha da artırabilir. Asistan uygulamaları, etkin bir Asistan oturumu hakkında sisteme ipucu vermek için bu modu kullanabilir. Böylece Asistan akışının, etkin USAGE_ASSISTANT oynatma dışında veya bağlı Bluetooth çevre birimleriyle kontrol edilmesi sağlanır.

Aktarma

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 onHandoffActivityRequested() callback to return a HandoffActivityData object which contains details that specify how Handoff should handle and recreate the activity on the receiving device.

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

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