自包含源: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;
我所见过的大量帖子和代码示例(例如this,this和this)似乎向我表明,这主要是所需的,静默安装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没有损坏。
有什么想法吗?有什么建议吗?非常感谢。