Android 使用 PackageInstaller 实现静默安装,并通过 BroadcastReceiver 自动重启应用

在 Android 系统中,如果你的应用具有系统权限(如系统签名或安装在 /system/priv-app 目录),就可以使用 PackageInstaller 实现 APK 的静默安装。

安装完成后,我们通常希望应用能够自动重启,以便更新立即生效。

本文将完整展示:

  1. BroadcastReceiver 监听安装事件

  2. 捕获自定义安装完成事件 (INSTALL_FINISH)

  3. 自动启动自身应用

  4. 使用 PackageInstaller 安装 APK 的完整代码

适用于 OTA 升级、企业设备更新、Kiosk 设备、医疗设备等定制系统。


一、监听系统安装广播

Android 在安装、升级应用时,会发送系统广播:

  • android.intent.action.PACKAGE_ADDED ------ 第一次安装

  • android.intent.action.PACKAGE_REPLACED ------ 覆盖安装(升级时必走)

  • 自定义广播:安装提交后的回调(PackageInstaller.commit)

清单文件配置如下:

复制代码
<receiver
    android:name=".updata.InstallReceiver"
    android:enabled="true"
    android:exported="true">

    <!-- 覆盖安装(升级) -->
    <intent-filter android:priority="999">
        <action android:name="android.intent.action.PACKAGE_REPLACED" />
        <data android:scheme="package" />
    </intent-filter>

    <!-- 第一次安装 -->
    <intent-filter android:priority="999">
        <action android:name="android.intent.action.PACKAGE_ADDED" />
        <data android:scheme="package" />
    </intent-filter>

    <!-- PackageInstaller commit 回调 -->
    <intent-filter>
        <action android:name="com.test.INSTALL_FINISH" />
    </intent-filter>

</receiver>

这里我们设置了高优先级,使其在系统广播链路中更早得到回调。


二、安装事件接收器 InstallReceiver

InstallReceiver 的任务:

  • 判断是否当前 App 被安装或升级

  • 若是,则自动启动

  • 接收 PackageInstaller 的提交回调

  • 同样执行启动逻辑

完整代码如下:

复制代码
package com.test.test.updata;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;

public class InstallReceiver extends BroadcastReceiver {

    private static final String TAG = "========";

    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        String pkg = null;

        if (intent.getData() != null) {
            pkg = intent.getData().getSchemeSpecificPart();
        }
        Log.e("========", "收到广播:" + action + "   包:" + pkg);

        // 本应用首次安装或升级安装
        if ((Intent.ACTION_PACKAGE_ADDED.equals(action)
                || Intent.ACTION_PACKAGE_REPLACED.equals(action))
                && pkg != null
                && pkg.equals(context.getPackageName())) {

            Log.e("========", "捕获安装或升级 → 自动启动");
            launchSelf(context);
            return;
        }

        // PackageInstaller 回调(仅首次安装)
        if ("com.test.INSTALL_FINISH".equals(action)) {
            Log.e("========", "收到 PackageInstaller commit 回调");
            launchSelf(context);
        }
    }

    private void launchSelf(Context context) {
        Intent launch = context.getPackageManager()
                .getLaunchIntentForPackage(context.getPackageName());

        if (launch != null) {
            launch.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            context.startActivity(launch);
        } else {
            Log.e(TAG, "找不到自己的启动 Activity");
        }
    }
}

安装完成后,会自动重新打开应用,实现无感升级。


三、使用 PackageInstaller 静默安装 APK

核心类:SystemInstaller

实现流程:

  1. 创建安装 Session

  2. 将 APK 内容写入 Session

  3. commit 提交安装

  4. 提交完成后系统会回调我们自定义广播 INSTALL_FINISH

代码如下:

复制代码
package com.test.test.updata;

import android.annotation.SuppressLint;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInstaller;
import android.util.Log;

import java.io.File;
import java.io.FileInputStream;
import java.io.OutputStream;

public class SystemInstaller {

    private static final String TAG = "SystemInstaller";

    @SuppressLint("RequestInstallPackagesPolicy")
    public static void installApk(Context context, String apkPath) {
        try {
            File apkFile = new File(apkPath);
            if (!apkFile.exists()) {
                Log.e(TAG, "APK 文件不存在: " + apkPath);
                return;
            }

            PackageInstaller packageInstaller = context.getPackageManager().getPackageInstaller();

            PackageInstaller.SessionParams params =
                    new PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL);

            params.setAppPackageName(null);

            int sessionId = packageInstaller.createSession(params);
            PackageInstaller.Session session = packageInstaller.openSession(sessionId);

            // 写入 APK
            try (OutputStream out = session.openWrite("app_install", 0, apkFile.length());
                 FileInputStream in = new FileInputStream(apkFile)) {

                byte[] buffer = new byte[8192];
                int c;
                while ((c = in.read(buffer)) != -1) {
                    out.write(buffer, 0, c);
                }
                session.fsync(out);
            }

            // 提交安装,发送 INSTALL_FINISH 回调
            session.commit(get(context).getIntentSender());
            session.close();

            Log.i(TAG, "提交安装成功");

        } catch (Exception e) {
            Log.e(TAG, "系统安装异常", e);
        }
    }

    public static PendingIntent get(Context context) {
        Intent intent = new Intent(context, InstallReceiver.class);
        intent.setAction("com.test.INSTALL_FINISH");

        return PendingIntent.getBroadcast(
                context,
                0,
                intent,
                PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE
        );
    }
}

四、安装完成自动重启应用的完整链路

整个流程如下:

复制代码
installApk()
     ↓ commit
InstallReceiver (INSTALL_FINISH 广播)
     ↓
launchSelf() 启动应用

系统安装广播 PACKAGE_REPLACED/PACKAGE_ADDED
     ↓
InstallReceiver 捕获自身包名
     ↓
launchSelf() 重新启动

无论是首次安装、覆盖安装还是 commit 回调,都能够完成自动启动。


五、注意事项

  1. 必须是系统应用或具备系统权限,否则静默安装会失败。
相关推荐
颂love37 分钟前
MySQL的执行流程
android·数据库·mysql
云起SAAS5 小时前
抖音小游戏源码 - 消消乐 | 含激励广告+成就系统 | 开箱即用商业级消除游戏模板
android·游戏·广告联盟·看激励广告联盟流量主·抖音小游戏源码 - 消消乐
大貔貅喝啤酒7 小时前
基于Windows下载安装Android Studio 3.3.2版本教程(2026详细图文版)
android·java·windows·android studio
程序员码歌7 小时前
OpenSpec 到 Superpowers:AI 编码从说清到做对
android·前端·人工智能
2501_915106327 小时前
深入解析无源码iOS加固原理与方案,保护应用安全
android·安全·ios·小程序·uni-app·cocoa·iphone
我叫张小白。9 小时前
PyCharm 集成 Git 与 Gitee
git·pycharm·gitee
黄林晴10 小时前
重磅官宣:Android UI 开发正式进入 Compose-first 时代
android·google io
Kapaseker11 小时前
搞懂变换!精通 Compose 绘制(二)
android·kotlin
美狐美颜SDK开放平台11 小时前
美颜SDK开发详解:如何优化美颜SDK在低端安卓机上的性能?
android·ios·音视频·直播美颜sdk·视频美颜sdk
Gary Studio11 小时前
深入MTK Android BSP:如何确定编译目标与查找项目设备树
android