研究应用的安装过程,老样子,我们还是先从使用入手。
在Android中,通过发送Intent就可以启动应用的安装过程,比如:
Uri uri = Uri.fromFile(new File(apkFilePath));
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(uri,"application/vnd.android.package-archive");
startActivity(intent);
而在Android的系统应用PackageInstaller中有一个InstallStart会响应这个Intent,
<activity android:name=".InstallStart"
android:theme="@style/Installer"
android:exported="true"
android:excludeFromRecents="true">
<intent-filter android:priority="1">
<action android:name="android.intent.action.VIEW" />
<action android:name="android.intent.action.INSTALL_PACKAGE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="file" />
<data android:scheme="content" />
<data android:mimeType="application/vnd.android.package-archive" />
</intent-filter>
......
</activity>
在InstallStart中会进行各种Uri的判断,最终会跳转到一个叫做PackageInstallerActivity的界面。
国内的厂商基本上会在
InstallStart这里进行修改,替换为自己的安装界面
对于PackageInstallerActivity来说,它的主要作用是
- 解析
Uri协议进行解析,包括file和package两种- 如果是
file协议会解析APK文件得到包信息PackageInfo
- 如果是
- 对未知来源进行处理
- 如果允许安装未知来源或者根据
Intent判断得出该APK不是未知来源,就会初始化安装确认界面 - 如果管理员限制来自未知源的安装, 就弹出提示
Dialog或者跳转到设置界面
- 如果允许安装未知来源或者根据
- 提取并在界面展示应用对应的权限
当点击确认安装后,其实会执行到startInstall()方法,相关内容如下:
private void startInstall() {
// Start subactivity to actually install the application
Intent newIntent = new Intent();
......
newIntent.setData(mPackageURI);
newIntent.setClass(this, InstallInstalling.class);
......
startActivity(newIntent);
finish();
}
上面的逻辑是跳转到InstallInstalling界面进行安装,我们看看这个Activity:
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
......
if ("package".equals(mPackageURI.getScheme())) {
// 直接安装 package
try {
getPackageManager().installExistingPackage(appInfo.packageName);
launchSuccess();
} catch (PackageManager.NameNotFoundException e) {
launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null);
}
} else {
// 对于 file 安装,按照session的逻辑去走
// 这部分在onResume中开始
final File sourceFile = new File(mPackageURI.getPath());
......
if (savedInstanceState != null) {
mSessionId = savedInstanceState.getInt(SESSION_ID);
mInstallId = savedInstanceState.getInt(INSTALL_ID);
......
} else {
......
mSessionId = getPackageManager().getPackageInstaller().createSession(params);
......
// 创建应用安装状态的Observer
// 真正注册是在后面 Session 的 commitLocked 中
// InstallEventReceiver 这里是做了二次封装,方便进行持久化操作
InstallEventReceiver.addObserver(this, mInstallId,
this::launchFinishBasedOnResult);
}
......
}
}
@Override
protected void onResume() {
super.onResume();
// This is the first onResume in a single life of the activity
if (mInstallingTask == null) {
PackageInstaller installer = getPackageManager().getPackageInstaller();
PackageInstaller.SessionInfo sessionInfo = installer.getSessionInfo(mSessionId);
// 启动异步安装任务 InstallingAsyncTask 进行一系列的session操作
if (sessionInfo != null && !sessionInfo.isActive()) {
mInstallingTask = new InstallingAsyncTask();
mInstallingTask.execute();
}
......
}
}
从上面的方法我们可以看到安装操作主要分为两个接口:
getPackageManager().installExistingPackage():主要是对已经并扫描到Settings的mPackages集合中的应用进行操作- 根据当前的
userID从集合中查询应用状态,如果存在并且应用没有安装,就进行一些简单的配置工作 - 最后通过
prepareAppDataAfterInstallLIF方法,创建特定userID下的应用数据
- 根据当前的
InstallingAsyncTask任务中的Session系列操作:一个应用完整的安装过程从这里开始private final class InstallingAsyncTask extends AsyncTask<Void, Void, PackageInstaller.Session> { volatile boolean isDone; @Override protected PackageInstaller.Session doInBackground(Void... params) { PackageInstaller.Session session; ...... session = getPackageManager().getPackageInstaller().openSession(mSessionId); try { File file = new File(mPackageURI.getPath()); try (InputStream in = new FileInputStream(file)) { long sizeBytes = file.length(); try (OutputStream out = session.openWrite("PackageInstaller", 0, sizeBytes)) { byte[] buffer = new byte[1024 * 1024]; while (true) { .

本文详细解析了Android应用的安装流程,从Intent启动安装、PackageInstallerService响应、InstallStart活动、PackageInstallerActivity的作用,到文件复制和安装阶段。过程中涉及到的关键类如PackageInstallerSession、InstallParams和InstallArgs,以及安装过程中对Uri、Intent、服务连接和文件操作的处理。此外,还简要提及了安装后的广播通知和观察者回调。
最低0.47元/天 解锁文章
3337

被折叠的 条评论
为什么被折叠?



