Fixed, Unable to upload APK on play store for new apps.

* We have implemented Play Asset Delivery to include the ZIM file within the Android App Bundle (AAB).
* To achieve this, we've created Gradle tasks to automatically download the ZIM file and place it inside the assets folder.
* In order to utilize this asset file, we've refactored our custom application code.
* We haven't removed the functionality of uploading the APK, as this approach remains static for now. Thus, we are retaining both codebases.
This commit is contained in:
MohitMali 2023-10-16 19:41:11 +05:30
parent 3a47ae601a
commit 4c951de69e
6 changed files with 147 additions and 2 deletions

View File

@ -100,6 +100,14 @@ class Transaction(
).execute().prettyPrint()
}
fun uploadBundle(file: File) {
publisher.edits().apks().upload(
packageName,
editId,
FileContent("application/octet-stream", file)
).execute().prettyPrint()
}
@Suppress("DEPRECATION")
fun addToTrackInDraft(apkVariants: List<ApkVariantOutput>): Track =
publisher.edits().tracks().update(packageName, editId, "internal", Track().apply {
@ -110,6 +118,17 @@ class Transaction(
})
track = "internal"
}).execute().prettyPrint()
@Suppress("DEPRECATION")
fun addBundleToTrackInDraft(versionCode: Int, versionName: String?): Track =
publisher.edits().tracks().update(packageName, editId, "internal", Track().apply {
releases = listOf(TrackRelease().apply {
status = "draft"
name = versionName
versionCodes = listOf(versionCode.toLong())
})
track = "internal"
}).execute().prettyPrint()
}
fun AndroidPublisher.transactionWithCommit(packageName: String, func: Transaction.() -> Unit) {

View File

@ -13,6 +13,7 @@ import java.io.FileOutputStream
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.ResponseBody
import java.io.FileNotFoundException
plugins {
android
@ -33,8 +34,13 @@ android {
createDownloadTask(it)
createPublishApkWithExpansionTask(it, applicationVariants)
}
File("$projectDir/../install_time_asset_for_dwds/src/main/assets", "$name.zim").let {
createDownloadTaskForPlayAssetDelivery(it)
createPublishBundleWithAssetPlayDelivery(applicationVariants)
}
}
}
bundle {
language {
// This is for testing the bundle file for the play store
@ -42,6 +48,12 @@ android {
enableSplit = false
}
}
splits {
abi {
isUniversalApk = true
}
}
assetPacks += ":install_time_asset_for_dwds"
}
fun ProductFlavor.createDownloadTask(file: File): Task {
@ -105,6 +117,38 @@ fun writeZimFileData(responseBody: ResponseBody, file: File) {
}
}
fun ProductFlavor.createDownloadTaskForPlayAssetDelivery(
file: File
): Task {
return tasks.create(
"download${
name.replaceFirstChar {
if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else "$it"
}
}ZimAndPutInAssetFolder"
) {
group = "Downloading"
doLast {
if (!file.exists()) {
file.createNewFile()
OkHttpClient().newCall(fetchRequest()).execute().use { response ->
if (response.isSuccessful) {
response.body?.let { responseBody ->
writeZimFileData(responseBody, file)
}
} else {
throw RuntimeException(
"Download Failed. Error: ${response.message}\n" +
" Status Code: ${response.code}"
)
}
}
}
}
}
}
val String.decodeUrl: String
get() = URLDecoder.decode(this, "UTF-8")
val String.isAuthenticationUrl: Boolean
@ -149,6 +193,37 @@ fun DomainObjectSet<ApplicationVariant>.releaseVariantsFor(productFlavor: Produc
find { it.name.equals("${productFlavor.name}Release", true) }!!
.outputs.filterIsInstance<ApkVariantOutput>().sortedBy { it.versionCodeOverride }
fun ProductFlavor.createPublishBundleWithAssetPlayDelivery(
applicationVariants: DomainObjectSet<ApplicationVariant>
): Task {
val capitalizedName =
name.replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else "$it" }
return tasks.create("publish${capitalizedName}ReleaseBundleWithPlayAssetDelivery") {
group = "publishing"
description = "Uploads $capitalizedName to the Play Console with an Expansion file"
doLast {
val packageName = "org.kiwix$applicationIdSuffix"
println("packageName $packageName")
createPublisher(File(rootDir, "playstore.json"))
.transactionWithCommit(packageName) {
val variants =
applicationVariants.releaseVariantsFor(this@createPublishBundleWithAssetPlayDelivery)
val generatedBundleFile =
File(
"$buildDir/outputs/bundle/${capitalizedName.lowercase(Locale.getDefault())}" +
"Release/custom-${capitalizedName.lowercase(Locale.getDefault())}-release.aab"
)
if (generatedBundleFile.exists()) {
uploadBundle(generatedBundleFile)
addBundleToTrackInDraft(variants[0].versionCode, versionName)
} else {
throw FileNotFoundException("Unable to find generated aab file")
}
}
}
}
}
afterEvaluate {
tasks.filter { it.name.contains("ReleaseApkWithExpansionFile") }.forEach {
val flavorName =
@ -156,4 +231,10 @@ afterEvaluate {
it.dependsOn.add(tasks.getByName("download${flavorName}Zim"))
it.dependsOn.add(tasks.getByName("assemble${flavorName}Release"))
}
tasks.filter { it.name.contains("ReleaseBundleWithPlayAssetDelivery") }.forEach {
val flavorName =
it.name.substringAfter("publish").substringBefore("ReleaseBundleWithPlayAssetDelivery")
it.dependsOn.add(tasks.getByName("download${flavorName}ZimAndPutInAssetFolder"))
it.dependsOn.add(tasks.getByName("bundle${flavorName}Release"))
}
}

View File

@ -19,11 +19,15 @@
package org.kiwix.kiwixmobile.custom.main
import android.content.Context
import android.content.pm.PackageManager
import android.util.Log
import androidx.core.content.ContextCompat
import org.kiwix.kiwixmobile.custom.main.ValidationState.HasBothFiles
import org.kiwix.kiwixmobile.custom.main.ValidationState.HasFile
import org.kiwix.kiwixmobile.custom.main.ValidationState.HasNothing
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import javax.inject.Inject
class CustomFileValidator @Inject constructor(private val context: Context) {
@ -37,16 +41,48 @@ class CustomFileValidator @Inject constructor(private val context: Context) {
private fun detectInstallationState(
obbFiles: List<File> = obbFiles(),
zimFiles: List<File> = zimFiles()
zimFiles: List<File> = zimFiles(),
assetFile: File? = getFileFromPlayAssetDelivery()
): ValidationState {
return when {
obbFiles.isNotEmpty() && zimFiles().isNotEmpty() -> HasBothFiles(obbFiles[0], zimFiles[0])
obbFiles.isNotEmpty() -> HasFile(obbFiles[0])
zimFiles.isNotEmpty() -> HasFile(zimFiles[0])
assetFile != null -> HasFile(assetFile)
else -> HasNothing
}
}
@Suppress("NestedBlockDepth", "MagicNumber")
private fun getFileFromPlayAssetDelivery(): File? {
var zimFile: File? = null
try {
val context = context.createPackageContext(context.packageName, 0)
val assetManager = context.assets
val inputStream = assetManager.open("dwds_de_dictionary_nopic_2023-09-12.zim")
val filePath = ContextCompat.getExternalFilesDirs(context, null)[0]
zimFile = File(filePath, "dwds_de_dictionary_nopic_2023-09-12.zim")
FileOutputStream(zimFile).use { outputSteam ->
inputStream.use { inputStream ->
val buffer = ByteArray(1024)
var length: Int
while (inputStream.read(buffer).also { length = it } > 0) {
outputSteam.write(buffer, 0, length)
}
outputSteam.flush()
}
}
} catch (packageNameNotFoundException: PackageManager.NameNotFoundException) {
Log.w(
"ASSET_PACKAGE_DELIVERY",
"Asset package is not found ${packageNameNotFoundException.message}"
)
} catch (ioException: IOException) {
Log.w("ASSET_PACKAGE_DELIVERY", "Unable to copy the content of asset ${ioException.message}")
}
return zimFile
}
private fun obbFiles() = scanDirs(ContextCompat.getObbDirs(context), "obb")
private fun zimFiles(): List<File> {

View File

@ -0,0 +1,8 @@
apply plugin: 'com.android.asset-pack'
assetPack {
packName = "install_time_asset_for_dwds" // Directory name for the asset pack
dynamicDelivery {
deliveryType = "install-time" // delivery mode
}
}

View File

@ -1,6 +1,7 @@
include(
":core",
":app",
":custom"
":custom",
":install_time_asset_for_dwds"
)
rootProject.name = "kiwix-android"