One of the last updates of Google Play Integrity API brought a new feature that allows you to check the installation source and “block” app navigation and suggest installation from Google Play. The feature forced some discussions in the community and misunderstanding. So let’s check what’s going on.

The new feature allows you to prevent app usage and navigate to Google Play to reinstall the app from the “right” store. I got two main points from comments and discussions in the community that intrigue me:

  • Now we can protect all our apps and check that it’s official apps;
  • What if the app was installed from an alt store and we break a user experience? These statements sparked my curiosity, and I started my research.

In short: most of the misunderstanding lies in part reading from a lot of sources. We already have the oportunity to check some installation soures and react to the results. The whole blog post shared some parts of my journey, nothing more.

About Google Play Integrity API

Google Play Integrity API (docs, client sources) allows you to verify the authenticity of app interactions and the device they’re running on. It prevents unauthorized access, abuse, and attacks by checking if requests are coming from the genuine app and device.

Google Play Integrity API acts as a third-party service that provides an authoritative verification mechanism.

I highly recommend checking one of the latest videos by Android Developers and the official documentation and diagram of work documentation.

If we think about this API as a third-party service we can get these intresting and important notes:

  • if the Google Play services are outdated or not installed (like some Chinese phones or custom ROMs) your verification will be unsuccessful;
  • you need an internet connection to get proper results too, if your app works with the offline mode you need to solve it by yourself.
  • you and only you have to decide how to react to verdicts (results of checking) in your app, it’s your part of the job

Let’s check the apps check!

Let’s check the apps check! I focus on the two verdicts (result of checks):

  1. Check the appIntegrity field to verify that the user installed it from Google Play - this version exists in the store and is signed with the right certificate
  2. Check that the account has the record of the installation of the app and maybe “bought” it via Google Play payments

Both checks provide some data and you as a developer should react to them. So if you decide to show the Google Play screen it’s your logic. Consider how this aligns with your offline workflow.

These checks help you prevent some stupid and easy-to-do clone apps with repackaging or simple mods. But it requires some work from your side and an understanding of the possible risks. If you think that users don’t install strange apps - check one of the latest news about malware.

The account verdict’s state “LICENSED” is pretty tricky. You should be careful especially if your system allows subscriptions or buying from different sources (for example iOS or WEB).

Scratch the surface of installation sources

In the first drafts this section header was named “Deep dive into installation sources”. However the whole installation process is pretty complex, so I changed the header.

The installation process is complex and contains different steps. The main work does PackageManager (yep, pm from ADB request too) and PackageManagerService (links to source code related to Android 14, but as I remember the general approach was same and for Android 6 too). In general, the whole install process depends on the app that launched this process and some data recorded from the “parent” into InstallSource class. For example, if you install the app from Google Play there must be com.android.vending, for F-Droid org.fdroid.fdroid. In case when you install the app via ADB or from the android shell it can be null or com.android.shell (AOSP source check)

Based on this we can check if an app was installed from Google Play. If you search or ask LLM bots you can get a similar code snippet:

fun Context.getInstallationSource(): String? = runCatching {
    // For API levels above or equal to 30 (Android 11 and later)
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
        packageManager.getInstallSourceInfo(packageName).installingPackageName
    } else {
        // For API levels below 30
        packageManager.getInstallerPackageName(packageName)
    }
}.getOrNull()

It is not so complex, right? But there is a problem. To get this information you need permission: INSTALL_PACKAGES. That is one of the most suspicious permissions for regular apps. Google Play has it.

By the way, if you restore some apps from the backup app the install source will be that app too.

OK, we can’t check the installation source like this, maybe we can check signatures on our side and rely on it with our service API calls for example? Technically yes, it’s not hard to collect the version, version code, and signing of our apps. But what’s the next step? Send it to our API service for checking, right? Can we use some hashing to generate helpful API headers and keys? Yes, we can. But in that case, if this algorithm is exposed (it’s not so hard to do) the whole work will be useless. But it’s better than nothing and it helps you with simple attacks but requires more complex logic on the back-end.

Conclusion

Google Play Integrity API is a helpful tool that can save your company time, money, and reputation. Can we break user experience with this integration? Yep, if we don’t think about all cases, especially devices without Google Play services or offline scenarios. Is it a perfect protection? Not really, but it’s one of the easiest and universal ways to protect your service from stupid attacks.

Remember, it’s just one layer of security. You still need to implement server-side checks and be prepared for cases where the API might not be available or reliable. And always consider the user experience - don’t lock out legitimate users just because they’re using a device or method you didn’t expect.

In the end, it’s about finding the right balance between security and usability. The Google Play Integrity API gives you some great tools, but how you use them is up to you. Always think about your specific app, your users, and your security needs when implementing these checks.