Android支持XAPK安装

XAPK安装需求

  • 支持XAPK安装
  • 支持APK/XAPK跨用户安装

xapk是将apk和其他文件打包成一个压缩文件,以.xapk格式结尾。调试时可以将.xapk后缀直接改为zip后缀,然后使用解压缩工具解压xapk包。通常能看到多个apk文件和一些资源配置文件,以Spotify.xapk包为例。
在这里插入图片描述

xapk安装

1、adb install-multiple调试是否可安装
在这里插入图片描述

2、代码实现

  • 解压xapk文件到一个新目录:unzip the file to a new folder.
    上层可使用原生API方法ZipFile类或ZipInputStream类进行解压缩。
  • 执行多次apk安装:install multiple.
private static boolean installXApk(Context context, File outputDirectory) {
        if (outputDirectory == null || !outputDirectory.exists()) return false;
        Log.d(TAG, "installXApk outputDirectory = " + outputDirectory.getPath());
        PackageInstaller packageInstaller = context.getPackageManager().getPackageInstaller();
        // 创建SessionParams对象,设置APK文件的安装参数
        PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL);
        //params.setAppPackageName(""); // 如果需要,设置目标应用的包名
        // 尝试创建新的安装会话
        int sessionId;
        try {
            sessionId = packageInstaller.createSession(params);
        } catch (IOException e) {
            Log.e(TAG, "Failed to create session", e);
            return false;
        }
        File[] apkFiles = outputDirectory.listFiles();
        if (apkFiles == null) {
            return false;
        }
        // 打开安装会话
        PackageInstaller.Session session = null;
        try {
            session = packageInstaller.openSession(sessionId);
        } catch (IOException e) {
            e.printStackTrace();
        }
        for (File apkFile : apkFiles) {
            if (!apkFile.getName().endsWith(".apk")) continue;
            Log.d(TAG, "installApk: name = " + apkFile.getName());
            OutputStream out = null;
            try {
                session = packageInstaller.openSession(sessionId);
                out = session.openWrite(apkFile.getName(), 0, apkFile.length());
                FileInputStream in = new FileInputStream(apkFile);
                byte[] buffer = new byte[65536];
                int c;
                while ((c = in.read(buffer)) != -1) {
                    out.write(buffer, 0, c);
                }
                session.fsync(out);
            } catch (IOException e) {
                Log.e(TAG, "Failed to write APK to session", e);
                if (session != null) session.abandon(); //如果写入失败,放弃会话
                return false;
            } finally {
                try {
                    if (out != null) {
                        out.close();
                    }
                } catch (IOException e) {
                    Log.e(TAG, "Failed to close output stream", e);
                }
            }
        }
        if (session != null) {
            PendingIntent intent = PendingIntent.getBroadcast(context, 0, new Intent("com.example.install"), PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT);
            session.commit(intent.getIntentSender());
            Log.d(TAG, "installXApk commit sessionId = " + sessionId);
        }
        return true;
    }

多用户安装

通常我们安装apk都是在给当前用户安装,该需求需要能做到跨用户安装,满足如下要求:

  • 在user用户下为当前用户安装apk

  • 在当前用户下为其他用户安装apk

1、在满足android:sharedUserId="android.uid.system"和系统platform签名的情况下,通过 pm install --user 指定用户来安装apk的方式理论可行。但在实现过程中会遇到data目录selinux权限以及违反neverallow规则等一系列问题。

2、PackageInstaller.Session传递apk路径方式默认安装在主用户下,无法直接为子用户安装apk。
目前找到的跨用户方式是通过机器已存在的packageName包名进行安装。

public static boolean silentInstallAsUser(Context context, String packageName, int userId) {
        Log.i(TAG, "silentInstallAsUser packageName = " + packageName + ", userId = " + userId);
        PackageManager pm = context.getPackageManager();
        try {
            int status = pm.installExistingPackageAsUser(packageName, userId);
            if (status == PackageManager.INSTALL_SUCCEEDED) {
                Log.d(TAG,"Install succeed");
                return true;
            } else {
                Log.d(TAG,"Install failed, result code = " + status);
                return false;
            }
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        return false;
    }

3、最终思路是通过区分两种情况(主用户安装/跨用户安装)来执行不同安装:

public boolean installMultuserApp(int userId, String path) {
        boolean ret = false;
        try {
            int currentUserId = ActivityManager.getCurrentUser();
            if (userId == 0) { //主用户静默安装
                ret = SilentInstallManager.silentInstallApk(mContext, path);
            } else { //跨用户静默安装
                String packageName = SilentInstallManager.getPackageName(mContext, path);
                if (!TextUtils.isEmpty(packageName)) {
                    boolean hasPackageName = SilentInstallManager.isAppInstalled(mContext, packageName);
                    Log.i(TAG, "installMultuserApp hasPackageName = " + hasPackageName);
                    if (hasPackageName) { //若存在该包名则直接安装
                        ret = SilentInstallManager.silentInstallAsUser(mContext, packageName, userId);
                    } else { //若不存在该包名则先安装在主用户,再安装到其它用户,最后再卸载主用户的包名
                        boolean mainStatus = SilentInstallManager.silentInstallApk(mContext, path);
                        if (mainStatus) {
                            //Thread.sleep(8000);
                            ret = SilentInstallManager.silentInstallAsUser(mContext, packageName, userId);
                        }
                        //最后再卸载主用户的包名
                        SilentInstallManager.silentUninstallAsUser(mContext, packageName, 0);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return ret;
    }

4、参考链接

Vivado2023是一款集成开发环境软件,用于设计和验证FPGA(现场可编程门阵列)和可编程逻辑器件。对于使用Vivado2023的用户来说,license是必不可少的。 Vivado2023的license是一种许可证,用于授权用户合法使用该软件。许可证分为多种类型,包括评估许可证、开发许可证和节点许可证等。每种许可证都有不同的使用条件和功能。 评估许可证是免费提供的,让用户可以在一段时间内试用Vivado2023的全部功能。用户可以使用这个许可证来了解软件的性能和特点,对于初学者和小规模项目来说是一个很好的选择。但是,使用评估许可证的用户在使用期限过后需要购买正式的许可证才能继续使用软件。 开发许可证是付费的,可以永久使用Vivado2023的全部功能。这种许可证适用于需要长期使用Vivado2023进行开发的用户,通常是专业的FPGA设计师或工程师。购买开发许可证可以享受Vivado2023的技术支持和更新服务,确保软件始终保持最新的版本和功能。 节点许可证是用于多设备或分布式设计的许可证,可以在多个计算机上安装Vivado2023,并共享使用。节点许可证适用于大规模项目或需要多个处理节点进行设计的用户,可以提高工作效率和资源利用率。 总之,Vivado2023 license是用户在使用Vivado2023时必须考虑的问题。用户可以根据自己的需求选择合适的许可证类型,以便获取最佳的软件使用体验。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值