赞
踩
xapk是将apk和其他文件打包成一个压缩文件,以.xapk格式结尾。调试时可以将.xapk后缀直接改为zip后缀,然后使用解压缩工具解压xapk包。通常能看到多个apk文件和一些资源配置文件,以Spotify.xapk包为例。
1、adb install-multiple调试是否可安装
2、代码实现
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、参考链接
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。