Things to Keep in Mind When Migrating Your App to Android 13

Migrating Your App to Android 13

The new Android release is out, and it’s time to upgrade your app! Android 13 doesn’t introduce as many breaking changes as was the case with some previous releases. We can say that Google’s main focus was once again privacy and the most impactful change is related to notifications. 

Your app should work as expected out of the box (for the most part), but Android 13 provides a couple of new features to enhance it. In this article, we will focus on some of them.

The first step in this journey is to set up the Android 13 SDK. In your build.gradle.kts or build.gradle file set your compileSdk (compileSdkVersion) and targetSdk (targetSdkVersion) to 33.

Keeping up with permissions

The latest release brings some changes to permissions.

If your app needs to manage a device’s connections to nearby access points over Wi-Fi and you don’t need to derive physical location information from the Wi-Fi APIs you should add the NEARBY_WIFI_DEVICES permission to Manifest. This permission is like the NEARBY_DEVICES permission (for Bluetooth) introduced in Android 12. Keep using ACCESS_FINE_LOCATION if you need to derive the device location.

READ_EXTERNAL_STORAGE is replaced by a more specific permission on Android 13. The type of media you want to read dictates which permissions you should request (ex. READ_MEDIA_IMAGES, READ_MEDIA_VIDEO, READ_MEDIA_AUDIO). If your app was previously granted the READ_EXTERNAL_STORAGE permission, the system will auto-grant each new permission to your app. One less thing to worry about.

Manifest changes to migrate:

	
	<manifest ...>
     <!-- Required only if your app targets Android 13. -->
     <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
     <uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
     <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />

     <!-- Required to maintain app compatibility. -->
     <uses-permission
         android:name="android.permission.READ_EXTERNAL_STORAGE"
         android:maxSdkVersion="32" />
    <application ...>
    ...
    </application>
</manifest>

Another thing to note: starting with Android 13, your app can also revoke runtime permissions. This is Google’s way of allowing developers to adhere to best practices for permissions. Check the official documentation for more information.

Permission to notify

The biggest change to permissions is the introduction of runtime permission for notifications: POST_NOTIFICATIONS. This means that apps require users to opt-in to notifications as with iOS. Just note that notifications related to media sessions are exempt from these changes in permissions.

Android 13 notifications

Notification permission prompt

Android 13 will handle notifications differently depending on the app target API and whether the app was just installed or available from before.

Newly installed apps

Notifications are off by default. Your app has to be given permission to post notifications by the user.

  • Target API level 33: the app fully controls when to show the permission dialog
  • Target API level 32 or lower: the system will show the permission dialog when the app creates its first notification channel

Existing apps on devices upgraded to Android 13

The system automatically pre-grants the new notification permission to all eligible apps when the user upgrades their device to Android 13. Users won’t see the permission dialog and notifications will be sent. Eligible apps have an existing notification channel and do not have their notifications explicitly disabled by the user.

The official documentation recommends requesting permission in context. Meaning it’s clear what the notifications are used for and why the user should opt in.

Notification permission on Android 13

Google’s example of requesting permission in context

Without modifying your app’s flows too much, we could ask users for notification permission after they finish onboarding, land on the home screen for the first time, or something similar. It’s useful to know you can always check if notifications are enabled by invoking the areNotificationsEnabled() method from NotificationManager.

Back navigation

If you are using OnBackPressed(), you might notice that it is deprecated in API 33. The TLDR; answer is to use OnBackInvokedCallback or androidx.activity.OnBackPressedCallback to handle back navigation instead.

What’s interesting is that from Android 13 the system will provide a predictive back gesture. It will show users they are about to navigate back to the launcher from the application with a swipe-back action.

Your application should tell the system if it uses the swipe-back gesture or not. This feature is currently experimental, explore it if you want to future-proof your app.

There are two cases to consider when implementing a predictive back gesture.

If you don’t want to intercept the back gesture, follow these steps:

1

Add the dependency "androidx.activity:activity:1.6.0-alpha05" (or newer) to build.gradle

2

Add android:enableOnBackInvokedCallback="true" under <application> tag in manifest

3

Enable Predictive back animations in the system’s developer options (for Android 13 this feature is still experimental but Google will expand upon it in future releases)

When using the gesture, you should be navigated back to the launcher if you followed the steps above.

On the other hand, if you want to intercept the back gesture:

1

Repeat the steps from the previous case

2

Register a callback that implements OnBackInvokedCallback

If you register the mentioned callback, the system will not perform any of the predictive back gesture animations. You shouldn’t be navigated to the launcher every time.

Check out the documentation for more info.

Poluglōttos

If you are confused about this heading, don’t be. Poluglōttos is a greek word from which the word polyglot is derived. If your app is polyglot i.e., supports many languages, then you might want to give users the option to switch their in-app language. 

You might be familiar with this problem because switching the language dynamically inside the app isn’t easy. Google it if you’re not. Solutions like Localian make language switching easier.

Android 13 App Language

System’s language options PER APP

But life could still be easier. That is why Android 13 is introducing per-app language preferences.

If your app implements the new per-app language preferences, then users can select the app’s language inside the system settings. What’s more, Android now provides APIs that make implementing an in-app language picker much easier and remove a lot of boilerplate code. LocaleManager is the class that contains new APIs. But to provide backward compatibility with older versions of Android, we will show the implementation using the Appcompat library (1.6.0-beta01 or higher).

Implement android:localeConfig in Manifest to add supported languages to phone settings.

	
	<manifest>
    ...
    <application
        ...
        android:localeConfig="@xml/locales_config"
    >
    </application>
</manifest>

Example of a local configuration file:

	
	<?xml version="1.0" encoding="utf-8"?>
<locale-config xmlns:android="http://schemas.android.com/apk/res/android">
  <locale android:name="en"/>
  <locale android:name="hr"/>
  <locale android:name="de"/>
</locale-config>

How to set a user’s preferred language (assuming the user picked Croatian):

	
	val appLocale: LocaleListCompat = LocaleListCompat.forLanguageTags("hr")
AppCompatDelegate.setApplicationLocales(appLocale)

Be aware, invoking setApplicationLocales() recreates your Activity.

Additionally, you need to make one more change to Manifest to support Android 12 or lower:

	
	<application
  ...
  <service
    android:name="androidx.appcompat.app.AppLocalesMetadataHolderService"
    android:enabled="false"
    android:exported="false">
    <meta-data
      android:name="autoStoreLocales"
      android:value="true" />
  </service>
  ...
</application>

And that’s it, switching languages should work now. For more information please check the official documentation.

Photo picker I choose you

Andorid 13 Photo picker

PHoto picker in action

A great new addition to Android 13 is the Photo picker. Even though the name suggests this great new feature is just for picking photos, the Photo picker can also allow a user to pick videos from their media library.

Without going into details, here is a simple example for launching a Photo picker (to pick a single photo) and how to handle the result. For more details and examples be sure to check out the official documentation.

Launch photo picker (user can select one photo):

	
	private val pickMedia = registerForActivityResult( 
    ActivityResultContracts.PickVisualMedia() 
) { uri -> 
        // handle result
} 

private fun choosePhotoFromGallery() = pickMedia.launch( 
    PickVisualMediaRequest( 
      ActivityResultContracts.PickVisualMedia.ImageOnly 
    )
) 

A new photo picker is available on apps targeting Android 13. But upcoming Google Play system updates will add photo picker support for apps that target Android 11 (API level 30) or higher.

Lucky 13

In the last couple of Android releases Google has been focused on permissions and user privacy and Android 13 continues this trend. In addition, a new version of the OS brings a couple of new features that will make the lives of users (and developers!) easier. To see if 13 is your lucky number grab a nearby Pixel phone or emulator and get your app ready.

Portions of this page are reproduced from work created and shared by the Android Open Source Project and used according to terms described in the Creative Commons 2.5 Attribution License.