Это код, который я использую для обновления моего приложения с настроенным CDN (я думаю, он также называется настроенным приложением, которое используется в частном порядке).
private fun downloadApk(url: String) {
forceUpdateDialog?.dismiss()
// instantiate it within the onCreate method
mProgressDialog = ProgressDialog(this)
mProgressDialog!!.setMessage("Downloading new version...")
mProgressDialog!!.isIndeterminate = true
mProgressDialog!!.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL)
mProgressDialog!!.setCancelable(false)
mProgressDialog!!.window!!.requestFeature(Window.FEATURE_NO_TITLE)
// mProgressDialog!!.window!!.setBackgroundDrawableResource(android.R.color.transparent)
mProgressDialog!!.setCanceledOnTouchOutside(false)
mProgressDialog!!.setOnCancelListener {
// TODO: nothing
}
// execute this when the downloader must be fired
val downloadTask = DownloadTask(this) // DownloadTask
downloadTask.execute(url)
mProgressDialog!!.setOnCancelListener {
downloadTask.cancel(true) //cancel the task
}
}
private class DownloadTask(context: Context) : AsyncTask<String, Int, String?>() {
var context: Context? = context
var mWakeLock: PowerManager.WakeLock? = null
//set destination
val fileName = NetworkConstants.APK_NAME
var destination = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
"${context.getExternalFilesDir(null)}/$fileName"
} else {
"${Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)}/$fileName"
}
override fun doInBackground(vararg params: String?): String? {
var input: InputStream? = null
var output: OutputStream? = null
var connection: HttpURLConnection? = null
try {
val url = URL(params[0])
connection = url.openConnection() as HttpURLConnection
connection.connect()
// expect HTTP 200 OK, so we don't mistakenly save error report
// instead of the file
if (connection.responseCode != HttpURLConnection.HTTP_OK) {
return "Server returned HTTP ${connection.responseCode}\n${connection.responseMessage}"
}
// this will be useful to display download percentage
// might be -1: server did not report the length
val fileLength = connection.contentLength
// download the file
input = connection.inputStream
output = FileOutputStream(destination)
val data = ByteArray(4096)
var total = 0
var count = 0
while ({ count = input.read(data); count }() != -1) {
// allow canceling with back button
if (isCancelled) {
input.close()
return null
}
total += count
// publishing the progress....
if (fileLength > 0) // only if total length is known
publishProgress((total * 100 / fileLength))
output.write(data, 0, count)
}
} catch (e: Exception) {
return e.toString()
} finally {
try {
output?.close()
input?.close()
} catch (e: IOException) {
e.printStackTrace()
}
connection?.disconnect()
}
return null
}
override fun onProgressUpdate(vararg values: Int?) {
super.onProgressUpdate(*values)
// if we get here, length is known, now set indeterminate to false
mProgressDialog!!.isIndeterminate = false
mProgressDialog!!.max = 100
mProgressDialog!!.progress = values[0] as Int
}
override fun onPreExecute() {
super.onPreExecute()
// take CPU lock to prevent CPU from going off if the user
// presses the power button during download
val pm = context!!.getSystemService(Context.POWER_SERVICE) as PowerManager
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, javaClass.name)
mWakeLock!!.acquire() // no need to set time
mProgressDialog!!.show()
deleteApk()
}
override fun onPostExecute(result: String?) {
mWakeLock?.release()
mProgressDialog?.dismiss()
if (result != null) {
Toast.makeText(context, "Update Failed: $result", Toast.LENGTH_LONG).show()
(context as LoginActivity).finish()
} else {
Toast.makeText(context, "Updating...", Toast.LENGTH_SHORT).show()
val file = File(destination)
installApk(file)
}
}
fun installApk(file: File) {
val uri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
Log.d("test", BuildConfig.APPLICATION_ID)
FileProvider.getUriForFile(
context!!,
"${BuildConfig.APPLICATION_ID}.fileprovider",
file
)
} else {
Uri.fromFile(file)
}
val intent = Intent(Intent.ACTION_VIEW).apply {
setDataAndType(uri, "application/vnd.android.package-archive")
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
}
context!!.startActivity(intent)
(context as LoginActivity).overridePendingTransition(
R.anim.abc_fade_in,
R.anim.abc_fade_out
)
(context as LoginActivity).finish()
}
/**
* Delete my apk for
*/
private fun deleteApk() {
val fileName = NetworkConstants.APK_NAME
val destination = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
"${context!!.getExternalFilesDir(null)}/$fileName"
} else {
"${Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)}/$fileName"
}
val file = File(destination)
if (file.exists()) {
file.delete()
}
}
}
APP_NAME
- это например my_app.apk.
В первый раз обновляется хорошо. Однако, начиная со второго обновления, он повторяет то же действие (появляется диалоговое окно принудительного выполнения> загрузка> успешное обновление> та же версия> принудительное обновление> ... X 00)
Итак, я подумал, что это потому, что apk дублируется. Итак, я попытался удалить apk всякий раз, когда приложение открывает что-то вроде этого.
override onCreate(){
super.onCreate()
deleteApk()
}
Однако это то же самое. Итак, я думаю, это из-за S3? как проблема с кешем? Или я могу управлять этим из Манифеста? Я вижу атрибут allowBackup
. И я изменил его на false. Похоже, это не работает. Что я могу сделать?