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. 必须是系统应用或具备系统权限,否则静默安装会失败。
相关推荐
柯南二号2 小时前
【大前端】【Android】用 Python 脚本模拟点击 Android APP —— 全面技术指南
android·前端·python
龚礼鹏2 小时前
图像显示框架六——SurfaceFlinger的初始化以及任务调度(基于Android 15源码分析)
android
ao_lang2 小时前
MySQL的存储过程和触发器
android·数据库·mysql
WebCsDn_TDCode2 小时前
Android Studio使用教程
android·android studio
小蜜蜂嗡嗡2 小时前
Android studio配置忽略文件
android·ide·android studio
颜颜yan_3 小时前
DevUI自定义开发实践:从零开始构建自定义组件和插件
android·java·数据库
爬也要爬着前进3 小时前
k8s部署wordpress
android·容器·kubernetes
儿歌八万首3 小时前
Flutter 混合开发指南:项目打包与原生 Android/iOS 集成
android·flutter·ios
2501_915921433 小时前
从需求到上架,现代 iOS 开发流程的工程化方法论
android·ios·小程序·https·uni-app·iphone·webview