是否可以通过base64String API响应调用生成APK文件?

问题描述 投票:0回答:2

我目前正在研究如何以编程方式更新和安装APK文件的解决方案-非常类似于this问题。我的应用程序不使用 Google服务。

出于更新目的,具有递增版本的APK文件存储在内部服务器上,并且C#Web服务返回APK文件的最新版本。

我使用Retrofit2:

    @Streaming
    @GET("/ws/webservice.svc/getUpdate")
    fun getUpdate(
        @Query("Programm") program: String,
        @Query("version") version: String,
        @Query("test") test: Boolean
    ): Single<String>

和LiveData:

override fun getUpdate() {
        disposables += api.getUpdate(
            program = context.getString(R.string.app_name),
            version = context.getString(R.string.app_version),
            test = isTest
        )
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribeBy(
                onSuccess = {
                    liveData.value = GetUpdate(it)
                },
                onError = {
                    liveData.value = Error("Error getUpdate: " + it.message)
                }
            )
    }

我面临的问题是,该API调用的响应(这意味着-最新的APK文件)具有base64String表示形式,如下图所示-例如,这只是其中一部分在浏览器中调用API时的服务器响应。

APK file as String

下载后,是否可以通过某种方式从此String表示形式生成“真实的” APK文件,因此之后我可以将其安装在设备上了吗?我知道这很奇怪,但是客户希望我为此目的重复使用相同的Web服务。

我发现了类似的问题here。如何在Kotlin中完成?预先感谢。

android web-services kotlin apk
2个回答
1
投票

是,您需要将base64解码为ByteArray,然后将字节写入带有后缀.apk的位置。您所拥有的是一个String,其中使用bytes编码方案将encoded设为base64

由于您使用了kotlin,因此您可能会在这里看到如何从ByteArray!中获得String [1]。然后,只需确保您写入的文件具有.apk扩展名即可。

[1] https://developer.android.com/reference/kotlin/java/util/Base64.Decoder#decode(kotlin.String)


0
投票

这应该是这个问题的答案。由于硬件限制,我无法为我的项目使用代码-我在Zebra VC80x上使用了该代码-根据Zebra的说法,不可能在内部存储上写入数据-因此,我总是收到错误消息“ Permission否认”。但这也许会帮助别人...

AndroidManifest.xml

    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />

带有LiveData的MVVM:

    override fun getUpdate() {
        disposables += api.getUpdate(
            program = context.getString(R.string.app_name) + ".apk",
            version = context.getString(R.string.app_version),
            test = isTest
        )
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .map(::decodeToAPK)
            .subscribe({
                liveData.value = GetUpdate 
            }, {
                liveData.value = Error("Error getUpdate: " + it.message)
            })
    }


    private fun decodeToAPK(base64String: String) {

        val byteArrayAPK = Base64.decode(base64String, Base64.DEFAULT)

        val path = Environment.getExternalStorageDirectory().path
        Log.d(null, path)
        val dir = File(path)
        if (!dir.exists()) {
            dir.mkdirs()
            Log.d(null, "dir created")
        }
        val fullName = "$path/appName.apk"
        val file = File(fullName)
        Log.d(null, "fullname: $fullName not yet created")
        if (!file.exists()) {
            file.createNewFile()
            Log.d(null, "fullname: $fullName created")
        }

        if (byteArrayAPK.isNotEmpty()) {
            Log.d(null, "byteArrayAPK is not empty")
            try {
                val fileOutputStream = FileOutputStream(file)
                Log.d(null, "init FileOutputStream")
                fileOutputStream.write(byteArrayAPK)
                fileOutputStream.close()
                Log.d(null, "fileOutputStream.close() $file")
            } catch (e: UnsupportedEncodingException) {
                Log.d(null, "FileOutputStream error")
                e.printStackTrace()
            }
        }

sealed class SomeAction : Action {
    data class Error(val message: String) : SomeAction()
    object GetUpdate : SomeAction()
}
© www.soinside.com 2019 - 2024. All rights reserved.