مانند نسخههای قبلی، اندروید ۱۴ شامل تغییرات رفتاری است که ممکن است بر برنامه شما تأثیر بگذارد. تغییرات رفتاری زیر منحصراً برای برنامههایی اعمال میشود که اندروید ۱۴ (سطح API ۳۴) یا بالاتر را هدف قرار میدهند. اگر برنامه شما اندروید ۱۴ یا بالاتر را هدف قرار میدهد، باید برنامه خود را اصلاح کنید تا در صورت لزوم، از این رفتارها به درستی پشتیبانی کند.
حتماً فهرست تغییرات رفتاری که بر همه برنامههای در حال اجرا در اندروید ۱۴ تأثیر میگذارند را صرف نظر از targetSdkVersion برنامه، بررسی کنید.
عملکرد اصلی
انواع خدمات پیشزمینه الزامی هستند
اگر برنامه شما Android 14 (سطح API 34) یا بالاتر را هدف قرار می دهد، باید حداقل یک نوع سرویس پیش زمینه را برای هر سرویس پیش زمینه در برنامه شما مشخص کند. شما باید یک نوع سرویس پیش زمینه را انتخاب کنید که نشان دهنده مورد استفاده برنامه شما باشد. این سیستم انتظار دارد که خدمات پیش زمینه ای که نوع خاصی دارند، مورد استفاده خاص را برآورده کنند.
اگر مورد استفاده در برنامه شما با هیچ یک از این انواع مرتبط نیست، اکیداً توصیه میشود که منطق خود را برای استفاده از WorkManager یا کارهای انتقال داده توسط کاربر تغییر دهید.
اعمال مجوز BLUETOOTH_CONNECT در BluetoothAdapter
Android 14 مجوز BLUETOOTH_CONNECT را هنگام فراخوانی روش BluetoothAdapter getProfileConnectionState() برای برنامههایی که Android 14 (سطح API 34) یا بالاتر را هدف قرار میدهند، اعمال میکند.
این روش قبلاً به مجوز BLUETOOTH_CONNECT نیاز داشت، اما اجرا نشد. مطمئن شوید که برنامه شما BLUETOOTH_CONNECT را در فایل AndroidManifest.xml برنامه شما همانطور که در قطعه زیر نشان داده شده است، اعلام کرده و بررسی کنید که یک کاربر قبل از تماس با getProfileConnectionState مجوز را داده است .
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
بهروزرسانیهای OpenJDK 17
Android 14 به کار تازه کردن کتابخانههای اصلی Android ادامه میدهد تا با ویژگیهای جدیدترین نسخه OpenJDK LTS، از جمله بهروزرسانیهای کتابخانه و پشتیبانی از زبان جاوا 17 برای توسعهدهندگان برنامهها و پلتفرمها، هماهنگ شود.
تعدادی از این تغییرات می تواند بر سازگاری برنامه تأثیر بگذارد:
- تغییرات در عبارات منظم : ارجاعات گروه نامعتبر اکنون مجاز نیستند تا معنایی OpenJDK را با دقت بیشتری دنبال کنند. ممکن است موارد جدیدی را مشاهده کنید که در آن یک
IllegalArgumentExceptionتوسط کلاسjava.util.regex.Matcherپرتاب می شود، بنابراین مطمئن شوید که برنامه خود را برای مناطقی که از عبارات منظم استفاده می کنند آزمایش کنید. برای فعال یا غیرفعال کردن این تغییر در حین آزمایش، پرچمDISALLOW_INVALID_GROUP_REFERENCEرا با استفاده از ابزارهای چارچوب سازگاری تغییر دهید. - مدیریت UUID : متد
java.util.UUID.fromString()اکنون بررسی های دقیق تری را هنگام تأیید آرگومان ورودی انجام می دهد، بنابراین ممکن است در حین deserialization یکIllegalArgumentExceptionرا مشاهده کنید. برای فعال یا غیرفعال کردن این تغییر در حین آزمایش، پرچمENABLE_STRICT_VALIDATIONرا با استفاده از ابزارهای چارچوب سازگاری تغییر دهید. - مشکلات ProGuard : در برخی موارد، افزودن کلاس
java.lang.ClassValueباعث ایجاد مشکل می شود اگر بخواهید برنامه خود را با استفاده از ProGuard کوچک کنید، مبهم کنید و بهینه کنید. مشکل از یک کتابخانه Kotlin سرچشمه می گیرد که رفتار زمان اجرا را بر اساس اینکهClass.forName("java.lang.ClassValue")یک کلاس را برمی گرداند یا نه، تغییر می دهد. اگر برنامه شما بر اساس نسخه قدیمیتری از زمان اجرا بدون کلاسjava.lang.ClassValueدر دسترس است، این بهینهسازیها ممکن است متدcomputeValueرا از کلاسهای مشتقشده ازjava.lang.ClassValueحذف کنند.
JobScheduler رفتار پاسخ به تماس و شبکه را تقویت میکند
自从引入后,JobScheduler 期望您的应用从
onStartJob 或 onStopJob。在 Android 14 之前,如果作业运行时间过长,系统会停止作业并静默失败。如果您的应用以 Android 14(API 级别 34)或更高版本为目标平台,
超过在主线程上授予的时间,应用会触发 ANR
显示“没有响应 onStartJob”错误消息或
“onStopJob没有回复”。
此 ANR 可能是由以下 2 种情况造成的:
1.有工作阻塞主线程,阻止回调 onStartJob
或者onStopJob在预期时间内执行并完成。
2. 开发者在 JobScheduler 中运行阻塞工作
回调 onStartJob 或 onStopJob,阻止从
在预期的时限内完成
要解决第 1 个问题,您需要进一步调试阻塞主线程的因素
您可以使用以下代码
ApplicationExitInfo#getTraceInputStream(),用于获取 Tombstone
ANR 发生时的跟踪信息如果您能够手动重现 ANR 问题
您可以录制系统轨迹,并使用
Android Studio 或 Perfetto,以便更好地了解应用上运行的
在发生 ANR 时调用主线程
请注意,直接使用 JobScheduler API 或使用 androidx 库 WorkManager 时可能会发生这种情况。
如需解决问题 2,请考虑迁移到 WorkManager,它支持将 onStartJob 或 onStopJob 中的任何处理封装在异步线程中。
JobScheduler 还引入了一项要求,即如果使用 setRequiredNetworkType 或 setRequiredNetwork 约束条件,则必须声明 ACCESS_NETWORK_STATE 权限。如果您的应用未声明
ACCESS_NETWORK_STATE 权限
Android 14 或更高版本,则会导致 SecurityException。
رابط برنامهنویسی کاربردی (API) راهاندازی Tiles
برای برنامههایی که نسخه ۱۴ و بالاتر را هدف قرار میدهند، TileService#startActivityAndCollapse(Intent) منسوخ شده است و اکنون هنگام فراخوانی یک استثنا ایجاد میکند. اگر برنامه شما فعالیت ها را از کاشی ها راه اندازی می کند، به جای آن از TileService#startActivityAndCollapse(PendingIntent) استفاده کنید.
حریم خصوصی
دسترسی جزئی به عکسها و ویدیوها
Android 14 دسترسی به عکسهای انتخاب شده را معرفی میکند، که به کاربران اجازه میدهد به برنامهها اجازه دسترسی به تصاویر و ویدیوهای خاص موجود در کتابخانه خود را بدهند، نه اینکه به همه رسانههای یک نوع خاص دسترسی داشته باشند.
این تغییر تنها در صورتی فعال میشود که برنامه شما Android 14 (سطح API 34) یا بالاتر را هدف قرار دهد. اگر هنوز از انتخابگر عکس استفاده نکردهاید، توصیه میکنیم آن را در برنامه خود پیادهسازی کنید تا تجربهای ثابت برای انتخاب تصاویر و ویدیوها ارائه دهید که همچنین حریم خصوصی کاربر را بدون نیاز به درخواست مجوز ذخیرهسازی افزایش میدهد.
اگر انتخابگر گالری خود را با استفاده از مجوزهای ذخیره سازی حفظ می کنید و نیاز دارید که کنترل کامل بر پیاده سازی خود داشته باشید، پیاده سازی خود را با استفاده از مجوز جدید READ_MEDIA_VISUAL_USER_SELECTED تطبیق دهید. اگر برنامه شما از مجوز جدید استفاده نمی کند، سیستم برنامه شما را در حالت سازگاری اجرا می کند.
تجربه کاربری
اعلانهای هدفمند تمامصفحه امن
با Android 11 (سطح API 30)، برای هر برنامه ای امکان استفاده از Notification.Builder.setFullScreenIntent برای ارسال اهداف تمام صفحه در حالی که گوشی قفل است وجود داشت. میتوانید با اعلام مجوز USE_FULL_SCREEN_INTENT در AndroidManifest، این را در نصب برنامه به طور خودکار اعطا کنید.
اعلانهای تمام صفحه برای اعلانهای با اولویت بسیار طراحی شدهاند که توجه فوری کاربر را میطلبد، مانند تماس تلفنی دریافتی یا تنظیمات ساعت زنگ دار که توسط کاربر پیکربندی شده است. برای برنامههایی که Android 14 (سطح API 34) یا بالاتر را هدف قرار میدهند، برنامههایی که مجاز به استفاده از این مجوز هستند محدود به برنامههایی هستند که فقط تماس و زنگ هشدار ارائه میکنند. فروشگاه Google Play مجوزهای USE_FULL_SCREEN_INTENT پیشفرض را برای هر برنامهای که با این نمایه مطابقت ندارد لغو میکند. مهلت این تغییرات خط مشی 31 مه 2024 است.
این مجوز برای برنامههای نصبشده روی تلفن قبل از بهروزرسانی کاربر به Android 14 فعال باقی میماند. کاربران میتوانند این مجوز را روشن و خاموش کنند.
می توانید از API جدید NotificationManager.canUseFullScreenIntent استفاده کنید تا بررسی کنید که آیا برنامه شما مجوز دارد یا خیر. در غیر این صورت، برنامه شما میتواند از هدف جدید ACTION_MANAGE_APP_USE_FULL_SCREEN_INTENT برای راهاندازی صفحه تنظیمات استفاده کند که در آن کاربران میتوانند مجوز را صادر کنند.
امنیت
محدودیتهای مربوط به intentهای ضمنی و در حال انتظار
对于以 Android 14(API 级别 34)或更高版本为目标平台的应用,Android 会通过以下方式限制应用向内部应用组件发送隐式 intent:
- 隐式 intent 只能传送到导出的组件。应用必须使用显式 intent 传送到未导出的组件,或将该组件标记为已导出。
- 如果应用通过未指定组件或软件包的 intent 创建可变待处理 intent,系统会抛出异常。
这些变更可防止恶意应用拦截意在供应用内部组件使用的隐式 intent。
例如,下面是可以在应用的清单文件中声明的 intent 过滤器:
<activity
android:name=".AppActivity"
android:exported="false">
<intent-filter>
<action android:name="com.example.action.APP_ACTION" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
如果应用尝试使用隐式 intent 启动此 activity,则系统会抛出 ActivityNotFoundException 异常:
Kotlin
// Throws an ActivityNotFoundException exception when targeting Android 14. context.startActivity(Intent("com.example.action.APP_ACTION"))
Java
// Throws an ActivityNotFoundException exception when targeting Android 14. context.startActivity(new Intent("com.example.action.APP_ACTION"));
如需启动非导出的 activity,应用应改用显式 intent:
Kotlin
// This makes the intent explicit. val explicitIntent = Intent("com.example.action.APP_ACTION") explicitIntent.apply { package = context.packageName } context.startActivity(explicitIntent)
Java
// This makes the intent explicit. Intent explicitIntent = new Intent("com.example.action.APP_ACTION") explicitIntent.setPackage(context.getPackageName()); context.startActivity(explicitIntent);
گیرندههای پخش ثبتشده در زمان اجرا باید رفتار صادراتی را مشخص کنند
以 Android 14(API 级别 34)或更高版本为目标平台并使用上下文注册的接收器的应用和服务必须指定以下标志,以指明接收器是否应导出到设备上的所有其他应用:RECEIVER_EXPORTED 或 RECEIVER_NOT_EXPORTED。此要求有助于利用 Android 13 中引入的这些接收器的功能,来保护应用免受安全漏洞的影响。
仅接收系统广播的接收器的例外情况
如果您的应用仅通过 Context#registerReceiver 方法(例如 Context#registerReceiver())针对系统广播注册接收器,那么它在注册接收器时不应指定标志。
بارگذاری کد پویای امنتر
如果您的应用以 Android 14(API 级别 34)或更高版本为目标平台并使用动态代码 正在加载 (DCL),所有动态加载的文件都必须标记为只读。 否则,系统会抛出异常。我们建议应用尽可能避免动态加载代码,因为这样做会大大增加应用因代码注入或代码篡改而遭到入侵的风险。
如果必须动态加载代码,请使用以下方法,在动态文件(例如 DEX、JAR 或 APK 文件)打开并写入任何内容之前立即将其设为只读:
Kotlin
val jar = File("DYNAMICALLY_LOADED_FILE.jar") val os = FileOutputStream(jar) os.use { // Set the file to read-only first to prevent race conditions jar.setReadOnly() // Then write the actual file content } val cl = PathClassLoader(jar, parentClassLoader)
Java
File jar = new File("DYNAMICALLY_LOADED_FILE.jar"); try (FileOutputStream os = new FileOutputStream(jar)) { // Set the file to read-only first to prevent race conditions jar.setReadOnly(); // Then write the actual file content } catch (IOException e) { ... } PathClassLoader cl = new PathClassLoader(jar, parentClassLoader);
处理已存在的动态加载文件
为防止系统对现有动态加载的文件抛出异常,我们建议您先删除并重新创建文件,然后再尝试在应用中重新动态加载这些文件。重新创建文件时,请按照上述指南在写入时将文件标记为只读。或者,您可以将现有文件重新标记为只读,但在这种情况下,我们强烈建议您先验证文件的完整性(例如,对照可信值检查文件的签名)以保护应用免遭恶意操作的影响。
محدودیتهای اضافی در شروع فعالیتها از پسزمینه
برای برنامههایی که Android 14 (سطح API 34) یا بالاتر را هدف قرار میدهند، سیستم زمانی را محدود میکند که برنامهها مجاز به شروع فعالیتها از پسزمینه باشند:
- وقتی یک برنامه با استفاده از
PendingIntent#send()یا روشهای مشابه، یکPendingIntentارسال میکند، اگر برنامه میخواهد امتیازات راهاندازی فعالیت پسزمینه خود را برای شروع هدف معلق اعطا کند، باید آن را انتخاب کند. برای شرکت کردن، برنامه باید یک بستهActivityOptionsباsetPendingIntentBackgroundActivityStartMode(MODE_BACKGROUND_ACTIVITY_START_ALLOWED)ارسال کند. - هنگامی که یک برنامه قابل مشاهده، سرویس برنامه دیگری را که در پسزمینه است با استفاده از روش
bindService()متصل میکند، برنامه قابل مشاهده اگر میخواهد امتیازات راهاندازی فعالیت پسزمینه خود را به سرویس محدود اعطا کند، اکنون باید شرکت کند. برای شرکت کردن، برنامه باید هنگام فراخوانی متدbindService()پرچمBIND_ALLOW_ACTIVITY_STARTSرا داشته باشد.
این تغییرات مجموعه محدودیتهای موجود را گسترش میدهد تا با جلوگیری از سوء استفاده برنامههای مخرب از APIها برای شروع فعالیتهای مخرب از پسزمینه، از کاربران محافظت کند.
پیمایش مسیر زیپ
对于以 Android 14(API 级别 34)或更高版本为目标平台的应用,Android 会通过以下方式防止 Zip 路径遍历漏洞:如果 Zip 文件条目名称包含“..”或以“/”开头,ZipFile(String) 和 ZipInputStream.getNextEntry() 会抛出 ZipException。
应用可以通过调用 dalvik.system.ZipPathValidator.clearCallback() 选择停用此验证。
رضایت کاربر برای هر جلسه ضبط MediaProjection الزامی است
برای برنامههایی که Android 14 (سطح API 34) یا بالاتر را هدف قرار میدهند، یک SecurityException توسط MediaProjection#createVirtualDisplay در یکی از سناریوهای زیر ایجاد میشود:
- برنامه شما
Intentکه ازMediaProjectionManager#createScreenCaptureIntentبرگردانده میشود در حافظه پنهان ذخیره میکند و چندین بار آن را بهMediaProjectionManager#getMediaProjectionارسال میکند. - برنامه شما چندین بار
MediaProjection#createVirtualDisplayرا در یک نمونهMediaProjectionفراخوانی می کند.
برنامه شما باید قبل از هر جلسه عکسبرداری از کاربر بخواهد رضایت بدهد. یک جلسه ضبط یک فراخوانی واحد در MediaProjection#createVirtualDisplay است و هر نمونه MediaProjection باید فقط یک بار استفاده شود.
کنترل تغییرات پیکربندی
اگر برنامه شما نیاز به فراخوانی MediaProjection#createVirtualDisplay برای مدیریت تغییرات پیکربندی دارد (مانند تغییر جهت صفحه یا اندازه صفحه)، میتوانید این مراحل را برای بهروزرسانی VirtualDisplay برای نمونه MediaProjection موجود دنبال کنید:
-
VirtualDisplay#resizeکنید. - یک
Surfaceجدید با عرض و ارتفاع جدیدVirtualDisplay#setSurfaceارائه دهید.
پاسخ تماس را ثبت کنید
برنامه شما باید برای رسیدگی به مواردی که کاربر برای ادامه جلسه ضبط رضایت نمی دهد، یک تماس پاسخ ثبت کند. برای انجام این کار، Callback#onStop را پیاده سازی کنید و از برنامه خود بخواهید منابع مرتبط (مانند VirtualDisplay و Surface ) را منتشر کند.
اگر برنامه شما این پاسخ تماس را ثبت نکند، MediaProjection#createVirtualDisplay هنگامی که برنامه شما آن را فراخوانی می کند، یک IllegalStateException ایجاد می کند.
محدودیتهای غیر SDK بهروزرسانی شدند
اندروید ۱۴ شامل فهرستهای بهروز شدهای از رابطهای کاربری محدود شده غیر SDK بر اساس همکاری با توسعهدهندگان اندروید و آخرین آزمایشهای داخلی است. در صورت امکان، قبل از محدود کردن رابطهای کاربری غیر SDK، مطمئن میشویم که جایگزینهای عمومی در دسترس هستند.
اگر برنامه شما اندروید ۱۴ را هدف قرار نمیدهد، ممکن است برخی از این تغییرات بلافاصله شما را تحت تأثیر قرار ندهند. با این حال، اگرچه در حال حاضر میتوانید از برخی رابطهای غیر SDK ( بسته به سطح API هدف برنامه خود ) استفاده کنید، استفاده از هر روش یا فیلد غیر SDK همیشه خطر بالای خرابی برنامه شما را به همراه دارد.
اگر مطمئن نیستید که برنامه شما از رابطهای غیر SDK استفاده میکند، میتوانید برنامه خود را آزمایش کنید تا متوجه شوید. اگر برنامه شما به رابطهای غیر SDK متکی است، باید برنامهریزی برای مهاجرت به جایگزینهای SDK را آغاز کنید. با این وجود، ما درک میکنیم که برخی از برنامهها موارد استفاده معتبری برای استفاده از رابطهای غیر SDK دارند. اگر نمیتوانید جایگزینی برای استفاده از رابط غیر SDK برای یک ویژگی در برنامه خود پیدا کنید، باید یک API عمومی جدید درخواست کنید .
برای کسب اطلاعات بیشتر در مورد تغییرات این نسخه از اندروید، بهروزرسانیهای محدودیتهای رابط غیر SDK در Android 14 را ببینید. برای کسب اطلاعات بیشتر در مورد رابط های غیر SDK به طور کلی، به محدودیت ها در رابط های غیر SDK مراجعه کنید.