In the past, I\'ve asked about sharing or backup of app-bundle / split apk files, here .
This seems like an almost impossible task, which I coul
If you have root, you can use this code.
Please get the read/write sdcard permission.(via runtime permissions or permission granted from settings app) before executing this code. airbnb apk was successfully installed after running this code.
Calling this function with args "/split-apks/" , I have placed the airbnb split apks in a directory in /sdcard/split-apks/.
installApk("/split-apks/");
public void installApk(String apkFolderPath)
{
PackageInstaller packageInstaller = getPackageManager().getPackageInstaller();
HashMap nameSizeMap = new HashMap<>();
long totalSize = 0;
File folder = new File(Environment.getExternalStorageDirectory().getPath()+ apkFolderPath);
File[] listOfFiles = folder.listFiles();
for (int i = 0; i < listOfFiles.length; i++) {
if (listOfFiles[i].isFile()) {
System.out.println("File " + listOfFiles[i].getName());
nameSizeMap.put(listOfFiles[i].getName(),listOfFiles[i].length());
totalSize += listOfFiles[i].length();
}
}
String su = "/system/xbin/su";
final String[] pm_install_create = new String[]{su, "-c", "pm" ,"install-create", "-S", Long.toString(totalSize) };
execute(null, pm_install_create);
List sessions = packageInstaller.getAllSessions();
int sessId = sessions.get(0).getSessionId();
String sessionId = Integer.toString(sessId);
for(Map.Entry entry : nameSizeMap.entrySet())
{
String[] pm_install_write = new String[]{su, "-c", "pm" ,"install-write", "-S", Long.toString(entry.getValue()),sessionId, entry.getKey(), Environment.getExternalStorageDirectory().getPath()+apkFolderPath+ entry.getKey()};
execute(null,pm_install_write);
}
String[] pm_install_commit = new String[]{su, "-c", "pm" ,"install-commit", sessionId};
execute(null, pm_install_commit);
}
public String execute(Map environvenmentVars, String[] cmd) {
boolean DEBUG = true;
if (DEBUG)
Log.d("log","command is " + Arrays.toString(cmd));
try {
Process process = Runtime.getRuntime().exec(cmd);
if (DEBUG)
Log.d("log", "process is " + process);
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
if (DEBUG)
Log.d("log", "bufferreader is " + reader);
if (DEBUG)
Log.d("log", "readline " + reader.readLine());
StringBuffer output = new StringBuffer();
char[] buffer = new char[4096];
int read;
while ((read = reader.read(buffer)) > 0) {
output.append(buffer, 0, read);
}
reader.close();
process.waitFor();
if (DEBUG)
Log.d("log", output.toString());
return output.toString();
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
EDIT: same code, but in Kotlin, as it's shorter:
sample usage:
Foo.installApk(context,fullPathToSplitApksFolder)
Example:
AsyncTask.execute {
Foo.installApk(this@MainActivity,"/storage/emulated/0/Download/split")
}
Code:
object Foo {
@WorkerThread
@JvmStatic
fun installApk(context: Context, apkFolderPath: String) {
val packageInstaller = context.packageManager.packageInstaller
val nameSizeMap = HashMap()
var totalSize: Long = 0
val folder = File(apkFolderPath)
val listOfFiles = folder.listFiles().filter { it.isFile && it.name.endsWith(".apk") }
for (file in listOfFiles) {
Log.d("AppLog", "File " + file.name)
nameSizeMap[file] = file.length()
totalSize += file.length()
}
val su = "su"
val pmInstallCreate = arrayOf(su, "-c", "pm", "install-create", "-S", totalSize.toString())
execute(pmInstallCreate)
val sessions = packageInstaller.allSessions
val sessionId = Integer.toString(sessions[0].sessionId)
for ((file, value) in nameSizeMap) {
val pmInstallWrite = arrayOf(su, "-c", "pm", "install-write", "-S", value.toString(), sessionId, file.name, file.absolutePath)
execute(pmInstallWrite)
}
val pmInstallCommit = arrayOf(su, "-c", "pm", "install-commit", sessionId)
execute(pmInstallCommit)
}
@WorkerThread
@JvmStatic
private fun execute(cmd: Array): String? {
Log.d("AppLog", "command is " + Arrays.toString(cmd))
try {
val process = Runtime.getRuntime().exec(cmd)
Log.d("AppLog", "process is $process")
val reader = BufferedReader(InputStreamReader(process.inputStream))
Log.d("AppLog", "bufferreader is $reader")
Log.d("AppLog", "readline " + reader.readLine())
val output = StringBuilder()
val buffer = CharArray(4096)
var read: Int
while (true) {
read = reader.read(buffer)
if (read <= 0)
break
output.append(buffer, 0, read)
}
reader.close()
process.waitFor()
Log.d("AppLog", output.toString())
return output.toString()
} catch (e: Exception) {
e.printStackTrace()
}
return null
}
}