mirror of
https://github.com/izzy2lost/aab2apk.git
synced 2026-06-19 01:20:08 -07:00
Added Device ID option to build apk for particular Serial ID
This commit is contained in:
@@ -89,6 +89,8 @@ fun App(fileStorageHelper: FileStorageHelper, savedPath: String?, adbSavedPath:
|
||||
var isAdbSetupDone by remember { mutableStateOf(false) }
|
||||
var adbPath by remember { mutableStateOf("") }
|
||||
var showLoadingDialog by remember { mutableStateOf(Pair("", false)) }
|
||||
var isDeviceIdEnabled by remember { mutableStateOf(false) }
|
||||
var deviceSerialId by remember { mutableStateOf("") }
|
||||
|
||||
// TODO: (Fixed this issue need to test more!) - Can't update file path once saved, For now Delete path.kb file inside storage directory.
|
||||
savedJarPath?.let {
|
||||
@@ -420,6 +422,56 @@ fun App(fileStorageHelper: FileStorageHelper, savedPath: String?, adbSavedPath:
|
||||
Strings.AUTO_UNZIP
|
||||
)
|
||||
Spacer(modifier = Modifier.padding(8.dp))
|
||||
if (isAdbSetupDone) {
|
||||
Text(
|
||||
text = Strings.DEVICE_OPTIONS,
|
||||
style = Styles.TextStyleBold(16.sp),
|
||||
modifier = Modifier.padding(start = 16.dp, top = 8.dp, end = 16.dp, bottom = 8.dp)
|
||||
)
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
CheckboxWithText(
|
||||
Strings.DEVICE_ID,
|
||||
isDeviceIdEnabled,
|
||||
onCheckedChange = {
|
||||
isDeviceIdEnabled = it
|
||||
},
|
||||
Strings.DEVICE_ID_INFO
|
||||
)
|
||||
if (isDeviceIdEnabled) {
|
||||
CustomTextField(
|
||||
deviceSerialId,
|
||||
Strings.SERIAL_ID,
|
||||
forPassword = false,
|
||||
onValueChange = {
|
||||
deviceSerialId = it
|
||||
}
|
||||
)
|
||||
ButtonWithToolTip(
|
||||
Strings.FETCH_DEVICES,
|
||||
onClick = {
|
||||
CommandExecutor()
|
||||
.executeCommand(
|
||||
CommandBuilder()
|
||||
.getAdbFetchCommand(adbSavedPath!!),
|
||||
coroutineScope,
|
||||
onSuccess = {
|
||||
logs += it
|
||||
},
|
||||
onFailure = {
|
||||
logs += it.printStackTrace()
|
||||
}
|
||||
)
|
||||
},
|
||||
Strings.FETCH_DEVICES_INFO,
|
||||
icon = "device_fetch"
|
||||
)
|
||||
}
|
||||
}
|
||||
Spacer(modifier = Modifier.padding(8.dp))
|
||||
}
|
||||
if (isLoading) {
|
||||
CircularProgressIndicator(
|
||||
modifier = Modifier.size(size = 40.dp)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package command
|
||||
|
||||
import utils.SigningMode
|
||||
import utils.Utils
|
||||
|
||||
class CommandBuilder {
|
||||
private var bundletoolPath: String = ""
|
||||
@@ -16,6 +15,8 @@ class CommandBuilder {
|
||||
private var keyAlias: String = ""
|
||||
private var keyPassword: String = ""
|
||||
private var adbVerifyCommandExecute = Pair(false, "")
|
||||
private var isDeviceIdEnabled: Boolean = false
|
||||
private var adbSerialId: String = ""
|
||||
|
||||
fun bundletoolPath(path: String) = apply { this.bundletoolPath = path }
|
||||
fun aabFilePath(path: Pair<String, String>) = apply { this.aabFilePath = path }
|
||||
@@ -31,6 +32,10 @@ class CommandBuilder {
|
||||
|
||||
fun verifyAdbPath(value: Boolean, path: String) = apply { this.adbVerifyCommandExecute = Pair(value, path) }
|
||||
|
||||
fun isDeviceSerialIdEnabled(value: Boolean) = apply { this.isDeviceIdEnabled = value }
|
||||
|
||||
fun adbSerialId(value: String) = apply { this.adbSerialId = value }
|
||||
|
||||
fun getAdbVerifyCommand(): String {
|
||||
val (forVerify, path) = adbVerifyCommandExecute
|
||||
if (forVerify) {
|
||||
@@ -39,6 +44,10 @@ class CommandBuilder {
|
||||
return ""
|
||||
}
|
||||
|
||||
fun getAdbFetchCommand(adbPath: String): String {
|
||||
return "\"${adbPath}\" devices"
|
||||
}
|
||||
|
||||
fun validateAndGetCommand(): Pair<String, Boolean> {
|
||||
if (bundletoolPath.isEmpty()) {
|
||||
return Pair("bundletoolPath", false)
|
||||
@@ -52,36 +61,40 @@ class CommandBuilder {
|
||||
if (signingMode == SigningMode.RELEASE && (keyStorePath.isEmpty() || keyStorePassword.isEmpty() || keyAlias.isEmpty() || keyPassword.isEmpty())) {
|
||||
return Pair("Check Keystore Info!", false)
|
||||
}
|
||||
if (isDeviceIdEnabled && adbSerialId.isEmpty()) {
|
||||
return Pair("Invalid Serial ID", false)
|
||||
}
|
||||
return Pair(getCommand(), true)
|
||||
}
|
||||
|
||||
private fun getCommand(): String {
|
||||
val commandBuilder = StringBuilder()
|
||||
if (Utils.isWindowsOS()) {
|
||||
commandBuilder.append("java -jar \"${bundletoolPath}\" build-apks ")
|
||||
if (isUniversalMode) {
|
||||
commandBuilder.append("--mode=universal ")
|
||||
}
|
||||
if (isOverwrite) {
|
||||
commandBuilder.append("--overwrite ")
|
||||
}
|
||||
if (isAapt2PathEnabled) {
|
||||
commandBuilder.append("--aapt2=\"$aapt2Path\" ")
|
||||
}
|
||||
commandBuilder.append(
|
||||
"--bundle=\"${aabFilePath.first}${aabFilePath.second}\" --output=\"${aabFilePath.first}${
|
||||
aabFilePath.second.split(
|
||||
"."
|
||||
)[0]
|
||||
}.apks\" "
|
||||
)
|
||||
|
||||
if (signingMode == SigningMode.RELEASE) {
|
||||
commandBuilder.append("--ks=$keyStorePath --ks-pass=pass:$keyStorePassword --ks-key-alias=$keyAlias --key-pass=pass:$keyPassword ")
|
||||
}
|
||||
|
||||
return commandBuilder.toString()
|
||||
commandBuilder.append("java -jar \"${bundletoolPath}\" build-apks ")
|
||||
if (isUniversalMode) {
|
||||
commandBuilder.append("--mode=universal ")
|
||||
}
|
||||
return ""
|
||||
if (isOverwrite) {
|
||||
commandBuilder.append("--overwrite ")
|
||||
}
|
||||
if (isAapt2PathEnabled) {
|
||||
commandBuilder.append("--aapt2=\"$aapt2Path\" ")
|
||||
}
|
||||
commandBuilder.append(
|
||||
"--bundle=\"${aabFilePath.first}${aabFilePath.second}\" --output=\"${aabFilePath.first}${
|
||||
aabFilePath.second.split(
|
||||
"."
|
||||
)[0]
|
||||
}.apks\" "
|
||||
)
|
||||
|
||||
if (signingMode == SigningMode.RELEASE) {
|
||||
commandBuilder.append("--ks=$keyStorePath --ks-pass=pass:$keyStorePassword --ks-key-alias=$keyAlias --key-pass=pass:$keyPassword ")
|
||||
}
|
||||
|
||||
if (isDeviceIdEnabled) {
|
||||
commandBuilder.append("--device-id=$adbSerialId ")
|
||||
}
|
||||
|
||||
return commandBuilder.toString()
|
||||
}
|
||||
}
|
||||
@@ -36,6 +36,9 @@ object Strings {
|
||||
const val ABD_SETUP_DONE = "Adb Connected"
|
||||
const val SETUP_ADB_INFO = "Setup ADB path to create builds based on connected device"
|
||||
const val DEVICE_ID = "Device Id"
|
||||
const val DEVICE_ID_INFO = "Device Id based on the Serial Number"
|
||||
const val DEVICE_ID_INFO = "Device Id based on the Serial Number. Use with Mode Universal to get one apk."
|
||||
const val VERIFYING_ADB_PATH = "Verifying ADB Path.."
|
||||
const val SERIAL_ID = "Serial Id"
|
||||
const val FETCH_DEVICES = "Fetch Devices"
|
||||
const val FETCH_DEVICES_INFO = "Fetch Connected Devices Info in LogView"
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M480-120q-138 0-240.5-91.5T122-440h82q14 104 92.5 172T480-200q117 0 198.5-81.5T760-480q0-117-81.5-198.5T480-760q-69 0-129 32t-101 88h110v80H120v-240h80v94q51-64 124.5-99T480-840q75 0 140.5 28.5t114 77q48.5 48.5 77 114T840-480q0 75-28.5 140.5t-77 114q-48.5 48.5-114 77T480-120Zm112-192L440-464v-216h80v184l128 128-56 56Z"/></svg>
|
||||
|
After Width: | Height: | Size: 425 B |
@@ -56,6 +56,7 @@ class CommandBuilderTest {
|
||||
.keyAlias("keyAlias")
|
||||
.keyPassword("keyPassword")
|
||||
.isUniversalMode(false).validateAndGetCommand()
|
||||
println(result)
|
||||
assertEquals(
|
||||
"java -jar \"bundletool.jar\" build-apks --bundle=\"/path/to/file.aab\" --output=\"/path/to/file.apks\" --ks=/path/to/keystore.jks --ks-pass=pass:keystorePassword --ks-key-alias=keyAlias --key-pass=pass:keyPassword ",
|
||||
result.first
|
||||
@@ -71,6 +72,7 @@ class CommandBuilderTest {
|
||||
.signingMode(SigningMode.DEBUG)
|
||||
.isUniversalMode(false)
|
||||
.validateAndGetCommand()
|
||||
println(result)
|
||||
assertEquals(
|
||||
"java -jar \"bundletool.jar\" build-apks --bundle=\"/path/to/file.aab\" --output=\"/path/to/file.apks\" ",
|
||||
result.first
|
||||
@@ -93,6 +95,7 @@ class CommandBuilderTest {
|
||||
.aabFilePath(Pair("/path/to/", "file.aab"))
|
||||
.isUniversalMode(true)
|
||||
.validateAndGetCommand()
|
||||
println(result)
|
||||
assertEquals(
|
||||
"java -jar \"bundletool.jar\" build-apks --mode=universal --bundle=\"/path/to/file.aab\" --output=\"/path/to/file.apks\" ",
|
||||
result.first
|
||||
@@ -107,10 +110,46 @@ class CommandBuilderTest {
|
||||
.aabFilePath(Pair("/path/to/", "file.aab"))
|
||||
.isOverwrite(true)
|
||||
.isUniversalMode(false).validateAndGetCommand()
|
||||
println(result)
|
||||
assertEquals(
|
||||
"java -jar \"bundletool.jar\" build-apks --overwrite --bundle=\"/path/to/file.aab\" --output=\"/path/to/file.apks\" ",
|
||||
result.first
|
||||
)
|
||||
assertEquals(true, result.second)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `validateAndGetCommand should return error when device id enabled but serial id is empty`() {
|
||||
val result = CommandBuilder()
|
||||
.bundletoolPath("bundletool.jar")
|
||||
.aabFilePath(Pair("/path/to/", "file.aab"))
|
||||
.isOverwrite(false)
|
||||
.isUniversalMode(false)
|
||||
.isDeviceSerialIdEnabled(true)
|
||||
.adbSerialId("")
|
||||
.validateAndGetCommand()
|
||||
assertEquals(
|
||||
"Invalid Serial ID",
|
||||
result.first
|
||||
)
|
||||
assertEquals(false, result.second)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `validateAndGetCommand should return valid command with device id enabled`() {
|
||||
val result = CommandBuilder()
|
||||
.bundletoolPath("bundletool.jar")
|
||||
.aabFilePath(Pair("/path/to/", "file.aab"))
|
||||
.isOverwrite(false)
|
||||
.isUniversalMode(false)
|
||||
.isDeviceSerialIdEnabled(true)
|
||||
.adbSerialId("RZCWC0EZLEH")
|
||||
.validateAndGetCommand()
|
||||
println(result)
|
||||
assertEquals(
|
||||
"java -jar \"bundletool.jar\" build-apks --bundle=\"/path/to/file.aab\" --output=\"/path/to/file.apks\" --device-id=RZCWC0EZLEH ",
|
||||
result.first
|
||||
)
|
||||
assertEquals(true, result.second)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
package command
|
||||
|
||||
import junit.framework.TestCase.assertTrue
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.hamcrest.MatcherAssert.assertThat
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
|
||||
class CommandExecutorTest {
|
||||
private lateinit var commandExecutor: CommandExecutor
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
commandExecutor = CommandExecutor()
|
||||
}
|
||||
|
||||
// These test cases may not work for MAC and Linux need to verify.
|
||||
@Test
|
||||
fun `execute valid command successfully`() {
|
||||
val expectedOutput = "openjdk 11.0.18 2023-01-17"
|
||||
val cmd = "java --version"
|
||||
|
||||
runBlocking {
|
||||
commandExecutor.executeCommand(
|
||||
cmd,
|
||||
this,
|
||||
onSuccess = {
|
||||
println("SUCCESS -> $it")
|
||||
assertThat(expectedOutput, it.contains(expectedOutput))
|
||||
},
|
||||
onFailure = {
|
||||
println("ERROR -> ${it.message}")
|
||||
assertThat(expectedOutput, it.message?.contains(expectedOutput) ?: false)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `execute invalid command and handle failure`() {
|
||||
val cmd = "invalid_command"
|
||||
runBlocking {
|
||||
commandExecutor.executeCommand(
|
||||
cmd,
|
||||
this,
|
||||
onSuccess = {
|
||||
assertTrue(it.isEmpty())
|
||||
},
|
||||
onFailure = {
|
||||
assertTrue(it.message?.contains("The system cannot find the file specified") ?: false)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user