Migrating Apps to Android 13
With each release of Android, we introduce new features as well as behaviour changes aimed at making Android more helpful, more secure, and more performant. In many cases, your app will work exactly as expected out of the box, while in other cases you might need to update your app to adapt to the platform changes.
We planned this migration to leverage the new capabilities offered by Android 13 and we've shared our experience through this blog to highlight the journey and the pitfalls to watch for, during the migration journey.
Ensure compatibility with Android 13
It's important to test the functionality of your existing app against Android 13 to ensure a great experience for users updating to the latest version of Android. Some platform changes can affect the way your app behaves, so it's important to test early and thoroughly and make any needed adjustments to your app.
You can usually adjust your app and publish an update without needing to change the app's
targetSdkVersion. Similarly, you should not need to use new APIs or change the app's
compileSdkVersion, although this can depend on the way your app is built and the platform functionality it's using.
Before you start testing, be sure to familiarize yourself with the behaviour changes for all apps. These changes might affect your app, even if you don't change its
1. Update Target API Level:
The first step in the process of migrating your app to the new target API level is to update your
If your app already complies with the annual target API level update policy, your app is on target SDK 31 (Android 12) or even SDK 32 (Android 12 L).
To support Android 13, you just need to go to your app-level
build.gradle and set the
targetSdkVersion as well as the
compileSdkVersion to the new target SDK version
2. Read Media Permission:
The first thing we needed to adapt was the
android.permission.READ_EXTERNAL_STORAGE. By targeting Android 13, we need to declare in our manifest what kind of media we exactly want to read.
READ_EXTERNAL_STORAGE is replaced by 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).
Manifest changes to migrate:
However, to maintain backward compatibility, you also still need to declare the
READ_EXTERNAL_STORAGE but with an extra property
maxSdkVersion set to SDK level
Note that if you previously declared
android.permission.WRITE_EXTERNAL_STORAGE, this permission
is no longer needed and can be removed.
Alternative way: Use the Android 13 Photo Picker
The photo picker is a very convenient way to retrieve media files like audio, video, and images.
You can call the photo picker by using the
MediaStore.ACTION_PICK_IMAGES intent. By default, the browser which will open up doesn’t only show images but also videos.
- To declare how many items the user can select from the photo picker, you need to add the
android.provider.extra.PICK_IMAGES_MAXextra to the calling
Intentwith your respective limit.
3. Notifications runtime permission:
Targeting the new Android 13 SDK level, we can no longer show notifications to the user without asking for his permission.
To be able to ask for the respective permission, the first step is to declare the
POST_NOTIFICATIONS in your
AndroidManifest.xml as you can see in the snippet below:
Next, check out the following code that shows how you can request permission for using the
POST_NOTIFICATIONS runtime permission, using the mentioned Activity Result API.
Android 13 will handle notifications differently depending on the app target API and whether the app was just installed or available before.
Newly installed apps
Notifications are off by default. Your app has to be given permission by the user to post notifications.
- 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
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
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
4. Advertising ID:
If you are using a Google Play Advertising ID, targeting SDK 33 you need to declare the
com.google.android.gms.permission.AD_ID permission in your
AndroidManifest.xml like you can see in the code snippet below:
Even if you are not using the advertising ID directly, in case you use an advertisement SDK in your app, the respective framework might make use of it.
However, if the respective framework is up to date, you might be lucky and don’t need to declare it explicitly if the SDK itself instead does it already.
5. Other Behavior changes:
If you are using
WebViews in your app, your app color theme (light or dark mode) will automatically be passed to the calling media query.
- If supported, the websites will therefore automatically appear in the respective current color scheme of your app.
- In case you want to avoid that behaviour, you need to disable the automatic darkening by calling
If you previously relied on the restarts of the device, you will need to reconsider how you properly handle that case.
By targeting Android 13, you will no longer receive the
LOCKED_BOOT_COMPLETED broadcast events when your device is launched, but only when your app is launched as well.
- Another update regards the standby bucket. If your app is not in use for 8 days or it excessively makes use of broadcasts and or bindings it will be put into that bucket and underlies battery optimization restrictions.
- Luckily, if your app has either
CAMERApermission, it is excluded from this behaviour.
Intent Filter Restrictions
Before Android 13, if your app sent an
Intent with a specific action to an external receiver (or to be more specific, to another app), no matter if the action was declared or not, the receiving side would process it.
If your app tries to send an
Intent to an external app targeting Android 13 and no
<intent-filter> matches the sent action, the request will get blocked.
6. Other API changes:
Many APIs like the
Drawable.class received API updates and are now underlying annotated with
@NonNull. If you override any of these APIs you may need to adapt your code to match the nullability properties.
Serializable objects, you can use the
getSerializableExtra(..) function previously you needed to cast the result to the respective underlying object.
With the new SDK 33, you now add the underlying class directly to the call as an argument and can receive the nullable result of it without further conversions.
In this article, we've shared our key experiences and lessons learned from the migration process of Halodoc apps to Android 13.
Just like every year, releases a new version of its Android operating system.
We as Android developers once again have to react to the changes and adapt our apps according to the new limitations and functions to ensure the best possible user experience across all Android versions.
Comparing the releases of the last years with Android 13, the migration process this year is relatively pleasant. There are also some good new features like the Photo Picker, the Foreground Service Manager, or the security improvements with the new Intent Filter restrictions.
If you want to have a look at other changes that might affect your app, check out the official documentation on the behaviour changes regarding Android 13.
Scalability, reliability and maintainability are the three pillars that govern what we build at Halodoc Tech. We are actively looking for engineers at all levels and if solving hard problems with challenging requirements is your forte, please reach out to us with your resumé at firstname.lastname@example.org.
Halodoc is the number 1 all around Healthcare application in Indonesia. Our mission is to simplify and bring quality healthcare across Indonesia, from Sabang to Merauke. We connect 20,000+ doctors with patients in need through our Tele-consultation service. We partner with 3500+ pharmacies in 100+ cities to bring medicine to your doorstep. We've also partnered with Indonesia's largest lab provider to provide lab home services, and to top it off we have recently launched a premium appointment service that partners with 500+ hospitals that allow patients to book a doctor appointment inside our application. We are extremely fortunate to be trusted by our investors, such as the Bill & Melinda Gates Foundation, Singtel, UOB Ventures, Allianz, GoJek, Astra, Temasek and many more. We recently closed our Series C round and In total have raised around USD$180 million for our mission. Our team works tirelessly to make sure that we create the best healthcare solution personalised for all of our patient's needs, and are continuously on a path to simplify healthcare for Indonesia.