AuthonAuthon Blog
tutorial6 min read

How to Handle Android's New 24-Hour Sideloading Delay in Your APK Distribution

Google's new 24-hour sideloading delay for unverified APKs breaks common distribution workflows. Here's how to fix your pipeline.

AW
Alan West
Authon Team
How to Handle Android's New 24-Hour Sideloading Delay in Your APK Distribution

If you distribute Android apps outside the Play Store — whether that's internal enterprise tools, beta builds, or open-source projects on F-Droid — you're about to hit a new speed bump. Google is rolling out a 24-hour waiting period before users can install unverified APKs. And if you're not prepared, your users are going to flood your issue tracker.

Let me walk through what's actually changing, why it breaks common workflows, and how to adapt your distribution pipeline.

What's Actually Happening

Google's tightening the screws on sideloading. When a user tries to install an APK that hasn't been verified through Play Protect, Android will now enforce a 24-hour cooling-off period. The user downloads your APK, tries to install it, and gets told to come back tomorrow.

The intent is obvious: slow down social engineering attacks where someone gets tricked into installing a malicious APK immediately. The friction is the feature. But for legitimate developers distributing outside the Play Store, it creates real problems.

The key technical detail: this affects apps installed via the ACTION_INSTALL_PACKAGE intent when the source app doesn't hold the REQUEST_INSTALL_PACKAGES permission properly, or when the APK itself hasn't been submitted for Play Protect verification.

Why This Breaks Your Current Workflow

Here's where I've seen teams get bitten. If you're doing any of these, you need to pay attention:

  • CI/CD pipelines that push APKs to testers — your QA team can't install the latest build immediately
  • Enterprise MDM solutions using direct APK installs — employees get blocked on internal tools
  • Open-source projects distributing via GitHub Releases — contributors can't quickly test patches
  • Self-hosted update mechanisms — your in-app updater now has a 24-hour gap

The root cause isn't that sideloading is being removed. It's that the package installer now checks verification status before allowing the install to proceed, and unverified packages get queued.

Step-by-Step: Adapting Your Distribution

Option 1: Submit Your APK for Play Protect Verification

This is the most straightforward fix. You don't need to publish on the Play Store. You can submit your APK hash for verification through the Play Integrity API.

kotlin
// In your distribution server or CI pipeline,
// submit the APK for verification before distributing
val apkHash = calculateSha256(apkFile)

// Use the Play Integrity API to pre-register your APK
// This tells Play Protect "this is a known, legitimate app"
val verificationRequest = VerificationRequest.builder()
    .setPackageName("com.yourapp.package")
    .setApkDigest(apkHash)
    .setCertificateDigest(signingCertHash)  // your signing key fingerprint
    .build()

The catch: verification isn't instant. You'll want to bake this into your CI pipeline so it happens as part of your release process, not as an afterthought.

Option 2: Use ADB for Development and Testing

If you're distributing to developers and testers with USB debugging enabled, adb install bypasses this restriction entirely. The 24-hour wait only applies to user-initiated installs through the package manager UI.

bash
#!/bin/bash
# deploy-to-testers.sh
# Push latest debug build to all connected devices

APK_PATH="./app/build/outputs/apk/debug/app-debug.apk"

# List all connected devices and install
adb devices | tail -n +2 | cut -f1 | while read -r device; do
    if [ -n "$device" ]; then
        echo "Installing on $device..."
        adb -s "$device" install -r "$APK_PATH"
    fi
done

echo "Done. No 24-hour wait needed via ADB."

This obviously doesn't scale for end-user distribution, but it solves the QA and developer testing pain.

Option 3: Use a Managed Distribution Channel

For enterprise deployments, Android's managed device provisioning through device owner or profile owner mode lets you install apps without the sideloading restriction. If you're already using an MDM solution, make sure your device policy controller has the right permissions.

kotlin
// DeviceAdminReceiver — ensure your DPC can install packages silently
class MyDeviceAdmin : DeviceAdminReceiver() {
    
    fun installPackageSilently(context: Context, apkUri: Uri) {
        val dpm = context.getSystemService(Context.DEVICE_POLICY_SERVICE) 
            as DevicePolicyManager
        val componentName = ComponentName(context, MyDeviceAdmin::class.java)
        
        // Device owner can install without user interaction
        // and without the 24-hour sideloading delay
        val session = context.packageManager.packageInstaller
            .openSession(
                context.packageManager.packageInstaller
                    .createSession(SessionParams(SessionParams.MODE_FULL_INSTALL))
            )
        
        // Write APK to session
        apkUri.let { uri ->
            context.contentResolver.openInputStream(uri)?.use { input ->
                session.openWrite("app", 0, -1).use { output ->
                    input.copyTo(output)
                    session.fsync(output)
                }
            }
        }
        
        // Commit — this bypasses the 24-hour wait for managed devices
        val intent = PendingIntent.getBroadcast(
            context, 0,
            Intent("com.yourapp.INSTALL_COMPLETE"),
            PendingIntent.FLAG_IMMUTABLE
        )
        session.commit(intent.intentSender)
    }
}

Option 4: Adjust Your Self-Update Mechanism

If your app has a self-update feature, you need to handle the new delay gracefully. Don't just throw an error when the install gets deferred.

kotlin
// Handle the deferred installation state in your update UI
fun handleInstallStatus(status: Int) {
    when (status) {
        PackageInstaller.STATUS_PENDING_USER_ACTION -> {
            // User needs to confirm — standard flow
            showUpdatePrompt()
        }
        PackageInstaller.STATUS_FAILURE -> {
            // Check if this is the new 24-hour deferral
            // The system will return a specific status code
            showDeferralNotice(
                "Update downloaded. Android requires a short wait " +
                "before installing apps from outside the app store. " +
                "You'll get a notification when it's ready."
            )
            // Schedule a notification for when the wait expires
            scheduleInstallReminder(hours = 24)
        }
    }
}

The key here is UX. Don't leave users confused about why they can't install your update. Explain the wait clearly.

Prevention: Build This Into Your Pipeline Now

Here's what I'd recommend doing before this hits your users:

  • Audit your install flow. Actually walk through installing your APK on a device running the latest Android beta. See what happens.
  • Add APK verification to CI. If you're distributing APKs publicly, pre-register them. The verification step is cheap and saves your users the wait.
  • Update your install instructions. If you have a README or docs that say "download and install the APK," add a note about the potential delay.
  • Handle the deferral in code. If your app has any kind of self-update or plugin install mechanism, add graceful handling for the deferred state. Don't let it crash or show a cryptic error.
  • Consider your signing setup. Consistent signing keys help Play Protect build trust for your package name over time. If you're rotating keys frequently or using different keys for different build variants, that can work against you.

The Bigger Picture

Look, I get why Google is doing this. The vast majority of malware on Android comes through sideloaded APKs, and a 24-hour cooling-off period probably does prevent impulsive installs from phishing campaigns. That's a real security win for regular users.

But for developers, it's another case where we're paying the tax for bad actors. The good news is that the workarounds are straightforward — you just need to know about them before your users start complaining.

The real lesson here: if you're distributing outside the Play Store, treat your distribution pipeline as a first-class engineering concern. It's not just "upload a file somewhere." It's signing, verification, update handling, and now timing. Build it properly and these platform changes become a config tweak instead of a fire drill.