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
No root required implementation Check this git hub link: https://github.com/nkalra0123/splitapkinstall
We have to create a service and pass that handle in session.commit()
Intent callbackIntent = new Intent(getApplicationContext(), APKInstallService.class);
PendingIntent pendingIntent = PendingIntent.getService(getApplicationContext(), 0, callbackIntent, 0);
session.commit(pendingIntent.getIntentSender());
EDIT: Since the solution works, but not really published here, I've decided to write it before marking it as correct solution. Here's the code:
manifest
APKInstallService
class APKInstallService : Service() {
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
when (if (intent.hasExtra(PackageInstaller.EXTRA_STATUS)) null else intent.getIntExtra(PackageInstaller.EXTRA_STATUS, 0)) {
PackageInstaller.STATUS_PENDING_USER_ACTION -> {
Log.d("AppLog", "Requesting user confirmation for installation")
val confirmationIntent = intent.getParcelableExtra(Intent.EXTRA_INTENT)
confirmationIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
try {
startActivity(confirmationIntent)
} catch (e: Exception) {
}
}
PackageInstaller.STATUS_SUCCESS -> Log.d("AppLog", "Installation succeed")
else -> Log.d("AppLog", "Installation failed")
}
stopSelf()
return START_NOT_STICKY
}
override fun onBind(intent: Intent): IBinder? {
return null
}
}
MainActivity
class MainActivity : AppCompatActivity() {
private lateinit var packageInstaller: PackageInstaller
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val toolbar = findViewById(R.id.toolbar)
setSupportActionBar(toolbar)
val fab = findViewById(R.id.fab)
fab.setOnClickListener {
packageInstaller = packageManager.packageInstaller
val ret = installApk("/storage/emulated/0/Download/split/")
Log.d("AppLog", "onClick: return value is $ret")
}
}
private fun installApk(apkFolderPath: String): Int {
val nameSizeMap = HashMap()
var totalSize: Long = 0
var sessionId = 0
val folder = File(apkFolderPath)
val listOfFiles = folder.listFiles()
try {
for (listOfFile in listOfFiles) {
if (listOfFile.isFile) {
Log.d("AppLog", "installApk: " + listOfFile.name)
nameSizeMap[listOfFile.name] = listOfFile.length()
totalSize += listOfFile.length()
}
}
} catch (e: Exception) {
e.printStackTrace()
return -1
}
val installParams = PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL)
installParams.setSize(totalSize)
try {
sessionId = packageInstaller.createSession(installParams)
Log.d("AppLog","Success: created install session [$sessionId]")
for ((key, value) in nameSizeMap) {
doWriteSession(sessionId, apkFolderPath + key, value, key)
}
doCommitSession(sessionId)
Log.d("AppLog","Success")
} catch (e: IOException) {
e.printStackTrace()
}
return sessionId
}
private fun doWriteSession(sessionId: Int, inPath: String?, sizeBytes: Long, splitName: String): Int {
var inPathToUse = inPath
var sizeBytesToUse = sizeBytes
if ("-" == inPathToUse) {
inPathToUse = null
} else if (inPathToUse != null) {
val file = File(inPathToUse)
if (file.isFile)
sizeBytesToUse = file.length()
}
var session: PackageInstaller.Session? = null
var inputStream: InputStream? = null
var out: OutputStream? = null
try {
session = packageInstaller.openSession(sessionId)
if (inPathToUse != null) {
inputStream = FileInputStream(inPathToUse)
}
out = session!!.openWrite(splitName, 0, sizeBytesToUse)
var total = 0
val buffer = ByteArray(65536)
var c: Int
while (true) {
c = inputStream!!.read(buffer)
if (c == -1)
break
total += c
out!!.write(buffer, 0, c)
}
session.fsync(out!!)
Log.d("AppLog", "Success: streamed $total bytes")
return PackageInstaller.STATUS_SUCCESS
} catch (e: IOException) {
Log.e("AppLog", "Error: failed to write; " + e.message)
return PackageInstaller.STATUS_FAILURE
} finally {
try {
out?.close()
inputStream?.close()
session?.close()
} catch (e: IOException) {
e.printStackTrace()
}
}
}
private fun doCommitSession(sessionId: Int) {
var session: PackageInstaller.Session? = null
try {
try {
session = packageInstaller.openSession(sessionId)
val callbackIntent = Intent(applicationContext, APKInstallService::class.java)
val pendingIntent = PendingIntent.getService(applicationContext, 0, callbackIntent, 0)
session!!.commit(pendingIntent.intentSender)
session.close()
Log.d("AppLog", "install request sent")
Log.d("AppLog", "doCommitSession: " + packageInstaller.mySessions)
Log.d("AppLog", "doCommitSession: after session commit ")
} catch (e: IOException) {
e.printStackTrace()
}
} finally {
session!!.close()
}
}
}