Android PackageInstaller,更新后重新打开应用程序

Posted

技术标签:

【中文标题】Android PackageInstaller,更新后重新打开应用程序【英文标题】:Android PackageInstaller, re-open the app after it updates itself 【发布时间】:2017-10-11 23:10:57 【问题描述】:

我正在开发一个以设备所有者身份运行的应用,我想在其中构建一个自动更新程序。

为此,我使用 PackageInstaller,因为由于我的设备所有者职位,我有权使用它。

private void installPackage(InputStream inputStream)
        throws IOException 
    notifyLog("Inizio aggiornamento...");
    PackageInstaller packageInstaller = context.getPackageManager().getPackageInstaller();
    int sessionId = packageInstaller.createSession(new PackageInstaller
            .SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL));
    PackageInstaller.Session session = packageInstaller.openSession(sessionId);

    long sizeBytes = 0;

    OutputStream out = null;
    out = session.openWrite("my_app_session", 0, sizeBytes);

    int total = 0;
    byte[] buffer = new byte[65536];
    int c;
    while ((c = inputStream.read(buffer)) != -1) 
        total += c;
        out.write(buffer, 0, c);
    
    session.fsync(out);
    inputStream.close();
    out.close();

    session.commit(createIntentSender(sessionId));


private IntentSender createIntentSender(int sessionId) 
    PendingIntent pendingIntent = PendingIntent.getBroadcast(
            context,
            sessionId,
            new Intent(LauncherReceiver.START_INTENT),
            0);
    return pendingIntent.getIntentSender();

更新正常,但问题是更新后它不会重新打开应用程序本身,即使我设置了一个 IntentSender 将操作LauncherReceiver.START_INTENT 广播到新的应用程序实例(这将带来它开始)。

这是我的接收器:

public class LauncherReceiver extends BroadcastReceiver 

    public static final String START_INTENT = "com.aaa.aaa.action.START";

    @Override
    public void onReceive(Context context, Intent intent) 
        System.out.println("CALL RECEIVER!!");
        Intent startIntent = new Intent(context, StartActivity.class);
        startIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TOP);
        context.startActivity(startIntent);
    

它已在我的清单中注册:

    <receiver android:name=".receivers.LauncherReceiver" android:enabled="true" android:exported="true">
        <intent-filter>
            <action android:name="com.aaa.aaa.action.START"></action>
            <category android:name="android.intent.category.DEFAULT" />
        </intent-filter>
    </receiver>

如果我通过 CLI 调用它,它可以工作:

am broadcast -a com.worldnet.gestitruck.action.START 

所以接收器工作但由于某种原因它不能从包安装程序会话提交中工作。该应用程序由于升级而自行关闭,但不会再次打开。

如果我将createIntentSender 更改为:

private IntentSender createIntentSender(int sessionId) 
    Intent intent = new Intent(Intent.ACTION_DIAL);
    intent.setData(Uri.parse("tel:0123456789"));
    PendingIntent pendingIntent = PendingIntent.getActivity(context,sessionId,intent,0);
    return pendingIntent.getIntentSender();

它实际上打开了电话服务。所以我认为问题在于升级生命周期,因为当广播动作产生时应用程序还没有准备好。

此外,我又进行了一次尝试,我创建了一个辅助应用程序,它只会调用我的主应用程序的广播操作,所以我可以调用这个辅助应用程序,并且通过这个“双步”它实际上可以重新打开刚才的更新的应用程序。问题是我必须安装两个应用程序=/

有人可以帮我吗?有没有办法重新打开刚刚更新的应用程序?

【问题讨论】:

设备所有者应用程序是实现类 DeviceAdminReceiver 的广播接收器的应用程序,安装在设备上并已通过 shell 或 NFC 运行 dpm 命令,使应用程序具有某些特殊权限在设备上。用谷歌搜索“android device owner”并检查this 是的,但是设备所有者模式授予您许多权限,包括安装应用程序无需用户确认。该应用程序不需要内置,您可以开发自己的应用程序并在您需要的设备上将其设置为设备所有者模式。当然,您需要通过 USB 或至少 NFC 物理访问设备,而 Play 商店分发不应该这样做。 (您可以阅读有关 Android Entrerprise(高级计划)的更多信息,了解有关没有设备所有者的特殊权限的更多选项)。 是的,它还允许在没有用户确认的情况下卸载。是的,只要设备所有者模式不是关键功能,并且即使没有它,应用程序也可以正常运行,您就可以在 Play 商店中发布它。在我看来,您还需要向 Google 解释为什么在审批过程中需要应用程序上的 DeviceOwner 模式。我在一分钟内找不到这里的例子,但谷歌可以找到很多例子(搜索去年的结果)。祝你好运! 我发现this codelab example 很有帮助。它旨在创建一个 COSU 应用程序,但它还包括设备所有者设置说明。 Here is a list of methods,您可以与 Device Ownerr 一起使用。 【参考方案1】:

从大约 Android 5 开始(我不知道确切的 API 级别),Android 将在您的应用更新后发送带有 ACTION="android.intent.action.MY_PACKAGE_REPLACED" 的广播 Intent。只需添加

        <intent-filter>
            <action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
        </intent-filter>

到您的&lt;receiver&gt; 声明,您应该能够在onReceive() 中收听并重新启动您的应用程序。

【讨论】:

谢谢,这行得通,我唯一需要注意的是手机上可能安装了阻止此功能的软件,我们必须处理see here 刚刚在 android P 上试了一下,没有任何问题。 我的 PendingIntent 应该如何看起来像我传递给 session.commit() 的样子?关于 API 级别,这种方法应该对我有用,但我无法让它工作。应用程序关闭,安装完成后没有任何反应。 ***.com/questions/63050850/… 该块 必须添加到清单文件中或者是 Activity 的任何类型的标头? @Windgate 正如我在答案中所说,&lt;intent-filter&gt; 需要在 &lt;receiver&gt; 声明中声明。这是BroadcastReceiver,而不是Activity

以上是关于Android PackageInstaller,更新后重新打开应用程序的主要内容,如果未能解决你的问题,请参考以下文章

[RK3568][Android11]PackageInstaller(应用安装)流程介绍

Android Lollipop - PackageInstaller.Session commit()

Android O PackageInstaller 解析

Android PackageInstaller,更新后重新打开应用程序

Android包管理机制 PackageInstaller的初始化

Android包管理机制PackageInstaller的初始化