静默安装的实现

近期做了一个车机上的应用商店App,安装包下载完成后需要通过静默安装的方式将应用在后台进行无声无息的安装,这里使用的安装方法是通过 PackageInstaller.Secssion 实现静默安装,该接口需要获取系统权限 android.permission.INSTALL_PACKAGES

1.其主要通过下面三个步骤进行的:

	//1.创建Session
	int sessionId = packageInstaller.createSession(params);
	//2.开启Session
	session = packageInstaller.openSession(sessionId);
	//3.获取输出流,用于将apk写入session
	outputStream = session.openWrite(apkName, 0, apkFile.length());
	//4.提交安装完成Intent
	session.commit(intentSender);

2.主要代码:

(1)installApk方法:

 public void installApk(String apkFilePath, InstallObserver installObserver) {
 		/*apkFilePath:这里我们首先传入的是安装包的路径   installObserver:自定义安装的回调,不需要可以删了*/
        File apkFile = new File(apkFilePath);
        //判断路径下的文件是否存在
        if (!apkFile.exists()) {
            LogUtils.error(TAG, "apkFile is null...");
            return;
        }
        String packageName = "";
        //获取安装包的信息
        PackageInfo packageInfo = AppStoreApplication.getApp().getPkgManager().getPackageArchiveInfo(apkFilePath,
                    PackageManager.GET_ACTIVITIES | PackageManager.GET_SERVICES);
        if (packageInfo != null) {
            packageName = packageInfo.packageName;
            String versionName = packageInfo.versionName
        }
        //获取packageInstaller,后面用来创建PackageInstaller.Session
        PackageInstaller packageInstaller = AppStoreApplication.getApp().getPkgManager().getPackageInstaller();
        //获取创建PackageInstaller.Session的参数
        PackageInstaller.SessionParams sessionParams = new PackageInstaller.SessionParams(
            PackageInstaller.SessionParams.MODE_FULL_INSTALL);
        /*指示将在此会话中交付的所有APK的总大小(以字节为单位),系统可以使用它来确保在继续之前存在足够的磁盘空间,
        或者估计安装在外部存储上的容器大小*/
        sessionParams.setSize(apkFile.length());
        PackageInstaller.Session session = null;
        try {
            //代表一个session的唯一ID,这里我是在全局变量中声明,因为后面的另外一个方法用到了这个sessionId
            mSessionId = packageInstaller.createSession(sessionParams);
            if (mSessionId != -1) {
            	//也就是在这个外部的onTransfesApkFile()方法中,将会用到sessionId
                boolean copySuccess = onTransfesApkFile(apkFilePath, packageName);
                if (copySuccess) { 
                    session = AppStoreApplication.getApp().getPkgManager().getPackageInstaller().openSession(mSessionId);
                    //设置安装完成后需要发送的一个自定义安装结果广播,这里我设置了App的NAME,VERSION,PACKAGE
                    Intent intent = new Intent(AppStoreApplication.getApp(),
                        InstallResultReceiver.class);
                    intent.setAction(PackageInstaller.EXTRA_STATUS);
                    intent.putExtra("APP_NAME", localAppInfo.getName());
                    intent.putExtra("APP_VERSION", localAppInfo.getLastVersion());
                    intent.putExtra("APP_PACKAGE", localAppInfo.getPackageName());
                    //执行结束后,发送intent
                    PendingIntent pendingIntent = PendingIntent.getBroadcast(AppStoreApplication.getApp(),1, 
	                    intent, PendingIntent.FLAG_UPDATE_CURRENT);
	                //这里最终进行session的提交
                   	session.commit(pendingIntent.getIntentSender());                 
                } else {
                	//此处是安装失败的回调,不需要可以删除
                    if (installObserver != null) {
                        installObserver.observer(false, apkFilePath, packageName);
                    }
                }
            }
        } catch (Exception exception) {
            LogUtils.error(TAG, "installApk exception = " + exception.getLocalizedMessage());
        } finally {
            if (null != session) {
                session.close();
            }
            //安装完成需要删除文件
            if (apkFile != null && apkFile.exists()) {
                apkFile.delete();
            }
        }
    }

(2)onTransfesApkFile方法(写入数据):

 private static boolean onTransfesApkFile(String apkFilePath, String packageName) {
        InputStream in = null;
        OutputStream out = null;
        PackageInstaller.Session session = null;
        boolean success = false;
        try {
            File apkFile = new File(apkFilePath);
            //根据sessionId来获取其代表的session
            session = AppStoreApplication.getApp().getPkgManager().getPackageInstaller().openSession(mSessionId);
            //向session中写入文件数据
            out = session.openWrite(packageName + "_base.apk", 0, apkFile.length());
            in = new FileInputStream(apkFile);
            int total = 0;
            int len;
            byte[] buffer = new byte[ONE_ZERO_TWO_FOUR * ONE_ZERO_TWO_FOUR];
            while ((len = in.read(buffer)) != -1) {
                total += len;
                out.write(buffer, 0, len);
            }
            session.fsync(out);
            success = true;
        } catch (IOException exception) {
            exception.printStackTrace();
        } finally {
            if (null != session) {
                session.close();
            }
            try {
                if (null != out) {
                    out.close();
                }
                if (null != in) {
                    in.close();
                }
            } catch (IOException exception) {
                exception.printStackTrace();
            }
        }
        return success;
    }

(3)广播接收应用安装的结果:

public class InstallResultReceiver extends BroadcastReceiver {

    private static final String TAG = "InstallResultReceiver";

    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if (PackageInstaller.EXTRA_STATUS.equals(action)) {
            // 接收package install 状态广播
            int status = intent.getIntExtra(
                PackageInstaller.EXTRA_STATUS, PackageInstaller.STATUS_FAILURE);
           		String appName = intent.getStringExtra("APP_NAME");
                String appPackage = intent.getStringExtra("APP_PACKAGE");     
            }
        }
    }
}

记住最后要在AndroidManifest.xml文件里去注册这个广播

<receiver
    android:name=".receiver.InstallResultReceiver"
    android:enabled="true"
    android:exported="true">
    <intent-filter android:priority="1000">
        <action android:name="android.content.pm.extra.STATUS" />
    </intent-filter>
</receiver>
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值