我的 Android 活动/应用程序正在使用 DownloadManager 和 PackageInstaller 进行自我更新。我将在此处发布相关代码,但底线是文件下载成功但未安装,并且 LogCat 中没有有用的信息来帮助我找出原因。
如果我的代码有问题,我很想知道,但据我所知,我正在按照示例所说的方式做事。我已经尝试过设置和不设置 DeviceOwner,并且无论哪种方式都可以看到相同的行为。什么都没有发生,LogCat 中也没有任何内容表明出了什么问题。
我尝试连接会话回调方法,但我无法获得任何信息,因为我的 'sessionInfo' 始终为 NULL。这怎么可能呢?
pkgInstaller.registerSessionCallback(new PackageInstaller.SessionCallback() {
PackageInstaller.SessionInfo sessionInfo = pkgInstaller.getSessionInfo(sID);
}
下载部分已成功运行,因此我将在此处显示相关行。
File downloadFile = new File(getExternalFilesDir(null),"myapp-update.apk");
该 apk 是在 Android Studio 中使用“Build -> Build Bundle(s) -> APK(s) -> Build APK(s)”构建的,它会输出一个“调试”APK(就像我构建和部署到IDE 中的设备)。它是使用较新的 VersionID 和 VersionName 构建的,然后上传到我的文件服务器。我的 Android 应用程序使用 DownloadManager 下载它,并且它正在运行。
这是下载 APK 后发生的情况。
private BroadcastReceiver onDownloadComplete = new BroadcastReceiver()
{
@Override
public void onReceive(Context context, Intent intent)
{
// Get our download record, verify it, etc.
// ......
// Get URI of downloaded file
int uriIndex = cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI);
String apkStr = cursor.getString(uriIndex);
// Install APK update
Uri apkUri = Uri.parse(apkStr);
installApk(Objects.requireNonNull(apkUri.getPath()));
}
}
这是下载后安装APK的方法。
public static final String ACTION_INSTALL_COMPLETE = BuildConfig.APPLICATION_ID + ".INSTALL_COMPLETE";
private void installApk(String apkFilePath)
{
try
{
// Create package manager installation params
PackageInstaller pkgInstaller = getBaseContext().getPackageManager().getPackageInstaller();
PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL);
params.setAppPackageName(this.getPackageName());
// Create package manager installation session
int sessionId = pkgInstaller.createSession(params);
PackageInstaller.Session session = pkgInstaller.openSession(sessionId);
// Get size of downloaded APK
long sizeBytes = 0;
final File file = new File(apkFilePath);
if (file.isFile())
sizeBytes = file.length();
// Stream downloaded APK file to package manager session
InputStream in = new FileInputStream(apkFilePath);
OutputStream out = session.openWrite("konektv_update_session", 0, -1);
byte[] buffer = new byte[65536];
int bytesRead = in.read(buffer);
while (bytesRead != -1)
{
out.write(buffer, 0, bytesRead);
bytesRead = in.read(buffer);
}
// Close streams
session.fsync(out);
out.close();
in.close();
// Close session
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, sessionId, new Intent(ACTION_INSTALL_COMPLETE),0);
session.commit(pendingIntent.getIntentSender());
session.close();
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
我用于 APK 安装的自定义广播接收器如下。它永远不会被调用,也不会安装下载的 APK。我可以说是因为什么都没发生,但即使发生了,我也会显示版本号并且它不会改变。
public class UpdateReceiver extends BroadcastReceiver
{
@Override
public void onReceive(Context context, Intent intent)
{
final String LOG_TAG = "myapp-updated";
if (intent == null)
return;
String action = intent.getAction();
if ((action == null) || !action.equalsIgnoreCase(Intent.ACTION_MY_PACKAGE_REPLACED))
return;
// Start main activity
Intent intentMain = new Intent(context, MainActivity.class);
intentMain.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intentMain.putExtra(KonekTvApplication.IS_BOOT_AUTOSTART, true);
context.startActivity(intentMain);
}
}
以下是我的 AndroidManifest.xml 文件中的相关位。
<uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES" />
<application
android:testOnly="true"
android:name=".MyApplication">
<receiver
android:name=".UpdateReceiver">
<intent-filter >
<action android:name="android.intent.action.MY_PACKAGE_REPLACED"/>
</intent-filter>
</receiver>
唯一的其他代码与 DeviceOwner 相关,但无论设备所有者如何,这种方法都应该有效。唯一的区别是更新是静默更新还是需要用户交互。
public class DeviceOwnerReceiver extends DeviceAdminReceiver
{
private static final String LOG_TAG = "my-owner-receiver";
@Override
public void onEnabled(Context context, Intent intent) {
Log.w(LOG_TAG,"Device owner enabled");
}
public static ComponentName getComponentName(Context context) {
return new ComponentName(context.getApplicationContext(), DeviceOwnerReceiver.class);
}
}
这是来自 AndroidManifest.xml 的设备所有者资料。
<receiver
android:name=".DeviceOwnerReceiver"
android:label="@string/app_name"
android:permission="android.permission.BIND_DEVICE_ADMIN">
<meta-data
android:name="android.app.device_admin"
android:resource="@xml/device_admin" />
<intent-filter>
<action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
</intent-filter>
</receiver>
这是 device_admin.xml 文件。
<?xml version="1.0" encoding="utf-8"?>
<device-admin xmlns:android="http://schemas.android.com/apk/res/android">
<uses-policies>
</uses-policies>
</device-admin>
非常感谢您提供的任何帮助。