文章目录
- 一、安装应用源码分析
- 1、HomePresenterImpl 添加应用
- 2、AppRepository.addVirtualApp 安装 SD 卡 APK 应用
一、安装应用源码分析
1、HomePresenterImpl 添加应用
mPresenter.addApp(info);
实际上调用的是 io.virtualapp.home.HomePresenterImpl
类的 addApp()
方法 , 安装应用 , 传入 AppInfoLite info
参数 , 封装如下值 :
packageName : com.example.filepath , path : /storage/emulated/0/./app-debug.apk , fastOpen : false
通过 VirtualCore.get().getInstalledAppInfo(info.packageName, 0);
代码 , 获取该应用是否安装过 ,
- 如果应用安装过 , 则该安装操作是克隆应用 ;
- 如果应用没有安装过 , 则该安装操作是从 SD 卡安装 ; 如果是从 SD 卡安装 , 则调用
InstallResult res = mRepo.addVirtualApp(info);
进行安装操作 ;
class HomePresenterImpl implements HomeContract.HomePresenter {
@Override
public void addApp(AppInfoLite info) {
class AddResult {
private PackageAppData appData;
private int userId;
private boolean justEnableHidden;
}
AddResult addResult = new AddResult();
VUiKit.defer().when(() -> {
// 获取安装的应用信息 , 该应用之前是否安装过
// 这里应该是判断 克隆应用 / SD 卡 APK 文件
InstalledAppInfo installedAppInfo = VirtualCore.get().getInstalledAppInfo(info.packageName, 0);
// 是否隐藏 , 如果之前有安装过 , 即这是第二次安装 , 则需要隐藏 , 命中 if (addResult.justEnableHidden) 分支
addResult.justEnableHidden = installedAppInfo != null;
if (addResult.justEnableHidden) { // 克隆应用
int[] userIds = installedAppInfo.getInstalledUsers();
int nextUserId = userIds.length;
/*
Input : userIds = {0, 1, 3}
Output: nextUserId = 2
*/
for (int i = 0; i < userIds.length; i ) {
if (userIds[i] != i) {
nextUserId = i;
break;
}
}
addResult.userId = nextUserId;
if (VUserManager.get().getUserInfo(nextUserId) == null) {
// user not exist, create it automatically.
String nextUserName = "Space " (nextUserId 1);
VUserInfo newUserInfo = VUserManager.get().createUser(nextUserName, VUserInfo.FLAG_ADMIN);
if (newUserInfo == null) {
throw new IllegalStateException();
}
}
boolean success = VirtualCore.get().installPackageAsUser(nextUserId, info.packageName);
if (!success) {
throw new IllegalStateException();
}
} else { // SD 卡 APK 文件 , 如果是第一次安装 , 则命中该分支
InstallResult res = mRepo.addVirtualApp(info);
if (!res.isSuccess) {
throw new IllegalStateException();
}
}
}).then((res) -> {
addResult.appData = PackageAppDataStorage.get().acquire(info.packageName);
}).done(res -> {
boolean multipleVersion = addResult.justEnableHidden && addResult.userId != 0;
if (!multipleVersion) {
PackageAppData data = addResult.appData;
data.isLoading = true;
mView.addAppToLauncher(data);
handleOptApp(data, info.packageName, true);
} else {
MultiplePackageAppData data = new MultiplePackageAppData(addResult.appData, addResult.userId);
data.isLoading = true;
mView.addAppToLauncher(data);
handleOptApp(data, info.packageName, false);
}
});
}
}
2、AppRepository.addVirtualApp 安装 SD 卡 APK 应用
InstallResult res = mRepo.addVirtualApp(info);
方法调用的是 AppRepository
类的 addVirtualApp
方法 ;
public class AppRepository implements AppDataSource {
@Override
public InstallResult addVirtualApp(AppInfoLite info) {
// int COMPARE_VERSION = 0X01 << 3;
// int SKIP_DEX_OPT = 0x01 << 6;
int flags = InstallStrategy.COMPARE_VERSION | InstallStrategy.SKIP_DEX_OPT;
// fastOpen 值是 false , 该分支没有命中
if (info.fastOpen) {
flags |= InstallStrategy.DEPEND_SYSTEM_IF_EXIST;
}
// 安装 SD 卡中的 APK 文件
return VirtualCore.get().installPackage(info.path, flags);
}
}
原始数据 AppInfoLite info
如下 :
I/HSL: packageName : com.example.filepath , path : /storage/emulated/0/./app-debug.apk , fastOpen : false
此处找到了可以直接调用的 API 方法 , 调用 VirtualCore.get().installPackage( SD卡绝对路径 , 0X01 << 3 | 0x01 << 6);
API 安装某个路径中中的 APK 文件 ;
flags 值参考 : 0X01 << 3 | 0x01 << 6
;
// int COMPARE_VERSION = 0X01 << 3;
// int SKIP_DEX_OPT = 0x01 << 6;
int flags = InstallStrategy.COMPARE_VERSION | InstallStrategy.SKIP_DEX_OPT;
InstallStrategy
常量类定义 :
public interface InstallStrategy {
int TERMINATE_IF_EXIST = 0x01 << 1;
int UPDATE_IF_EXIST = 0x01 << 2;
int COMPARE_VERSION = 0X01 << 3;
int IGNORE_NEW_VERSION = 0x01 << 4;
int DEPEND_SYSTEM_IF_EXIST = 0x01 << 5;
int SKIP_DEX_OPT = 0x01 << 6;
}