PackageUtil.AppSnippet as = PackageUtil.getAppSnippet(this, appInfo, sourceFile);
mAlert.setIcon(as.icon);
…
if (savedInstanceState != null) {
//咱们第一次仅savedInstanceState==null
//安装包的会话 ID
mSessionId = savedInstanceState.getInt(SESSION_ID);
//我们等待的安装事件的 ID
mInstallId = savedInstanceState.getInt(INSTALL_ID);
//重新登记结果;如果结果是在 Activtiy 被销毁时交付的,则可能会立即回调
try {
//添加一个观察者。如果此id已存在事件,请在此调用内回调。
// 向 InstallEventReceiver 注册一个观察者
// InstallEventReceiver 是一个 BroadcastReceiver,可以通过 EventResultPersister 接收到所有的安装事件
// 这里事件会回调给 this::launchFinishBasedOnResult
InstallEventReceiver.addObserver(this, mInstallId,
this::launchFinishBasedOnResult);
} catch (EventResultPersister.OutOfIdsException e) {
// Does not happen
}
} else {
//咱们第一次仅savedInstanceState==null
//创建 SessionParams,它用来携带会话的参数
PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
PackageInstaller.SessionParams.MODE_FULL_INSTALL);
params.setInstallAsInstantApp(false);
…
params.setInstallReason(PackageManager.INSTALL_REASON_USER);
File file = new File(mPackageURI.getPath());
try {
// 对 APK 进行轻量级的解析,并将解析的结果赋值给 SessionParams 相关字段
PackageParser.PackageLite pkg = PackageParser.parsePackageLite(file, 0);
params.setAppPackageName(pkg.packageName);
params.setInstallLocation(pkg.installLocation);
params.setSize(
PackageHelper.calculateInstalledSize(pkg, false, params.abiOverride));
} catch (PackageParser.PackageParserException e) {
…
} catch (IOException e) {
…
}
try {
// 向 InstallEventReceiver 注册一个观察者返回一个新的 mInstallId
// InstallEventReceiver 是一个 BroadcastReceiver,可以通过 EventResultPersister 接收到所有的安装事件
// 这里事件会回调给 this::launchFinishBasedOnResult
mInstallId = InstallEventReceiver
.addObserver(this, EventResultPersister.GENERATE_NEW_ID,
this::launchFinishBasedOnResult);
} catch (EventResultPersister.OutOfIdsException e) {
launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null);
}
try {
//PackageInstaller 的 createSession
//方法内部会通过 IPackageInstaller 与 PackageInstallerService进行进程间通信,
//最终调用的是 PackageInstallerService 的 createSession 方法来创建并返回 mSessionId
mSessionId = getPackageManager().getPackageInstaller().createSession(params);
} catch (IOException e) {
launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null);
}
}
mCancelButton = mAlert.getButton(DialogInterface.BUTTON_NEGATIVE);
//监听会话的更改并更新进度条
mSessionCallback = new InstallSessionCallback();
}
}
NameNotFoundException:当找不到给定的包、应用程序或组件名称时,将引发此异常。
在 onCreate() 方法中,首先执行一些初始化操作,比如获取 mInstallId、mSessionId以及监听回调 mSessionCallback 。接下来看看 onStart() 。
onStart()
@Override
protected void onStart() {
super.onStart();
//设置回话监听回调
getPackageManager().getPackageInstaller().registerSessionCallback(mSessionCallback);
}
onResume()
@Override
protected void onResume() {
super.onResume();
//This is the first onResume in a single life of the activity
if (mInstallingTask == null) {
//PackageInstaller:提供在设备上安装、升级和删除应用程序的能力。
//这包括支持打包为单个“整体”APK 的应用程序或打包为多个“拆分”APK 的应用程序。
PackageInstaller installer = getPackageManager().getPackageInstaller();
//安装Session的详细信息
PackageInstaller.SessionInfo sessionInfo = installer.getSessionInfo(mSessionId);
if (sessionInfo != null && !sessionInfo.isActive()) {
//创建mInstallingTask并启动
mInstallingTask = new InstallingAsyncTask();
mInstallingTask.execute();
} else {
// 安装完成后我们会收到广播
//mCancelButton不允许点击
mCancelButton.setEnabled(false);
//Activity.setFinishOnTouchOutside():设置此活动在其窗口边界外触摸
setFinishOnTouchOutside(false);
}
}
}
InstallingAsyncTask
/**
* Send the package to the package installer and then register a event result observer that
* will call {@link #launchFinishBasedOnResult(int, int, String)}
*/
private final class InstallingAsyncTask extends AsyncTask<Void, Void,
PackageInstaller.Session> {
volatile boolean isDone;
@Override
protected PackageInstaller.Session doInBackground(Void… params) {
PackageInstaller.Session session;
try {
//打开现有Session
session = getPackageManager().getPackageInstaller().openSession(mSessionId);
} catch (IOException e) {
synchronized (this) {
isDone = true;
notifyAll();
}
return null;
}
//设置暂存此会话的当前进度(0-1z之间)。
session.setStagingProgress(0);
try {
File file = new File(mPackageURI.getPath());
//输入流in
try (InputStream in = new FileInputStream(file)) {
long sizeBytes = file.length();
//打开一个流以将 APK 文件写入会话。
try (OutputStream out = session
.openWrite(“PackageInstaller”, 0, sizeBytes)) {
byte[] buffer = new byte[1024 * 1024];
//写入文件
while (true) {
int numRead = in.read(buffer);
if (numRead == -1) {
session.fsync(out);
break;
}
if (isCancelled()) {
session.close();
break;
}
//将 APK 文件通过 IO 流的形式写入到 PackageInstaller.Session 中
out.write(buffer, 0, numRead);
if (sizeBytes > 0) {
float fraction = ((float) numRead / (float) sizeBytes);
session.addProgress(fraction);
}
}
}
}
return session;
} catch (IOException | SecurityException e) {
Log.e(LOG_TAG, “Could not write package”, e);
session.close();
return null;
} finally {
synchronized (this) {
isDone = true;
notifyAll();
}
}
}
@Override
protected void onPostExecute(PackageInstaller.Session session) {
if (session != null) {
//包已下载好,设置安装提交广播
Intent broadcastIntent = new Intent(BROADCAST_ACTION);
broadcastIntent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
broadcastIntent.set