Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android PackageInstaller not installing APK

Hello StackOverflow users,

i have an Android app outside of the Play Store. It updates itself by downloading a new APK and invoking the installer dialog using an Intent. The update functionality does not work anymore on Android 10.

I need to use the PackageInstaller API on Android 10 now, but i can't get it to work. My app is not a device or profile owner, but since i don't want a silent install so i think it should be fine.

My problem is that as soon as i commit the session absolutely nothing happens.

PackageInstaller installer = activity.PackageManager.PackageInstaller;
PackageInstaller.SessionParams sessionParams = new PackageInstaller.SessionParams(PackageInstallMode.FullInstall);
int sessionId = installer.CreateSession(sessionParams);
PackageInstaller.Session session = installer.OpenSession(sessionId);

var input = new FileStream(pfad, FileMode.Open, FileAccess.Read);
var packageInSession = session.OpenWrite("package", 0, -1);
input.CopyTo(packageInSession);
packageInSession.Close();
input.Close();

//That this is necessary could be a Xamarin bug.
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();

Intent intent = new Intent(activity, activity.Class);
intent.SetAction("com.example.android.apis.content.SESSION_API_PACKAGE_INSTALLED");
PendingIntent pendingIntent = PendingIntent.GetActivity(activity, 0, intent, 0);
IntentSender statusReceiver = pendingIntent.IntentSender;

// Commit the session (this will start the installation workflow).
session.Commit(statusReceiver);

I took a look at the DDMS and got nothing relevant out of it. One thing that might be of interest is that when i Dispose() the streams, i get an IOException: write failed (EBADF) bad file descriptor which would indicate a bad APK. But i doubt it's that because i can install the APK using a file manager without a hitch. Googling the error didn't lead me anywhere.

How can i fix this problem?

like image 926
AlphaNERD Avatar asked Jan 10 '20 16:01

AlphaNERD


People also ask

Why is my APK Download not installing?

Why APK won't install on Android? First, make sure that your Android version supports the APK version you want to install. Also, remove the Play Store version of the app before installing an APK. Don't forget to check the storage space and permission to install apps from unknown sources.

Why my package installer is not working?

If not already done: Settings -> Apps -> All -> Package Installer Clear Cache & Data, Force Stop, reboot. If this doesn't work repeat, but reboot into recovery and wipe the cache partition. Still having issues try AppInstaller.

What does it mean that com Google Android PackageInstaller?

packageinstaller is the package name of a pre-installed system app on the Android OS called Package Installer. For reference, Google Chrome's package name is com. android. chrome. Package Installer is the service that runs in the background when you install, update, or uninstall apps on your Android device.

How do I enable package installer?

Samsung devices On your device, tap Settings > Apps. Tap Special access > Install unknown apps. Tap the browser from where you will download the APK, such as Chrome. If prompted, toggle Allow from this source on.


1 Answers

There are a couple of things you need to make sure in order for the apk installation to succeed in Android Q:

  • Do not use using statements or try to dispose anything inside the AddApkToInstallSession method. The Dispose causes the installation to fail. Use try/finally and close instead:

private static void AddApkToInstallSession(Context context, Android.Net.Uri apkUri, PackageInstaller.Session session)
{
  var packageInSession = session.OpenWrite("package", 0, -1);
  var input = context.ContentResolver.OpenInputStream(apkUri);

  try
  {
      if (input != null)
      {
          input.CopyTo(packageInSession);
      }
      else
      {
          throw new Exception("Inputstream is null");
      }
  }
  finally
  {
      packageInSession.Close();
      input.Close();
  }

  //That this is necessary could be a Xamarin bug.
  GC.Collect();
  GC.WaitForPendingFinalizers();
  GC.Collect();
}
  • You must override the "OnNewIntent" method because you need an intent to confirm the installation of the APK file:

protected override void OnNewIntent(Intent intent)
{
    Bundle extras = intent.Extras;
    if (PACKAGE_INSTALLED_ACTION.Equals(intent.Action))
    {
        var status = extras.GetInt(PackageInstaller.ExtraStatus);
        var message = extras.GetString(PackageInstaller.ExtraStatusMessage);
        switch (status)
        {
            case (int)PackageInstallStatus.PendingUserAction:
                // Ask user to confirm the installation
                var confirmIntent = (Intent)extras.Get(Intent.ExtraIntent);
                StartActivity(confirmIntent);
                break;
            case (int)PackageInstallStatus.Success:
                //TODO: Handle success
                break;
            case (int)PackageInstallStatus.Failure:
            case (int)PackageInstallStatus.FailureAborted:
            case (int)PackageInstallStatus.FailureBlocked:
            case (int)PackageInstallStatus.FailureConflict:
            case (int)PackageInstallStatus.FailureIncompatible:
            case (int)PackageInstallStatus.FailureInvalid:
            case (int)PackageInstallStatus.FailureStorage:
                //TODO: Handle failures
                break;
        }
    }
}
  • The Activity where you override the "OnNewIntent" method must have LaunchMode set to LaunchMode.SingleTop
  • The user must have given the application from which you try to install the APK file the necessary permissions to install APK's. You can check if this is the case by calling PackageManager.CanRequestPackageInstalls(). If this function returns false, you can open the application options window by using this code:
StartActivity(new Intent(
            Android.Provider.Settings.ActionManageUnknownAppSources,
            Android.Net.Uri.Parse("package:" + Android.App.Application.Context.PackageName)));

so the user can easily set the switch to enable this.

  • This is my main method to initialize the APK installation:

public void InstallPackageAndroidQAndAbove(Android.Net.Uri apkUri)
{
    var packageInstaller = PackageManager.PackageInstaller;
    var sessionParams = new PackageInstaller.SessionParams(PackageInstallMode.FullInstall);
    int sessionId = packageInstaller.CreateSession(sessionParams);
    var session = packageInstaller.OpenSession(sessionId);

    AddApkToInstallSession(apkUri, session);

    // Create an install status receiver.
    var intent = new Intent(this, this.Class);
    intent.SetAction(PACKAGE_INSTALLED_ACTION);
    var pendingIntent = PendingIntent.GetActivity(this, 0, intent, 0);
    var statusReceiver = pendingIntent.IntentSender;

    // Commit the session (this will start the installation workflow).
    session.Commit(statusReceiver);
}
  • If you are debugging on a Xiaomi device, you must disable MIUI Optimizations under developer options. Otherwise the installation will fail with permission denied error.
like image 189
breez Avatar answered Sep 27 '22 19:09

breez