Автономный источник : https://github.com/kwende/PackageInstallerExample
Проверено на : пиксель 2 P ie 9.0, эмулятор API 28
У нас есть одноцелевые Android устройства (единственной причиной которых является запуск одного приложения) в полевых условиях. Чтобы улучшить пользовательский опыт, мы ищем тихое обновление приложения. Насколько я понимаю, для этого нам нужно работать как приложение «Владелец устройства», а затем использовать класс PackageInstaller. Однако, несмотря на то, что я следовал нескольким постам, которые я нашел в Интернете (как на SO, так и в других местах), я не смог получить класс PackageInstaller для установки моего пользовательского APK или любого другого случайного APK, который я пробовал. Я ищу совет.
Чтобы пройтись по исходному коду, сначала у меня есть основной MainActivity здесь . Соответствующий источник выглядит следующим образом:
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 здесь . Опять же, код, наиболее интересный для этого обсуждения, следующий:
// 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 и это ), кажется, указывает мне, что это в основном то, что требуется, тогда, чтобы тихо установить APK. Однако это не удается. Я знаю, что происходит сбой, потому что 1) ничего не устанавливается и 2) приемник вещания, который я настроил для получения уведомлений о статусе установки, всегда указывает на сбой (код здесь ). Опять же, ради потомков, код, на который я обращаю особое внимание, таков (и я считаю, что он не работает, потому что 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 не повреждены.
Есть мысли? Любой совет? Спасибо.