Android支持XAPK安装

打印 上一主题 下一主题

主题 510|帖子 510|积分 1530

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.
  1. private static boolean installXApk(Context context, File outputDirectory) {
  2.         if (outputDirectory == null || !outputDirectory.exists()) return false;
  3.         Log.d(TAG, "installXApk outputDirectory = " + outputDirectory.getPath());
  4.         PackageInstaller packageInstaller = context.getPackageManager().getPackageInstaller();
  5.         // 创建SessionParams对象,设置APK文件的安装参数
  6.         PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL);
  7.         //params.setAppPackageName(""); // 如果需要,设置目标应用的包名
  8.         // 尝试创建新的安装会话
  9.         int sessionId;
  10.         try {
  11.             sessionId = packageInstaller.createSession(params);
  12.         } catch (IOException e) {
  13.             Log.e(TAG, "Failed to create session", e);
  14.             return false;
  15.         }
  16.         File[] apkFiles = outputDirectory.listFiles();
  17.         if (apkFiles == null) {
  18.             return false;
  19.         }
  20.         // 打开安装会话
  21.         PackageInstaller.Session session = null;
  22.         try {
  23.             session = packageInstaller.openSession(sessionId);
  24.         } catch (IOException e) {
  25.             e.printStackTrace();
  26.         }
  27.         for (File apkFile : apkFiles) {
  28.             if (!apkFile.getName().endsWith(".apk")) continue;
  29.             Log.d(TAG, "installApk: name = " + apkFile.getName());
  30.             OutputStream out = null;
  31.             try {
  32.                 session = packageInstaller.openSession(sessionId);
  33.                 out = session.openWrite(apkFile.getName(), 0, apkFile.length());
  34.                 FileInputStream in = new FileInputStream(apkFile);
  35.                 byte[] buffer = new byte[65536];
  36.                 int c;
  37.                 while ((c = in.read(buffer)) != -1) {
  38.                     out.write(buffer, 0, c);
  39.                 }
  40.                 session.fsync(out);
  41.             } catch (IOException e) {
  42.                 Log.e(TAG, "Failed to write APK to session", e);
  43.                 if (session != null) session.abandon(); //如果写入失败,放弃会话
  44.                 return false;
  45.             } finally {
  46.                 try {
  47.                     if (out != null) {
  48.                         out.close();
  49.                     }
  50.                 } catch (IOException e) {
  51.                     Log.e(TAG, "Failed to close output stream", e);
  52.                 }
  53.             }
  54.         }
  55.         if (session != null) {
  56.             PendingIntent intent = PendingIntent.getBroadcast(context, 0, new Intent("com.example.install"), PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT);
  57.             session.commit(intent.getIntentSender());
  58.             Log.d(TAG, "installXApk commit sessionId = " + sessionId);
  59.         }
  60.         return true;
  61.     }
复制代码

多用户安装

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


  • 在user用户下为当前用户安装apk
  • 在当前用户下为其他用户安装apk
1、在满足android:sharedUserId="android.uid.system"和体系platform签名的情况下,通过 pm install --user 指定用户来安装apk的方式理论可行。但在实现过程中会遇到data目录selinux权限以及违反neverallow规则等一系列标题。
2、PackageInstaller.Session传递apk路径方式默认安装在主用户下,无法直接为子用户安装apk。
目前找到的跨用户方式是通过机器已存在的packageName包名进行安装。
  1. public static boolean silentInstallAsUser(Context context, String packageName, int userId) {
  2.         Log.i(TAG, "silentInstallAsUser packageName = " + packageName + ", userId = " + userId);
  3.         PackageManager pm = context.getPackageManager();
  4.         try {
  5.             int status = pm.installExistingPackageAsUser(packageName, userId);
  6.             if (status == PackageManager.INSTALL_SUCCEEDED) {
  7.                 Log.d(TAG,"Install succeed");
  8.                 return true;
  9.             } else {
  10.                 Log.d(TAG,"Install failed, result code = " + status);
  11.                 return false;
  12.             }
  13.         } catch (PackageManager.NameNotFoundException e) {
  14.             e.printStackTrace();
  15.         }
  16.         return false;
  17.     }
复制代码
3、最终思路是通过区分两种情况(主用户安装/跨用户安装)来执行不同安装:
  1. public boolean installMultuserApp(int userId, String path) {
  2.         boolean ret = false;
  3.         try {
  4.             int currentUserId = ActivityManager.getCurrentUser();
  5.             if (userId == 0) { //主用户静默安装
  6.                 ret = SilentInstallManager.silentInstallApk(mContext, path);
  7.             } else { //跨用户静默安装
  8.                 String packageName = SilentInstallManager.getPackageName(mContext, path);
  9.                 if (!TextUtils.isEmpty(packageName)) {
  10.                     boolean hasPackageName = SilentInstallManager.isAppInstalled(mContext, packageName);
  11.                     Log.i(TAG, "installMultuserApp hasPackageName = " + hasPackageName);
  12.                     if (hasPackageName) { //若存在该包名则直接安装
  13.                         ret = SilentInstallManager.silentInstallAsUser(mContext, packageName, userId);
  14.                     } else { //若不存在该包名则先安装在主用户,再安装到其它用户,最后再卸载主用户的包名
  15.                         boolean mainStatus = SilentInstallManager.silentInstallApk(mContext, path);
  16.                         if (mainStatus) {
  17.                             //Thread.sleep(8000);
  18.                             ret = SilentInstallManager.silentInstallAsUser(mContext, packageName, userId);
  19.                         }
  20.                         //最后再卸载主用户的包名
  21.                         SilentInstallManager.silentUninstallAsUser(mContext, packageName, 0);
  22.                     }
  23.                 }
  24.             }
  25.         } catch (Exception e) {
  26.             e.printStackTrace();
  27.         }
  28.         return ret;
  29.     }
复制代码
4、参考链接


  • https://android.stackexchange.com/questions/221204/how-to-install-xapk-apks-or-multiple-apks-via-adb
  • https://alysoninno.cn/android/install-apk-splits-package

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

正序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

宝塔山

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表