为什么PackageInstaller无法安装软件包?

时间:2020-02-28 17:13:13

标签: android xamarin xamarin.forms xamarin.android

自包含源https://github.com/kwende/PackageInstallerExample

经过测试:Pixel 2 Pie 9.0,API 28仿真器

我们在现场有单一用途的Android设备(其唯一原因是运行一个应用程序)。为了改善用户体验,我们正在研究静默更新该应用程序。据我了解,为此,我们需要以“设备所有者”应用程序运行,然后使用PackageInstaller类。但是,尽管遵循了我在网上找到的几篇文章(无论是在SO还是其他地方)的指导,但是我仍然无法获得PackageInstaller类来安装我的自定义APK或我尝试过的任何随机APK。我正在寻找建议。

要遍历源代码,首先,我有MainMainActivity here。相关来源如下:

    protected override void OnCreate(Bundle savedInstanceState)
    {
        // Looks like permissions to read and write external storage must be explicit. 
        //https://stackoverflow.com/questions/31746787/xamarin-android-system-unauthorizedaccessexception-access-to-the-path-is-de
        if (ContextCompat.CheckSelfPermission(this, Manifest.Permission.WriteExternalStorage) != (int)Permission.Granted)
        {
            ActivityCompat.RequestPermissions(this, new string[] { Manifest.Permission.WriteExternalStorage }, 0);
        }

        if (ContextCompat.CheckSelfPermission(this, Manifest.Permission.ReadExternalStorage) != (int)Permission.Granted)
        {
            ActivityCompat.RequestPermissions(this, new string[] { Manifest.Permission.ReadExternalStorage }, 0);
        }

       ...

        // This will prompt the user to allow/disallow the elevation of this app as "device owner". 
        DevicePolicyManager devicePolicyManager = (DevicePolicyManager)GetSystemService(Context.DevicePolicyService);
        ComponentName demoDeviceAdmin = new ComponentName(this, Java.Lang.Class.FromType(typeof(DeviceAdminBroadcastReceiver)));
        Intent intent = new Intent(DevicePolicyManager.ActionAddDeviceAdmin);
        intent.PutExtra(DevicePolicyManager.ExtraDeviceAdmin, demoDeviceAdmin);
        intent.PutExtra(DevicePolicyManager.ExtraAddExplanation, "Device administrator");
        StartActivity(intent);

        IntentFilter filter = new IntentFilter();
        filter.AddAction("ANY_UNIQUE_NAME_WILL_DO");
        RegisterReceiver(new InstallerStatusBroadcastReceiver(), filter);
    }

在此来源中,我明确地要求获得读取/写入存储的权限,并提示用户授予我的应用“设备所有者”权限,最后注册一个广播接收器以获取安装结果尝试。所有这些似乎都可以成功运行。

代码的下一个也是最重要的一部分是在MainPage.xaml.cs here中。同样,此讨论中最有趣的代码如下:

        // path to the APK to be installed. This could be something downloaded, or it could a file on the SD card. 
        const string localPath = "/storage/emulated/0/Download/.......";

        // the following code was largely inspired from 
        // here: https://github.com/nagamanojv/android-kiosk-example/blob/master/KioskExample/app/src/main/java/com/sureshjoshi/android/kioskexample/MainActivity.java. 
        // here: https://forums.xamarin.com/discussion/73589/does-anyone-try-to-install-package-with-packageinstaller-i-get-files-still-open-exception
        // here: https://forums.xamarin.com/discussion/170925/xamarin-android-10-how-to-install-3rd-party-apk

        //instantiate a package installer and its parameters.
        PackageInstaller installer = Android.App.Application.Context.PackageManager.PackageInstaller;
        PackageInstaller.SessionParams sessionParams = new PackageInstaller.SessionParams(PackageInstallMode.FullInstall);

        int sessionId = installer.CreateSession(sessionParams);
        PackageInstaller.Session session = installer.OpenSession(sessionId);

        using (var input = new FileStream(localPath, FileMode.Open, FileAccess.Read))
        {
            using (var packageInSession = session.OpenWrite("package", 0, -1))
            {
                input.CopyTo(packageInSession);
            }
        }

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

        PendingIntent pendingIntent = PendingIntent.GetBroadcast(Android.App.Application.Context, sessionId, new Intent("ANY_UNIQUE_NAME_WILL_DO"), 0);
        session.Commit(pendingIntent.IntentSender);

        return; 

我所见过的大量帖子和代码示例(例如thisthisthis)似乎向我表明,这主要是所需的,静默安装APK。但是,它失败了。我知道它失败了,因为1)没有安装任何东西,以及2)我已设置为接收安装状态通知的广播接收器似乎总是指示失败(代码here)。再次,为了后代,我正在查看的代码是这样的(并且我相信它会失败,因为 status 始终为-1):

        int status = intent.GetIntExtra(PackageInstaller.ExtraStatus, -1);
        string moreMessage = intent.GetStringExtra(PackageInstaller.ExtraStatusMessage);

        // error codes and whatnot pulled from //https://developer.android.com/reference/android/content/pm/PackageInstaller#STATUS_FAILURE
        switch (status)
        {
            // STATUS_FAILURE_INVALID
            case 4:
                Toast.MakeText(context, "STATUS_FAILURE_INVALID!", ToastLength.Short).Show();
                //The operation failed because one or more of the APKs was invalid. For example, they might be malformed, corrupt, incorrectly signed, mismatched, etc.
                break;
        }

        return;

我想念什么?我已为该应用授予以下权限:

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INSTALL_PACKAGES" />
<uses-permission android:name="android.permission.DELETE_PACKAGES" />
<uses-permission android:name="android.permission.GET_PACKAGE_SIZE" />
<uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<uses-permission android:name="android.permission.BROADCAST_PACKAGE_REMOVED" />

...但是尽管如此,但从未安装过APK,也没有返回任何有意义的错误代码。我还想知道我要安装的APK本身是否不好(尽管尝试了几次);当我点击安装它们时,它们都已安装(或者因为我一直在模拟器中运行而被“单击”)。因此,我必须得出结论,APK没有损坏。

有什么想法吗?有什么建议吗?非常感谢。

0 个答案:

没有答案