اندروید 14 – محدودیت ها و ویژگی های جدید

اندروید 14 - محدودیت ها و ویژگی های جدید
در این پست می‌خوانید:

به نام خدا، اندروید 14 منتشر شد، قصد دارم دربارۀ اکثر اثراتی که روی برنامه نویسان اندروید گذاشته صحبت کنم. قرار محدودیت های جدید در حالت پس زمینه، تغییرات در Foreground Services و محدودیت های تازه در کار با intent و BroadcastReceiver رو وارسی کنیم، محدودیت های زیادی در اندروید 14 داریم اما ویژگی های تازه ای هم داریم.

Predictive Back Gesture در اندروید 14

در اندروید 13 انتظار می رفت که در نسخۀ بعدی اندروید (که اندروید 14 باشه) ما باید منتظر بروزآوری جدیدی دربارۀ Predictive Back Gesture باشیم. همچنین امکان ایجاد transition animation های شخصی سازی شده افزوده شده هست.

برای این منظور متد handleOnBackProgressed() به OnBackPressedCallback افزوده شده. این متد مانند handleOnBackPressed() با پیشرفت Back Gesture صدا زده شده. متد هایی که به ترتیب در انتهای انیمیشن Back Gesture و لغو آن فراخوانی می شن.

در صفحه نمایش می تونی نمونه ای از پیاده سازی انیمیشن سفارشی خود رو با استفاده از کتابخانۀ Jetpack AppCompat 1.8.0 مشاهده کنی.

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        ...
        val box = findViewById<View>(R.id.box)
        val screenWidth = 
            Resources.getSystem().displayMetrics.widthPixels
        val maxXShift = (screenWidth / 20)

        val callback = object : OnBackPressedCallback(
            enabled = true
        ) {

            override fun handleOnBackProgressed(
                backEvent: BackEvent
            ) {
                when (backEvent.swipeEdge) {
                    BackEvent.EDGE_LEFT ->
                        box.translationX = backEvent.progress *     
                            maxXShift
                    BackEvent.EDGE_RIGHT ->
                        box.translationX = -(backEvent.progress * 
                            maxXShift)
                }
                box.scaleX = 1F - (0.1F * backEvent.progress)
                box.scaleY = 1F - (0.1F * backEvent.progress)
            }

            override fun handleOnBackPressed() {
                // Back Gesture competed
            }

            
            override fun handleOnBackCancelled() {
                // Back Gesture cancelled 
                // Reset animation objects to initial state
            }
        }
        this.onBackPressedDispatcher.addCallback(callback)
    }
}

همچنین بجای صدا زدن تابع overidePendingTransition() که منسوخ شده است باید تابع جدید overrideActivityTransition() رو صدا بزنی. تابع فعلی با Predictive Back به درستی کار نمی کنه چون هنگان اجرای transition animation اولویت بیشتری داره.

// New API
overrideActivityTransition(
    enterAnim = R.anim.open_trans,
    exitAnim = R.anim.exit_trans,
    backgroundColor = R.color.bgr_color
)

// deprecated
overridePendingTransition(R.anim.open_trans, R.anim.exit_trans)

محدودیت نصب برنامه های قدیمی در اندروید 14

یکی از تعییرات اعلام شده برای اندروید 14، ناتوانی برای نصب اپلیکیشن های با targetSdk کمتر 23 (اندروید 6) هست. با minSdk اشتباه نگیرید!

هدف از این تغییر توقف توزیع برنامه هایی هست که به نسخه های جدید targetSdk بروزرسانی نمی شن و خارج از Google Play توزیع می شن و از آسیب پذیری های قدیمی اندروید بهره می برن. بدین ترتیب اپلیکیشن ها می تونن با دور زدن مکانیزم Runtime Permission تمامی مجوز ها رو حین نصب بدست بیارن.

هنگامی که کاربر سعی کنه چنین برنامه ای رو نصب کنه با خطا بر می خوره و در logcat یک گزارش با جزئیات پدیدار می شه:

INSTALL_FAILED_DEPRECATED_SDK_VERSION: App package must target at least SDK version 23, but found 7

یعنی targetSDK حداقل باید api 23 باشه اما بجاش نسخۀ 7 یافت شد.

نصب برنامه ها با هر targetSDK از طریق adb با یک flag ویژه برای نادیده گرفتن محدودیت ها قابل دسترسی خواهد بود.

adb install --bypass-low-target-sdk-block FILENAME.apk

بنظر میاد این راه حل درستی برای مبارزه با نرم افزار های قدیمی باشه؛ همچنین برای آن دسته از علاقه مندان که می خواهند این کار رو انجام بدن از طریق adb فرصت رو باز گذاشتند. می شه انتظار داشت با هر نسخه اندروید جدید targetSdkVersion افزایش یابه.

بین المللی شدن با اندروید 14

اکنون کاربران می تونن تنظیمات regional setting رو بدون توجه به انتخاب شده در system locale تغییر بدن: واحد های دما، روز اول هفته و سیستم های محاسبه. توسعه دهندگان باید هنگام توسعۀ نرم افزار خود این اطلاعات رو مدنظر داشته باشند.

Grammatical Inflection API در اندروید 14

برای زبان هایی که مفهوم جنسیت در آنها تعریف شده؛ مانند روسی، ایتالیایی، فرانسوی و… ، اندروید 14، Grammatical Inflection API رو معرفی کرده. اکنون می تونی جنسیت کاربر رو برای یک برنامه از طریق GrammaticalInflectionManager مشخص کنی، که باعث می شه Activity به عنوان بخشی از پیکر بندی دوباره ایجاد بشه.

// Specify user's gender for grammar
val gIM: GrammaticalInflectionManager = сontext.getSystemService()
gIM.setRequestedApplicationGrammaticalGender(
  Configuration.GRAMMATICAL_GENDER_FEMININE
)

اکنون در منابع می تونی رشته های جداگانه برای جنسیت های مختلف درست کنی.

اندروید 14 - دریافت جنسیت از سیستم

Nonlinear text increment (افزایش غیر خطی متن) در اندروید 14

در اندروید توصیه می شه اندازۀ متن رو در sp تنظیم کنی. sp یک واحد ویژه هست گه اندازه متن درنظر گرفت شده توسط کاربر در تنظیمات گوشیش رو لحاظ می کنه. نکته منفیش اونجا بود که اگر متن کوچک می بود خوانا می بود و اگر متن بزرگ می شد بخاطرش برش خوردن ناخوانا می شد.

اندروید 14 یک سیستم مقیاس بندی متن جدیدی رو بربنیاد Web Content Accessibility Guidelines که مختصر WCAG خوانده می شود، معرفی کرد. اکنون یک مقیاس فونت غیر خطی اعمال می شه. این بدان معنی که متن بزرگ تر به اندازۀ متن کوچک تر افزایش نمی یابه.

افزون بر این، حداکثر اندازۀ متن افزایش خواهد یافت. در pixel 7 pro، در اندروید 13 حداکثر مقدار 130% بود اما در اندروید 14 ، 200% است.

اندروید 14 ، افزایش مقیاس متن به صورت غیر خطی

مقایسه اندازه متن در اندروید 13 و اندروید 14 در پیکسل 7 پرو

برای تبدیل صحیح پیکسل ها به sp و back، باید از TypedValue.applyDimension() و TypedValue.deriveDimension() استفاده کنی. این APIها ویژگی های مقیاس بندی متن غیرخطی رو در نظر می گیرن، برخلاف ضرب کردن ساده اندازه متن در SP در ضریب مقیاس بندی که می شه در Configuration.fontScale و DisplayMetrics.scaledDensity به دست آورد.

// Convert 10 SP to PX
TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 10F, displayMetrics)

// Convert 50 PX to SP
TypedValue.deriveDimension(TypedValue.COMPLEX_UNIT_SP, 50F, displayMetrics)

share sheet (اشتراک گذاری برگه) در اندروید 14

اگر می خواهید به جدید ترین روش های برنامه نویسی اندروید با استفاده از کاتلین مسلط بشید و همۀ معماری های موجود در اندروید را یاد بگیرید در دورۀ نخبگان اندروید محمد نوری با بیش از ده سال تجربه شرکت کنید

اندروید 14 طراحی و ویؤگی های share sheet رو بروزرسانی کرده. گفت و گوی سیستمی که هنگام به اشتراک گذاری متن، عکس یا سایر محتوا ها ببینی. در Pixel 7 Pro در بخش Direct Share، به جای 4 عنصر در Android 13، پنج عنصر در اندروید 14 قرار داده  شده. آنها همچنهین سیستم رتبه بندی رو تغییر دادن.

هنگام ارسال پیام به کاربر، از ShortcutManagerCompat.pushDynamicShortcut() استفاده کنید و هنگان ایجاد ShortcutInfo ؛ addCapabilityBinding() رو با اکشن actions.intent.SEND_MESSAGE صدا بزن.

ShortcutManagerCompat.pushDynamicShortcut(context,
    ShortcutInfoCompat.Builder(context, id)
        // Configure Shortcut
        .addCapabilityBinding("actions.intent.SEND_MESSAGE")
        .build()
)
اندروید 14 share sheet

بروزرسانی ShareSheet در اندروید 14

اکنون در رابط کاربری استاندارد سیستم، امکان افزودن action های اضافی به عنوان یک شی ChooserAction، حاوی icon، عنوان و PendingIntent وجود خواهد داشت که هنگام انتخاب یک action فرستاده می شن. هیچ محدودیتی برای تعداد action های شخصی ات وجود نداره.

یک action ویژۀ دیگه ای هم وجود داره که برای ویرایش محتوای فرستاده شده درنگریسته شده. برای ایجادش باید از ChooserActions نیز استفاده کنی.

تمام action های اضافی ایجاد شده باید از طریق EXTRA جدید به Intent افزوده بشن. در پایین می توانی نحوۀ انجامش رو مشاهده کنی.

val intent: Intent = // Create Inent и put content for sharing

val modifyAction: ChooserAction = 
    ChooserAction.Builder(modifyIcon, "Modify Share", modifyActionIntent).build()
// Specify action to edit content
intent.putExtra(EXTRA_CHOOSER_MODIFY_SHARE_ACTION, modifyAction)


// Additional actions that can be done with content
val customActions: Array<ChooserAction> = arrayOf(
  ChooserAсtion.Builder(copyIcon, "Copy", copyIntent).build(),
  ChooserAсtion.Builder(albumIcon, "Create Album", createAlbumIntent).build(),
  ChooserAсtion.Builder(createLinkIcon, "Create link", createLinkIntent).build()
)
// Add additional actions that can be done with content
inent.putExtra(Intent.EXTRA_CHOOSER_CUSTOM_ACTIONS, customActions)


// Create Intent for Share Sheet
val chooserIntent = Intent.createChooser(customActions, "Share 1 image")
// Launch Share Sheet
context.startActivity(chooserIntent)

 

SCHEDULE_EXACT_ALARM به طور پیش فرض در اندروید 14 غیرفعال است

برای اپلیکیشن های با targetSDK ی 33 به بالا (اندروید 14 و بالاتر)

در Android 12 یک مجوز جدید با نام SCHEDULE_EXACT_ALARM برای استفاده از API AlarmManager معرفی شد که با زمان دقیق زنگ هشدار مرتبط است. در اندروید 13 مجوز جدید USE_EXACT_ALARMS پدیدار گشت. در اندروید 14 هیچ مجوز جدیدی افزوده نشد، اما آن ها کار SCHEDULE_EXACT_ALARM رو تغییر دادند.

اکنون برای برنامه هایی با targetSdk 33 و بالاتر صادر نمی شه. در صورت به‌روزرسانی دستگاه یا بازیابی نسخه پشتیبانی، مجوز اعطا می‌شه، اما برای نصب‌های جدید، مجوز داده نمی شه. استثناها دربرگیرندۀ برنامه های امضا شده با گواهی سیستم و برنامه های دارای امتیازات ویژه و همچنین برنامه هاییه که بهینه سازی باتری براشون غیرفعاله.

تعیین نوع Foreground Service در اندروید 14 الزامیه

در اندروید 10 برای تمامی سرویس های Foreground، امکان اعلام نوع سرویسی که هدف از راه اندازیش رو مشخص می کنه، پدیدار شد. در اندروید 14 ، تعیین نوع برای همه سرویس هایی که می تونن به عنوان Foreground راه اندازی بشن اجباری می شه و در اندروید مدرن تقریباً همه مواردش هست.

برای پوشش تمام گزینه های مورد استفاده برای Foreground Service، نوع های جدیدی از سرویس ها رو افزودند، و هر یک از آنها مجوز ویژه ای دارن.

<!-- AndroidManifest.xml -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

    <!-- Permission to launch Foreground Service -->
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

    <!-- Permission to launch Foreground Service with dataSync type -->
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />

    <application>
        <service
            android:name=".SyncService"
            android:foregroundServiceType="dataSync"
        />
    </application>
</manifest>

این ویژگی جدید مشخص می کنه که آیا عملیات انجام شده در سرویس، ذیل دسته بندی های مجاز قرار می گیره یا نه. نیز سیستم می تونه درک بهتری از آنچه برنامه انجام می ده و آنکه آیا چیزی مشکوک وجود داره یا نه، داشته باشه. گوگل اکیداً استفاده از WorkManager و دیگر API های ویژه رو توصیه می کنه؛ اما اگر نتونستند نیازت رو برطرف کنن آنگاه به عنوان راه حل جایگزین، ناچار ForegroundService رو پیاده سازی کن.

Google Play همچنین ForegroundService رو در مرحله آپلود ساخت بررسی می کند. هر برنامه با پشتیبانی از اندروید 14 (targetSdk>= 34) باید تأیید کنه که سرویس با نوع وظیفه اعلام شده، مورد نیازه. اگرنه اجازه انتشار در فروشگاه رو نخواهی داشت.

برای راه اندازی ForegroundService افزون بر راه اندازی ForegroundService، باید مجوز راه اندازی نوع خاصی از سرویس رو هم بیفزونی. همه این مجوزها از نوع عادی هستند، یعنی مجوزها هنگام نصب برنامه به طور خودکار صادر می شن و نیازی نیست که آن ها رو جداگانه درخواست کنی.

افزون بر مجوز، الزامات دیگه ای هم وجود داره، برای مثل واسۀ سرویسی که با دوربین کار می کنه، لازم است که AndroidManifest مجوز CAMERA نیز داشته باشد. اطلاعات بیشتر در مورد نوع ها و مجوزهای متصل را می توان در اسناد رسمی یافت.

همه نوع ها با یک مورد استفاده خاص مرتبط هستن، به جز موارد زیر:

  • systemExempted – نوعی ویژه، طراحی شده برای برنامه های سیستمی و ساعت های زنگ داری که با وجود مجوزهای SCHEDULE_EXACT_ALARM و USE_EXACT_ALARM تعیین می شن.
  • نوع specialUse زمانی استفاده می شه که سایر نوع های ForegroundService مناسبت نباشن. اعلام آن افزون بر نوع و مجوز، مستلزم مشخص کردن دلیل استفاده از این نوع در یک property خاص در AndroidManifest است. ایده هایت رو در مورد شیوۀ استفاده از این نوع های جدید در comment ها بنویس.
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" />

    <application>

        <service
            android:name=".SpecialService"
            android:foregroundServiceType="specialUse">
            <property
                android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE"
                android:value="Reason to use special service type" />
        </service>
    </application>
</manifest>
  • نوع shortService برای انجام عملیات هایی در نظر گرفته شده است که نمی شه آن ها رو قطع یا به تاخیر انداخت. این نوع به مجوز های اضافی نیاز نداره اما دارای چند تا محدودیت خاص هست: طول عمر محدودی داره (تا 3 دقیقه)، نمی شه سایر ForegroundService ها رو راه اندازی کرد، نمی شه پس از متوقف شدن روند برنامه توسط سیستم عامل دوباره راه اندازی کرد سرویس رو، و غیره.

طول عمر سرویس از لحظه فراخوانی startForeground() محاسبه می شه. انتظار می ره سرویس با فراخوانی stopSelf() یا stopForeground() به پایان برسه. هنگامی که زمان اجرا منقضی می شود، یک متد callback جدید در سرویس فراخوانی می شود – onTimeout(). این callback بهت هشدار می ده که تنها یک فرصت برای متوقف کردن سرویس برات باقی مونده.

در غیر این صورت، ANR رخ می ده حتی اگر برنامه عملیات دیگری رو در ForegroundService انجام بده. غیرفعال کردن بهینه سازی باتری، بر محدودیت طول عمر سرویس تأثیر نمی گذاره.

تمدید طول عمر Short Foreground Service امکان پذیره. اگر برنامه بتونه ForegroundService رو راه اندازی کنه، می تونه Short Foreground Service رو دوباره از نو راه اندازی کنه. راه اندازی مجدد سرویس کوتاه مدت عمر سرویس رو 3 دقیقه افزایش می ده.

محدودیت های جدید بر Implicit Intent در اندروید 14

اندروید 14 همچنان به اعمال بهترین شیوه ها برای جلوگیری از سوء استفادۀ بدافزارها از اجزای برنامه داخلی، ادامه می ده. اکنون Implicit Intent ها فقط به اجزای برنامه صادر شده تحویل داده می شن. برای مواردی که صادر نشده اند، باید از Explicit Intent ها استفاده بشه.

<activity
    android:name=".AppActivity"
    android:exported="false">
    <intent-filter>
        <action android:name="dev.androidbroadcast.action.APP_ACTION" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>
// Drop the exception in case if targetSdk 34+
context.startActivity(Intent("dev.androidbroadcast.action.APP_ACTION"))

// Make the Intent clear by specifying the application package
val explicitIntent = 
    Intent("dev.androidbroadcast.action.APP_ACTION")
        // Specifying the application package where the component is located    
        // In case of your application, package of your application
        .setPackage(context.packageName)
context.startActivity(explicitIntent)

دومین تغییر در مکانیسم Intent آنه که هر PendingIntent قابل تغییری که از Implicit Intent استفاده می کنه حالا به یک exception می فرجامه.

تغییرات BroadcastReceiver در اندروید 14

فزون بر این، رفتار intent که تحویل context-registered می شه، برای همه برنامه ها، صرف نظر از targetSdk، تغییر می کنه. تمام intentهایی که ممکنه دریافت کنن، زمانی که برنامه در حالت cache هست (به عنوان مثال مینیمایز شده و کاربر برای مدتی از آن استفاده نکرده است)، تحویل داده نمی شن.

تحویل intent زمانی صورت می گیره که برنامه دوباره فعال بشه. افزون بر این، هنگام فرستادن چندین intent یکسان تنها یکی از آنها قابل تحویل دادنه.

همچنین ثبت BroadcastReceiver  از طریق کد نویسی، نسبت به قبل سخت تر شده. اکنون باید مشخص شه که آیا آنها بر بنیاد قیاس صادر می شن یا خیر، همونجور که برای همۀ اجزای موجود در AndroidManifest انجام می شه.

هنگام ثبت کردن باید پرچم RECEIVER_EXPORTED یا RECEIVER_NOT_EXPORTED رو مشخص کنی. این تغییر فقط برای برنامه هایی با پشتیبانی از اندروید 14 کار می کنه:

class DataReceiver: BroadcastReceiver() {

    override fun onReceive(context: Context, intent: Intent) {
        // Process data
    }
}

val intentFilter = IntentFilter() // configure IntentFilter
context.registerReceiver(DataReceiver(), intentFilter, Context.RECEIVER_NOT_EXPORTED)

بروزرسانی های JobScheduler در اندروید 14

JobScheduler توانایی راه اندازی وظایف طولانی برای انتقال داده بین دستگاه و سرور رو داره. این نوع وظیفه a user-initiated data transfer job (یک کار انتقال داده توسط کاربر) خوانده می شه. این نوع کار فقط زمانی قابل راه اندازیه که برنامه برای کاربر قابل مشاهده باشه یا زمانی که برنامه بتواند یک Activity رو از طریق background راه اندازی کنه.

برای راه‌اندازی یک کار انتقال داده توسط کاربر، باید مجوز RUN_USER_INITIATED_JOBS رو در AndroidManifest بنهی و سرویسی رو بیفزونی که از کلاس JobService ارث بری کرده باشه.

حین ایجاد JobInfo باید متد setUserInitiated() رو با مدار true به عنوان آرگومان صدا بزنی. یک پیش نیاز برای راه اندازی JobInfo وجود داره و آن، نمایش اعلان سیستم (نوتیفیکشن) هست. تو باید این کار را هنگام صدا زدن ()onStartJob انجام بدی.

<manifest xmlns:android="http://schemas.android.com/apk/res/android">

    <uses-permission android:name="android.permission.RUN_USER_INITIATED_JOBS" />

    <application>
        <service
            android:name="dev.androidbroadcast.CustomTransferService"
            android:exported="false"
            android:permission="android.permission.BIND_JOB_SERVICE" />
    </application>
</manifest>
val networkRequest = NetworkRequest.Builder()
    .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
    .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED)
    // Additional network request requirement
    .build()

val jobInfo = JobInfo.Builder(1, ComponentName(context, CustomTransferService::class.java))
    .setUserInitiated(true)
    .setRequiredNetwork(networkRequest)
    .setEstimatedNetworkBytes(ONE_GIGABYTE, ZERO_BYTES)
    // ...
    .build()

val jobScheduler: JobScheduler = checkNotNull(context.getSystemService())
jobScheduler.schedule(jobInfo)
class CustomTransferService : JobService() {

    override fun onStartJob(job: JobParameters): Boolean {
        if (job.jobId == JOB_ID) {
            // Showing a notification
            setNotification(job, NOTIF_ID, newNotification(), JobService.JOB_END_NOTIFICATION_POLICY_REMOVE)
            val success = doDataTransfer()
            jobFinished(job, wantsReschedule = !success)
            return false
        }
        error("Job isn't handled")
    }
}

واسۀ شروع موفقیت آمیز، لازمه تمام شرایط اجرا رو فراهم کنی. فزون بر این، سیستم باید منابع لازم برای اجرای خودش رو داشته باشه. تفاوت مهم یک کار انتقال داده که توسط کاربر آغاز می شه اینه که مشمول سهمیه های App Standby Buckets برای شروع کار نیست.

تحت شرایط بخصوص، سیستم همچنان می تونه در صورت لزوم، کار رو متوقف کنه. قبل از آن، متد ()onStopJob صدا زده می شه که در آن بهت توصیه می شه پیشرفت فعلی عملیات شبکه رو ذخیره کنی تا پس از راه اندازی مجدد، مجبور نباشی کار را از اول انجام بدی، بلکه فقط قسمت لازم رو تکمیل کنی.

class CustomTransferService : JobService() {

    override fun onStopJob(job: JobParameters): Boolean {
        if (job.jobId == JOB_ID) {
            // Saving data transfer progress
            return true
        }
    }
}

از API به نظر میاد که تگ User Initiated رو می توان برای هر نوع Job (کار) ساخت، اما مستندات متد می گه که در اندروید 14 فقط باید در ترکیب با setRequiredNetwork() یا setRequiredNetworkType() صدا زده بشه. شاید در نسخه‌های بعدی اندروید، شاهد نوع های بیشتری از وظایف با تگ های صریح باشیم که می‌تونن توسط کاربر آغاز بشن.

هنگام انتشار اندروید 14، Jetpack WorkManager (جایگزین پیشنهادی گوگل بجای JobScheduler) مستقیما این ویژگی رو به API خودش نیفزوده بود. این ممکنه در نسخه های بعدی روی بده، یا این تغییر تحت پوشش WorkManager API موجود استفاده بشه.

دسترسی جزئی به عکس ها و فیلم ها

همانند iOS، اندروید 14 دسترسی جزئی به عکس ها و فیلم ها رو فراهم می کنه. اکنون، وقتی رسانه درخواست می‌کنی، کاربر دیالوگی رو می‌بینه که ازش می‌خواد یا برای دسترسی به همه رسانه‌ها یا دسترسی تنها به عکس‌ها/فیلم‌ها یکی رو انتخاب کنه. این ویژگی جدید برای همه برنامه ها، صرف نظر از targetSdk.OS آنها کار خواهد کرد.

اندروید 14 و ای او اس

در سمت چپ – اندروید 14؛ در سمت راست — iOS 14.

اندروید 13 پیشتر مجوز های جداگانه ای را برای دسترسی به عکس و دسترسی به ویدیو معرفی کرده. اکنون یک مجوز اضافی دیگه READ_MEDIA_VISUAL_USER_SELECTED وجود خواهد داشت که بهت امکان می ده بارها و بارها یک انتخاب رو برای عکس ها/فیلم های جداگانه درخواست کنی. مجوز جدید باید فزون بر READ_MEDIA_IMAGES و READ_MEDIA_VIDEO موجود برای پشتیبانی از رفتار جدید استفاده بشه. اعلام آن به این معنی است که برنامه شما از این انتخاب مجدد پشتیبانی می کنه.

<manifest xmlns:android="http://schemas.android.com/apk/res/android" />

    <!-- Devices running Android 13 (API level 33) or higher -->
    <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
    <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />

    <!-- To handle the reselection within the app on Android 14 -->
    <uses-permission android:name="android.permission.READ_MEDIA_VISUAL_USER_SELECTED" />

</manifest>

دسترسی به رسانه های فردی به صورت موقت اعطا می شه، اما مستندات رسمی مدت زمانش رو توضیح نداده. اگر مجوز جدید اعلام نشه، هنگامی که برنامه به پس زمینه می ره یا کاربر برنامه رو از بین می بره، دسترسی جزئی بلافاصله لغو می شه. چیزی شبیه به شیوۀ عملکرد یک مجوز موقت یک بار مصرف. بنابراین، نمی تونی وضعیت های دریافت مجوز READ_MEDIA_VISUAL_USER_SELECTED رو ذخیره کنی و باید هر بار آن ها رو بررسی کنی.

وقتی دستگاهت رو به اندروید 14 به‌روزرسانی می کنی، اگر برنامه با کسب مجوز های مناسب به عکس‌ها/فیلم‌های کاربر دسترسی کامل داشته باشه، همان سطح دسترسی به این داده ها رو حفظ می کنه.

مستندات می گه که افزودن مجوز و مکانیسم جدید بر کار برنامه شما تأثیری نخواهد داشت. اما در آینده باید با در نظر گرفتن اینکه کاربر ممکن است بخواد عکس های جدیدی رو به انتخاب بیفزونه، اصلاح بشه.

برخی از برنامه ها حتی برای کار با کل کتابخانه رسانه طراحی شده اند و بی گمان نیاز به دوباره کاری دارن. در جایگاه یک کاربر، من آن رو به عنوان یک پیشرفت بزرگ می بینم چون انواع پیام رسان ها و شبکه های اجتماعی دیگه نمی تونن به هر آنچه که من در گالری دارم دسترسی داشته باشن.

اگر برنامه شما نیاز به دسترسی به عکس ها/فیلم ها در حین اجرا در پس زمینه داره، قویاً توصیه می شه از مجوز جدید برای عملکرد صحیح بیشتر پشتیبانی کنی. در غیر این صورت، ممکن است به طور مرتب این مجوزها را در Android 14 لغو کنی.

بهبودی های AppStore در اندروید 14

اندروید 14 با افزودن API های جدید به PackageInstaller، زندگی فروشگاه های شخص ثالث رو آسون تر می کنه. بیا با محدودیت های نصب برنامه ها آغاز کنیم! حالا می شه در هر زمان با فراخوانی API مربوطه اتفاق بیفته. Android U اومده Install Constraints API رو اضافه کرده که بهت امکان می ده شرایطی رو مشخص کنی که تحت آن بشه نصب رو انجام داد.

PackageInstaller.InstallConstraints.Builder()
    // The application isn’t visible to the user
    .setAppNotForegroundRequired()
    // No interaction with the application
    .setAppNotInteractingRequired()
    // The application is visible but not in the foreground
    .setAppNotTopVisibleRequired()
    // The device isn't used
    .setDeviceIdleRequired()
    // No current phone call
    .setNotInCallRequired()
    .build()

سپس می تونی با استفاده از متد checkInstallConstraints () بررسی کنی که آیا برنامه های مشخص شده الزامات رو برآورده می کنن یا نه.

val packageInstaller: PackageInstaller = //...
packageInstaller.checkInstallConstraints(
    packageNames = listOf("dev.androidbroadcast"),
    constraints,
    Executors.newSingleThreadExecutor()
) { result: PackageInstaller.InstallConstraintsResult ->
    if (result.areAllConstraintsSatisfied()) {
        // install APK files
    }
}

همچنین می تونی متد مسدود کنندۀ ()watchForInstallConstraints  رو فراخوانی کنی، که تا زمانی که شرایط برای برنامه‌های مشخص شده برآورده بشه، منتظر بمانه.

packageInstaller.waitForInstallConstraints(
    listOf("dev.androidbroadcast"),
    constraints,
    intentSender,
    timeout = Duration.ofHours(1).toMillis()
)

با استفاده از متد ()commitSessionAfterInstallConstraintsAreMet می تونی بروزرسانی رو تا زمانی که شرایط برآورده بشه به تعویق بیندازی.

 

packageInstaller.commitSessionAfterInstallConstraintsAreMet(
    sessionId,
    intentSender,
    constraints,
    timeout = Duration.ofHours(1).toMillis()
)

اکنون، قبل از نصب چندین APK از طریق PackageSession API، می تونی از کاربر اجازه انجام این کار رو دریافت کنی. باید متد جدید () requestUserPreapproval رو فراخوانی کنی. این بهت امکان می ده بدون نیاز به دریافت مکرر مجوز برای نصب APK های جداگانه، به راحتی با App Bundle کار کنی. بنابراین، به‌روزرسانی های فروشگاه برای چندین برنامه به تأیید یک کاربر نیاز دارد.

val sessionId: Int = packageInstaller.createSession(
    PackageInstaller.SessionParams(SessionParams.MODE_INHERIT_EXISTING)
)
val pendingIntent: PendingIntent = // ...

val session: Session = packageInstaller.openSession(sessionId)
// Call the system dialog to request permission from the user
// intentSender determines where the result will be sent
session.requestUserPreapproval(
    PreapprovalDetails.Builder()
        .setIcon(iconBitmap)
        .setLabel(message)
        .setLocale(locale)
        .build(),
    pendingIntent.intentSender
)
// Wait for the user’s permission, and then the session starts
session.commit(intentSender)

برای محافظت از کاربر در برابر به روزرسانی برنامه ها از یک فروشگاه ناشناخته، متد setRequestUpdateOwnership() در PackageInstaller API معرفی شده. لازمه کاربر تایید کنه که واقعا می خواد برنامۀ نصب کننده رو تغییر بده. این معمولا زمانی اتفاق میوفته که برنامه هایی رو از یک برنامه نصب می کنی، مثلاً Google Play، اما سعی می کنی آنها رو از فروشگاه برنامه دیگری بروزرسانی کنی.

اندروید 14

اخطار هنگام بروزرسانی یک برنامه

هنگامی که کاربر می کوشه یک برنامه رو از یک نصب کننده دیگر به روز کنه، یک دیالوگ با یک هشدار می بینه که معمولا برنامه باید از منبع دیگری به روز بشه. کاربر باید به روزرسانی رو تأیید کنه.

تشخیص اسکرین شات در اندروید 14

برای شناسایی اسکرین شات ها در اندروید 14، یک API ویژه در Activity پدیدار می شه. پس از گرفتن اسکرین شات، Callback رو فراخوانی می کنه. API فقط می تونه اسکرین شات هایی رو که توسط کاربر روی دستگاه گرفته شده است، با استفاده از یک کلید ترکیبی ویژه(مثلا فرشدن همزمان دکمه پایین صفحه و دکمۀ خاموش) تشخیص بده.

اگر اسکرین شات از صفحه در حین تست با استفاده از دستورات خاص یا از طریق ADB گرفته شه، Callback کار نخواهد کرد. برای اینکه API کار کنه، باید مجوز DETECT_SCREEN_CAPTURE رو به AndroidManifest بیفزونی. سپس یک callback در onStart() ثبت کن و به یاد نره که آن رو در onStop() حذف کنی. اگر نه، می تونی از Jetpack Lifecycle استفاده کنی.

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <uses-permission android:name="android.permission.DETECT_SCREEN_CAPTURE" />
</manifest>
class MainActivity : Activity() {

    private val mainExecutor = MainEcxector()
    
    private val screenshotCallback = ScreenCaptureCallback {
        // A screenshot was taken
    }

    override fun onStart() {
        super.onStart()
        registerScreenCaptureCallback(mainExecutor, screenshotCallback)
    }

    override fun onStop() {
        super.onStop()
        unregisterScreenCaptureCallback(screenshotCallback)
    }
}

مجوز جداگانه برای نمایش اعلان های سیستمی تمام صفحه در اندروید 14

اعلان تمام صفحه یک ساعت زنگ دار

اعلان تمام صفحه یک ساعت زنگ دار

اندروید 11 نوتیفیکیشن های تمام صفحه رو معرفی کرد که در صفحه قفل و هنگام اجرای برنامه های تمام صفحه قابل مشاهده خواهند بود. این قالب برای نشان دادن اعلان های مهمی مانند تماس های دریافتی و هشدار ها (Alarms) در نظر گرفته شده بود.

با شروع اندروید 14، فقط برنامه هایی که برای آن ها در نظر گرفته شده است می تونن مجوز USE_FULL_SCREEN_INTENT موجود رو دریافت کنن. Google Play هنگام نظارت بر ساخت برنامه ها بر این قضیه نظارت می کنه.

همچنین مهمه که یادت باشه که کاربر همیشه می تونه مجوز رو لغو کنه، بنابراین پیش از نمایش یک اعلان تمام صفحه، مهمه که با فراخوانی NotificationManager.canUseFullScreenIntent () در دسترس بودن این ویژگی رو بررسی کنی.  برای درخواست از کاربر برای اعطای این مجوز، می تونی از یک Intent جدید با ACTION_MANAGE_APP_USE_FULL_SCREEN_INTENT استفاده کنید، که صفحه ای رو باز می کنه که در آن کاربر می تونه مجوز رو اعطا کنه.

val intent = Intent(Settings.ACTION_MANAGE_APP_USE_FULL_SCREEN_INTENT)
try {
     context.startActivity(intent)
} catch (e: ActivityNotFoundException) {
     // Activity cannot be started
}

ایمنی داده از Google Play در سیستم اندروید 14

در سال 2023، گوگل پلی تکمیل اطلاعات مربوط به اطمینان از امنیت داده هایی که برنامه با آنها کار می کنه رو اجباری کرد. اکنون این اطلاعات نه تنها در صفحه برنامه موجود در فروشگاه بلکه در سیستم نیز قابل مشاهده خواهد بود.

در اندروید 14، هنگامی که برنامه ات دسترسی به موقعیت مکانی کاربر در سیستم دیالوگ درخواست مجوز می کنه، کاربر می‌تونه ببینه چرا برنامه باید به موقعیت مکانی اش دسترسی داشته باشه و این داده ها با چه کسانی به اشتراک گذاشته می شن. این بخش فقط در صورتی نمایش داده می شه که برنامه موقعیت مکانی رو با خدمات شخص ثالث به اشتراک بگذاره.

ایمنی داده ها در اندروید 14

ایمنی داده ها در اندروید 14

اگر برنامه اشتراک گذاری موقعیت مکانی کاربر رو با سرویس های دیگه تغییر بده، کاربر یک اخطار ماهانه درباره این تغییرات دریافت می کنه. پس از باز شدن، کاربر بخش Update Location Sharing رو با فهرستی از همه برنامه هایی که قوانین مربوطه را تغییر داده اند مشاهده می کنه.

اطلاعیه تغییر ایمنی داده در اندروید 14

اطلاعیه تغییر ایمنی داده در اندروید 14

این تغییر به منظور شفاف سازی اشتراک گذاری داده ها برای کاربران هست. برنامه ها دیگه نمی توانن قوانین رو بدون توجه کاربر تغییر بدن. دریافت چنین اعلان هایی نه تنها در مورد مکان، بلکه در مورد انواع دیگر داده ها نیز عالی خواهد بود.

Foreground Service سامسونگ

یک تغییر کوچک اما مهم – گوگل شروع به کار فعالانه با فروشندگان برای استانداردسازی رفتار برنامه ها در background در سیستم عامل های مبتنی بر اندروید از تولید کنندگان مختلف کرده است. سامسونگ پیشتر اعلام کرده است که One UI 6.0 مبتنی بر اندروید 14 تضمین می کنه که Foreground Service مطابق با مستندات و خط مشی جدید کار کنه. در حال حاضر، فقط می توانیم امیدوار باشیم که این ها فقط واژه های تو خالی نباشن و وضعیت به سمت بهتر شدن تغییر کنه.

تغییرات زیادی در اندروید 14 ایجاد شده است، اما برخی از آنها کوچک هستن و بر تعداد کمی تاثیر خواهند گذاشت، بنابراین به سرعت آن ها رو مرور می کنیم.

این مقاله به مرور آپدیت خواهد شد.

دیدگاه‌ها ۰
ارسال دیدگاه جدید