Android 插件化VirtualApp 源码分析 ( 安装应用源码分析 | HomePresenterImpl 添加应用 | AppRepository.addVirtualApp )

Posted 韩曙亮

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 插件化VirtualApp 源码分析 ( 安装应用源码分析 | HomePresenterImpl 添加应用 | AppRepository.addVirtualApp )相关的知识,希望对你有一定的参考价值。





一、安装应用源码分析




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;
}

以上是关于Android 插件化VirtualApp 源码分析 ( 安装应用源码分析 | HomePresenterImpl 添加应用 | AppRepository.addVirtualApp )的主要内容,如果未能解决你的问题,请参考以下文章

Android 插件化VirtualApp 源码分析 ( 安装应用源码分析 | HomePresenterImpl 添加应用 | AppRepository.addVirtualApp )

Android 插件化VirtualApp 源码分析 ( 安装应用源码分析 | HomePresenterImpl 添加应用 | AppRepository.addVirtualApp )

Android 插件化VirtualApp 接入 ( 在 VirtualApp 工程下创建 Module | 添加依赖 | 启动 VirtualApp 插件引擎 )

Android 插件化VirtualApp 接入 ( 在 VirtualApp 工程下创建 Module | 添加依赖 | 启动 VirtualApp 插件引擎 )

Android 插件化VirtualApp 安装并启动资源中自带的 APK 插件 ( 添加依赖库 | 准备插件 APK | 启动插件引擎 | 拷贝 APK 插件 | 安装插件 | 启动插件 )(代码片

Android 插件化VirtualApp 安装并启动资源中自带的 APK 插件 ( 添加依赖库 | 准备插件 APK | 启动插件引擎 | 拷贝 APK 插件 | 安装插件 | 启动插件 )(代码片