Funkcje i interfejsy API

Android 17 wprowadza nowe funkcje i interfejsy API dla deweloperów. W kolejnych sekcjach znajdziesz podsumowanie tych funkcji, które pomoże Ci rozpocząć korzystanie z powiązanych interfejsów API.

Szczegółową listę nowych, zmodyfikowanych i usuniętych interfejsów API znajdziesz w raporcie o różnicach w interfejsach API. Szczegółowe informacje o nowych interfejsach API znajdziesz w dokumentacji interfejsów API Androida. Nowe interfejsy API są wyróżnione.

Sprawdź też obszary, na które zmiany na platformie mogą mieć wpływ. Więcej informacji znajdziesz na tych stronach:

Główna funkcja

Android 17 wprowadza te nowe funkcje związane z podstawową funkcjonalnością Androida:

Nowe aktywatory ProfilingManager

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

新增的触发条件包括:

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

Interfejsy JobDebugInfo API

Android 17 引入了新的 JobDebugInfo API,可帮助开发者调试 其 JobScheduler 作业,包括作业为何未运行、运行了多长时间以及 其他汇总信息。

扩展后的 JobDebugInfo API 的第一个方法是 getPendingJobReasonStats(),该方法会返回一个映射,其中包含作业处于 待执行状态的原因及其各自的累计待执行 时长。此方法将 getPendingJobReasonsHistory()getPendingJobReasons() 方法结合在一起,让您能够了解预定 作业为何未按预期运行,但通过在单个方法中提供时长和作业原因,简化了信息检索。

例如,对于指定的 jobId,该方法可能会返回 PENDING_JOB_REASON_CONSTRAINT_CHARGING 和 60000 毫秒的时长,表明 作业因未满足充电限制而处于待执行状态 60000 毫秒。

Prywatność

Android 17 zawiera te nowe funkcje, które zwiększają prywatność użytkowników.

Selektor kontaktów na Androidzie

Android 联系人选择器是一个标准化的可浏览界面,供用户与您的应用分享联系人。该选择器可在搭载 Android 17 或更高版本的设备上使用,可提供一种注重隐私保护的替代方案,以取代范围广泛的 READ_CONTACTS 权限。您的应用不会请求访问用户的整个地址簿,而是指定所需的数据字段(例如电话号码或电子邮件地址),然后用户选择要分享的特定联系人。这只会授予您的应用对所选数据的读取权限,从而确保精细控制,同时提供一致的用户体验,并具有内置的搜索、个人资料切换和多选功能,而无需构建或维护界面。

如需了解详情,请参阅联系人选择器文档

Bezpieczeństwo

Android 17 zawiera te nowe funkcje, które zwiększają bezpieczeństwo urządzenia i aplikacji:

Tryb ochrony zaawansowanej na Androidzie (AAPM)

Android 高级保护模式为 Android 用户提供了一套强大的新安全功能,标志着在保护用户(尤其是面临较高风险的用户)免遭复杂攻击方面迈出了重要一步。AAPM 是一项选择启用功能,只需进行一项配置设置即可激活。用户可以随时启用该功能,以应用一套主观的安全保护措施。

这些核心配置包括:禁止安装未知来源的应用(旁加载)、限制 USB 数据信号传输,以及强制执行 Google Play 保护机制扫描,从而显著减小设备的攻击面。 开发者可以使用 AdvancedProtectionManager API 与此功能集成,以检测模式的状态,从而使应用能够在用户选择启用此模式时自动采用强化型安全姿态或限制高风险功能。

Łączność

Android 17 wprowadza te funkcje, aby poprawić łączność urządzeń i aplikacji.

Sieci satelitarne o ograniczonej przepustowości

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

Wrażenia użytkowników i interfejs systemu

Android 17 zawiera te zmiany, które zwiększają wygodę użytkowników.

Handoff

Przekazywanie to nowa funkcja i interfejs API, które pojawią się w Androidzie 17. Deweloperzy aplikacji mogą je zintegrować, aby zapewnić użytkownikom ciągłość działania na różnych urządzeniach. Umożliwia użytkownikowi rozpoczęcie działania w aplikacji na jednym urządzeniu z Androidem i przeniesienie go na inne urządzenie z Androidem. Przekazywanie działa w tle na urządzeniu użytkownika i wyświetla dostępne działania z innych pobliskich urządzeń użytkownika w różnych punktach wejścia, takich jak program uruchamiający i pasek zadań na urządzeniu odbierającym.

Aplikacje mogą wyznaczyć przekazywanie, aby uruchamiać tę samą natywną aplikację na Androida, jeśli jest ona zainstalowana i dostępna na urządzeniu odbierającym. W tym przepływie między aplikacjami użytkownik jest przekierowywany za pomocą precyzyjnego linku do wyznaczonej aktywności. Przekazywanie z aplikacji do przeglądarki może być też oferowane jako opcja rezerwowa lub bezpośrednio wdrażane za pomocą przekazywania z użyciem adresu URL.

Obsługa funkcji Handoff jest wdrażana w przypadku poszczególnych aktywności. Aby włączyć przekazywanie, wywołaj metodę setHandoffEnabled() dla aktywności. Wraz z przekazaniem może być konieczne przesłanie dodatkowych danych, aby odtworzona aktywność na urządzeniu odbierającym mogła przywrócić odpowiedni stan. Zaimplementuj wywołanie zwrotne onHandoffActivityRequested(), aby zwrócić obiekt HandoffActivityData, który zawiera szczegółowe informacje określające, jak funkcja przekazywania ma obsługiwać i odtwarzać aktywność na urządzeniu odbierającym.

Live Update - Semantic color 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 na Androida 17

Określanie odległości za pomocą różnicy czasu dotarcia sygnału w kierunku do urządzenia (DL-TDoA) pozwala urządzeniu określić swoje położenie względem wielu punktów dostępu przez pomiar względnych czasów dotarcia sygnałów.

Poniższy fragment kodu pokazuje, jak zainicjować Menedżera pomiarów odległości, sprawdzić możliwości urządzenia i rozpocząć sesję 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.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
        }
    }
}

Konfiguracje poza pasmem (OOB)

Poniższy fragment zawiera przykład danych konfiguracyjnych DL-TDoA OOB dla Wi-Fi i 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
};

Jeśli nie możesz użyć konfiguracji OOB, ponieważ jej brakuje, lub jeśli musisz zmienić wartości domyślne, których nie ma w konfiguracji OOB, możesz utworzyć parametry za pomocą znaku DlTdoaRangingParams.Builder, jak pokazano w tym fragmencie kodu. Zamiast parametru DlTdoaRangingParams.createFromFiraConfigPacket() możesz użyć tych parametrów:

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