web-dev-qa-db-ja.com

Android PackageInstallerがAPKをインストールしない

StackOverflowユーザーの皆様

AndroidアプリはPlayストアの外にあります。新しいAPKをダウンロードし、インテントを使用してインストーラーダイアログを呼び出すことにより、アプリ自体が更新されます。更新機能は、Android 10。

Android 10でPackageInstaller APIを使用する必要がありますが、動作しません。アプリはデバイスまたはプロファイルの所有者ではありませんが、サイレントは必要ないのでインストールして大丈夫だと思います。

私の問題は、セッションをコミットしてもすぐには何も起こらないことです。

_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);
_

私はDDMSを調べましたが、関連するものは何もありませんでした。興味深いのは、ストリームをDispose()したときに、不正なAPKを示すIOException: write failed (EBADF) bad file descriptorを取得することです。しかし、それは私が問題なくファイルマネージャーを使用してAPKをインストールできるので、それは疑わしいです。エラーをグーグルすることは私をどこにも導きませんでした。

この問題を解決するにはどうすればよいですか?

2
AlphaNERD

Android Q:

  • Usingステートメントを使用したり、AddApkToInstallSessionメソッド内で何かを破棄したりしないでください。 Disposeにより、インストールが失敗します。代わりにtry/finallyを使用して閉じます。
_
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();
}
_
  • APKファイルのインストールを確認するインテントが必要なため、「OnNewIntent」メソッドをオーバーライドする必要があります。
_
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;
        }
    }
}
_
  • 「OnNewIntent」メソッドをオーバーライドするアクティビティでは、LaunchModeを_LaunchMode.SingleTop_に設定する必要があります
  • ユーザーは、APKファイルをインストールしようとするアプリケーションに、APKをインストールするために必要な権限を与えている必要があります。これが当てはまるかどうかを確認するには、PackageManager.CanRequestPackageInstalls()を呼び出します。この関数がfalseを返す場合、次のコードを使用してアプリケーションオプションウィンドウを開くことができます。
_StartActivity(new Intent(
            Android.Provider.Settings.ActionManageUnknownAppSources,
            Android.Net.Uri.Parse("package:" + Android.App.Application.Context.PackageName)));
_

これにより、ユーザーはスイッチを簡単に設定してこれを有効にできます。

  • これは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);
}
_
  • Xiaomiデバイスでデバッグする場合は、開発者向けオプションでMIUI最適化を無効にする必要があります。そうでない場合、インストールは許可拒否エラーで失敗します。
1
breez