2

我的 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>

非常感谢您提供的任何帮助。

4

0 回答 0