اندروید ۱۷ ویژگیها و APIهای جدید و فوقالعادهای را برای توسعهدهندگان معرفی میکند. بخشهای زیر این ویژگیها را خلاصه میکنند تا به شما در شروع کار با APIهای مرتبط کمک کنند.
برای مشاهده لیست کاملی از APIهای جدید، اصلاحشده و حذفشده، گزارش تفاوت API را مطالعه کنید. برای جزئیات بیشتر در مورد APIهای جدید، به مرجع API اندروید مراجعه کنید - APIهای جدید برای مشاهده، هایلایت شدهاند.
همچنین باید حوزههایی را که تغییرات پلتفرم ممکن است بر برنامههای شما تأثیر بگذارد، بررسی کنید. برای اطلاعات بیشتر، به صفحات زیر مراجعه کنید:
- تغییرات رفتاری که هنگام هدف قرار دادن برنامهها در اندروید ۱۷، بر آنها تأثیر میگذارند
- تغییرات رفتاری که صرف نظر از
targetSdkVersion، بر همه برنامهها تأثیر میگذارد .
عملکرد اصلی
اندروید ۱۷ ویژگیهای جدید زیر را که مربوط به قابلیتهای اصلی اندروید هستند، اضافه میکند.
تریگرهای جدید ProfilingManager
اندروید ۱۷ چندین تریگر سیستمی جدید به ProfilingManager اضافه کرده است تا به شما در جمعآوری دادههای عمیق برای اشکالزدایی مشکلات عملکرد کمک کند.
محرکهای جدید عبارتند از:
-
TRIGGER_TYPE_COLD_START: تریگر در هنگام شروع سرد برنامه رخ میدهد. این تریگر هم نمونهای از پشته فراخوانی و هم ردگیری سیستم را در پاسخ ارائه میدهد. -
TRIGGER_TYPE_OOM: تریگر زمانی رخ میدهد که یک برنامهOutOfMemoryErrorرا صادر کند و در پاسخ، یک Java Heap Dump ارائه دهد. -
TRIGGER_TYPE_KILL_EXCESSIVE_CPU_USAGE: تریگر زمانی رخ میدهد که یک برنامه به دلیل استفاده غیرعادی و بیش از حد از CPU از بین میرود و در پاسخ، یک نمونه پشته فراخوانی ارائه میدهد. -
TRIGGER_TYPE_ANOMALY: ناهنجاریهای عملکرد سیستم مانند فراخوانیهای بیش از حد binder و استفاده بیش از حد از حافظه را تشخیص میدهد.
برای درک نحوه تنظیم تریگر سیستم، به مستندات مربوط به پروفایلینگ مبتنی بر تریگر و نحوه بازیابی و تجزیه و تحلیل دادههای پروفایلینگ مراجعه کنید.
ماشه پروفایلینگ برای ناهنجاریهای برنامه
اندروید ۱۷ یک سرویس تشخیص ناهنجاری روی دستگاه معرفی میکند که رفتارهای فشرده از منابع و رگرسیونهای سازگاری بالقوه را رصد میکند. این سرویس که با ProfilingManager ادغام شده است، به برنامه شما اجازه میدهد تا مصنوعات پروفایلینگ ایجاد شده توسط رویدادهای خاص شناسایی شده توسط سیستم را دریافت کند.
از تریگر TRIGGER_TYPE_ANOMALY برای تشخیص مشکلات عملکرد سیستم مانند فراخوانیهای بیش از حد binder و استفاده بیش از حد از حافظه استفاده کنید. هنگامی که یک برنامه محدودیتهای حافظه تعریف شده توسط سیستم عامل را نقض میکند، تریگر ناهنجاری به توسعهدهندگان اجازه میدهد تا heap dumpهای مخصوص برنامه را دریافت کنند تا به شناسایی و رفع مشکلات حافظه کمک کنند. علاوه بر این، برای هرزنامههای بیش از حد 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)
}
APIهای JobDebugInfo
Android 17 引入了新的 JobDebugInfo API,可帮助开发者调试其 JobScheduler 作业,了解作业未运行的原因、运行时长以及其他汇总信息。
扩展后的 JobDebugInfo API 的第一个方法是 getPendingJobReasonStats(),该方法会返回一个映射,其中包含作业处于待执行状态的原因及其各自的累计待执行时长。此方法将 getPendingJobReasonsHistory() 和 getPendingJobReasons() 方法联接在一起,可让您了解预定作业未按预期运行的原因,但通过在单个方法中同时提供时长和作业原因,简化了信息检索。
例如,对于指定的 jobId,该方法可能会返回 PENDING_JOB_REASON_CONSTRAINT_CHARGING 和 60000 毫秒的时长,表示作业因未满足充电约束而处于等待状态 60000 毫秒。
کاهش قفلهای بیدارباش با پشتیبانی شنونده برای آلارمهای allow-while-idle
اندروید ۱۷ نوع جدیدی از AlarmManager.setExactAndAllowWhileIdle را معرفی میکند که به جای PendingIntent یک OnAlarmListener میپذیرد. این مکانیزم جدید مبتنی بر فراخوانی برای برنامههایی که در حال حاضر برای انجام وظایف دورهای، مانند برنامههای پیامرسان که اتصالات سوکت را حفظ میکنند، به wakelockهای مداوم متکی هستند، ایدهآل است.
حریم خصوصی
اندروید ۱۷ شامل ویژگیهای جدید زیر برای بهبود حریم خصوصی کاربران است.
پشتیبانی از پلتفرم رمزگذاری شده کلاینت هلو (ECH)
اندروید ۱۷ پشتیبانی پلتفرم از Encrypted Client Hello (ECH) را معرفی میکند، که یک بهبود قابل توجه در حریم خصوصی ارتباطات شبکه است. ECH یک افزونه TLS 1.3 است که نشانگر نام سرور (SNI) را در طول اولین اتصال TLS رمزگذاری میکند. این رمزگذاری با دشوارتر کردن شناسایی دامنه خاصی که یک برنامه به آن متصل میشود، برای واسطههای شبکه، به محافظت از حریم خصوصی کاربر کمک میکند.
این پلتفرم اکنون شامل APIهای لازم برای کتابخانههای شبکه برای پیادهسازی ECH است. این شامل قابلیتهای جدید در DnsResolver برای جستجوی رکوردهای HTTPS DNS حاوی پیکربندیهای ECH و روشهای جدید در SSLEngines و SSLSockets متعلق به Conscrypt برای فعال کردن ECH با ارسال این پیکربندیها هنگام اتصال به یک دامنه است. توسعهدهندگان میتوانند تنظیمات ECH، مانند فعال کردن آن به صورت فرصتطلبانه یا اجباری کردن استفاده از آن را از طریق عنصر جدید <domainEncryption> در فایل پیکربندی امنیت شبکه، که به صورت جهانی یا بر اساس هر دامنه قابل اجرا است، پیکربندی کنند.
انتظار میرود کتابخانههای شبکه محبوب مانند HttpEngine، WebView و OkHttp این APIهای پلتفرم را در بهروزرسانیهای آینده ادغام کنند و پذیرش ECH و افزایش حریم خصوصی کاربران را برای برنامهها آسانتر کنند.
برای اطلاعات بیشتر، به مستندات Encrypted Client Hello مراجعه کنید.
انتخابگر مخاطبین اندروید
انتخابگر مخاطب اندروید (Android Contact Picker) یک رابط کاربری استاندارد و قابل مرور برای کاربران است تا مخاطبین را با برنامه شما به اشتراک بگذارند. این انتخابگر که در دستگاههای دارای اندروید ۱۷ (سطح API ۳۷) یا بالاتر موجود است، جایگزینی با حفظ حریم خصوصی برای مجوز گسترده READ_CONTACTS ارائه میدهد. برنامه شما به جای درخواست دسترسی به کل دفترچه آدرس کاربر، فیلدهای داده مورد نیاز خود، مانند شماره تلفن یا آدرس ایمیل را مشخص میکند و کاربر مخاطبین خاصی را برای اشتراکگذاری انتخاب میکند. این به برنامه شما اجازه میدهد فقط به دادههای انتخاب شده دسترسی داشته باشد و کنترل جزئی را تضمین کند و در عین حال یک تجربه کاربری سازگار با قابلیتهای جستجوی داخلی، تغییر پروفایل و انتخاب چندگانه را بدون نیاز به ساخت یا نگهداری رابط کاربری ارائه دهد.
برای اطلاعات بیشتر، به مستندات contact picker مراجعه کنید.
امنیت
اندروید ۱۷ ویژگیهای جدید زیر را برای بهبود امنیت دستگاه و برنامهها اضافه میکند.
حالت حفاظت پیشرفته اندروید (AAPM)
Android 高级保护模式为 Android 用户提供了一套强大的新安全功能,标志着在保护用户(尤其是面临较高风险的用户)免遭复杂攻击方面迈出了重要一步。AAPM 是一项选择启用功能,只需进行一项配置设置即可激活。用户可以随时启用该功能,以应用一套主观的安全保护措施。
这些核心配置包括:禁止安装未知来源的应用(旁加载)、限制 USB 数据信号传输,以及强制执行 Google Play 保护机制扫描,从而显著减小设备的攻击面。
开发者可以使用 AdvancedProtectionManager API 与此功能集成,以检测模式的状态,从而使应用能够在用户选择启用此模式时自动采用强化型安全姿态或限制高风险功能。
امضای APK PQC
Android 现在支持混合 APK 签名方案,以保护应用的签名身份免受利用量子计算的攻击的潜在威胁。此功能引入了一种新的 APK 签名方案,可让您将经典签名密钥(例如 RSA 或 EC)与新的后量子加密 (PQC) 算法 (ML-DSA) 配对。
这种混合方法可确保您的应用在未来免受量子攻击,同时与依赖于经典签名验证的旧版 Android 和设备保持完全的向后兼容性。
对开发者的影响
- 使用 Play 应用签名的应用:如果您使用 Play 应用签名,可以等待 Google Play 为您提供使用 Google Play 生成的 PQC 密钥升级混合签名的选项,从而确保您的应用受到保护,而无需手动管理密钥。
- 使用自行管理的密钥的应用:自行管理签名密钥的开发者可以利用更新后的 Android build 工具(例如 apksigner)轮换到混合身份,将 PQC 密钥与新的经典密钥相结合。(您必须创建新的经典密钥,无法重复使用旧密钥。)
اتصال
اندروید ۱۷ ویژگیهای زیر را برای بهبود اتصال دستگاه و برنامه اضافه میکند.
شبکههای ماهوارهای محدود
实现优化,使应用能够在低带宽卫星网络上有效运行。
تجربه کاربری و رابط کاربری سیستم
اندروید ۱۷ شامل تغییرات زیر برای بهبود تجربه کاربری است.
جریان صدای اختصاصی دستیار
Android 17 为 Google 助理应用引入了专用的 Google 助理音量流,
以便使用 USAGE_ASSISTANT 进行播放。此项更改将 Google 助理音频与标准媒体流分离,让用户可以单独控制这两个音量。这样便可实现以下场景:将媒体播放静音,同时保持 Google 助理响应的可听性,反之亦然。
有权访问新的 MODE_ASSISTANT_CONVERSATION 音频模式的 Google 助理应用可以进一步提高音量控制的一致性。Google 助理应用可以使用此模式向系统提供有关活跃 Google 助理会话的提示,确保可以在活跃 USAGE_ASSISTANT 播放之外或使用连接的蓝牙外设控制 Google 助理流。
تحویل دستی
切换是 Android 17 中新增的一项功能和 API,应用开发者可以将其集成到应用中,以便为用户提供跨设备连续性。它允许用户在一个 Android 设备上启动应用 activity,然后将其转移到另一个 Android 设备。Handoff 在用户设备的后台运行,并通过各种入口点(例如接收设备上的启动器和任务栏)显示用户附近其他设备上的可用活动。
应用可以指定 Handoff 来启动相同的原生 Android 应用(如果该应用已安装在接收设备上且可供使用)。在此应用到应用流程中,用户通过深层链接跳转到指定 activity。或者,应用到网站切换功能可以作为后备选项提供,也可以通过网址切换功能直接实现。
切换支持是按 activity 实现的。如需启用 Handoff,请针对 activity 调用 setHandoffEnabled() 方法。可能需要随切换传递其他数据,以便接收设备上重新创建的 activity 可以恢复适当的状态。实现 onHandoffActivityDataRequested() 回调以返回 HandoffActivityData 对象,该对象包含用于指定 Handoff 应如何处理并在接收设备上重新创建 activity 的详细信息。
بهروزرسانی زنده - API رنگ معنایی
在 Android 17 中,实时更新启动了语义着色 API,以支持具有通用含义的颜色。
以下类支持语义着色:
NotificationNotification.MetricNotification.ProgressStyle.PointNotification.ProgressStyle.Segment
填色游戏
- 绿色:与安全相关。此颜色应在以下情况下使用:让别人知道您处于安全状态。
- 橙色:用于表示警告和标记物理危险。在用户需要注意以设置更好的保护设置的情况下,应使用此颜色。
- 红色:通常表示危险、停止。它应在需要人们紧急关注的情况下显示。
- 蓝色:中性颜色,适用于信息性内容,应与其他内容区分开来。
以下示例展示了如何将语义样式应用于通知中的文本:
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 برای اندروید ۱۷
下行链路到达时间差 (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();