简体   繁体   English

Android PackageInstaller 未安装 APK

[英]Android PackageInstaller not installing APK

Hello StackOverflow users,你好 StackOverflow 用户,

i have an Android app outside of the Play Store.我在 Play 商店之外有一个 Android 应用程序。 It updates itself by downloading a new APK and invoking the installer dialog using an Intent.它通过下载新的 APK 并使用 Intent 调用安装程序对话框来更新自身。 The update functionality does not work anymore on Android 10.更新功能不再适用于 Android 10。

I need to use the PackageInstaller API on Android 10 now, but i can't get it to work.我现在需要在 Android 10 上使用 PackageInstaller API,但我无法让它工作。 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.我查看了 DDMS,并没有从中得到任何相关信息。 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.可能感兴趣的一件事是,当我Dispose()流时,我收到IOException: write failed (EBADF) bad file descriptor ,这表明 APK 有问题。 But i doubt it's that because i can install the APK using a file manager without a hitch.但我怀疑这是因为我可以使用文件管理器顺利安装 APK。 Googling the error didn't lead me anywhere.谷歌搜索错误并没有把我带到任何地方。

How can i fix this problem?我该如何解决这个问题?

There are a couple of things you need to make sure in order for the apk installation to succeed in Android Q:为了在 Android Q 中成功安装 apk,您需要确保以下几点:

  • Do not use using statements or try to dispose anything inside the AddApkToInstallSession method.不要使用 using 语句或尝试在 AddApkToInstallSession 方法中处理任何内容。 The Dispose causes the installation to fail. Dispose 会导致安装失败。 Use try/finally and close instead:使用 try/finally 和 close 代替:

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:您必须覆盖“OnNewIntent”方法,因为您需要一个意图来确认 APK 文件的安装:

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您覆盖“OnNewIntent”方法的活动必须将 LaunchMode 设置为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.用户必须已向您尝试从中安装 APK 文件的应用程序授予安装 APK 所需的权限。 You can check if this is the case by calling PackageManager.CanRequestPackageInstalls() .您可以通过调用PackageManager.CanRequestPackageInstalls()来检查是否是这种情况。 If this function returns false, you can open the application options window by using this code:如果此函数返回 false,您可以使用以下代码打开应用程序选项窗口:
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:这是我初始化 APK 安装的主要方法:

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.如果您在小米设备上调试,则必须在开发者选项下禁用 MIUI 优化。 Otherwise the installation will fail with permission denied error.否则安装将因权限被拒绝错误而失败。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM