Auto-Installation von Updates für < Android 10

master
Niko Diamadis 6 years ago
parent 840873a965
commit dfd02f272e

@ -38,6 +38,16 @@
<meta-data
android:name="firebase_analytics_collection_enabled"
android:value="false" />
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths" />
</provider>
</application>
</manifest>

@ -22,7 +22,6 @@ import com.androidnetworking.interfaces.StringRequestListener
import com.cyb3rko.techniklogger.recycler.ProjectEntryViewHolder
import com.cyb3rko.techniklogger.recycler.ProjectViewState
import com.cyb3rko.techniklogger.utils.About
import com.cyb3rko.techniklogger.utils.Updater
import com.google.firebase.database.*
import es.dmoral.toasty.Toasty
import kotlinx.android.synthetic.main.activity_main.*
@ -238,10 +237,7 @@ class MainActivity : AppCompatActivity() {
if (BuildConfig.VERSION_CODE != neuesterVersionCode) {
Log.d(this@MainActivity.toString(), "Update verfügbar: ${sharedPref.getString("neuesteVersion", "")}")
val updateDialog = Updater()
updateDialog.isCancelable = false
updateDialog.show(supportFragmentManager, "Update-Dialog")
updateCheck(this@MainActivity)
ActivityCompat.requestPermissions(
this@MainActivity, arrayOf(

@ -0,0 +1,120 @@
package com.cyb3rko.techniklogger
import android.Manifest
import android.app.DownloadManager
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.util.Base64
import android.util.Log
import android.webkit.URLUtil
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.core.content.FileProvider
import com.afollestad.materialdialogs.MaterialDialog
import com.androidnetworking.AndroidNetworking
import com.androidnetworking.error.ANError
import com.androidnetworking.interfaces.StringRequestListener
import es.dmoral.toasty.Toasty
import java.io.File
import java.nio.charset.StandardCharsets
internal fun updateCheck(activity: MainActivity) {
AndroidNetworking.initialize(activity)
AndroidNetworking.get("https://git.aldiserver.de/api/v1/repos/niko/technik-logger-app/contents/app/build.gradle")
.addHeaders("Authorization", "token d70a26aa455b25e60885ba5ff31cce231d454f82")
.doNotCacheResponse()
.build()
.getAsString(object : StringRequestListener {
override fun onResponse(response: String?) {
var parts = response!!.split("content\":\"".toRegex()).toTypedArray()
var parts2 = parts[1].split("\",\"target".toRegex()).toTypedArray()
val content = String(Base64.decode(parts2[0], Base64.DEFAULT), StandardCharsets.UTF_8)
parts = content.split("versionCode ".toRegex()).toTypedArray()
parts2 = parts[1].split("\n".toRegex()).toTypedArray()
val neuesterVersionCode = parts2[0].toInt()
parts = parts2[1].split("\"".toRegex()).toTypedArray()
parts2 = parts[1].split("\"".toRegex()).toTypedArray()
val newestVersion = parts2[0]
if (BuildConfig.VERSION_CODE != neuesterVersionCode) {
Log.d("Technik-Logger Updater", "Update verfügbar: $newestVersion")
showDownloadDialog(activity, newestVersion)
ActivityCompat.requestPermissions(
activity, arrayOf(
Manifest.permission.INTERNET, Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.REQUEST_INSTALL_PACKAGES
), 1
)
} else {
Log.d(activity.toString(), "App auf dem neuesten Stand")
}
}
override fun onError(anError: ANError?) {
Log.d(activity.toString(), "Update-Abfrage fehlgeschlagen: ${anError!!.errorBody.trimIndent()}")
}
})
}
internal fun showDownloadDialog(context: Context, newestVersion: String) {
MaterialDialog(context).show {
title(0, "Neues Update verfügbar")
message(0, "Das Update '$newestVersion' steht zum Download bereit!\n\nAktuell installierte Version: '${BuildConfig.VERSION_NAME}'")
positiveButton(0, "Herunterladen") {
downloadApk(context, newestVersion)
}
}
}
private fun downloadApk(context: Context, newestVersion: String) {
if (ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
val link = "https://cdn.cyb3rko.de/Apps/Technik-Logger/Technik-Logger%20v$newestVersion.apk"
println("$newestVersion: $link")
val request = DownloadManager.Request(Uri.parse(link))
.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, URLUtil.guessFileName(link, null, null))
.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
val downloadManager = context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
downloadManager.enqueue(request)
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
val onCompleteReceiver = object: BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
val apkPath = "${Environment.getExternalStorageDirectory()}/download/Technik-Logger v$newestVersion.apk"
val file = File(apkPath)
installBelowAndroid10(context!!, file, this)
}
}
context.registerReceiver(onCompleteReceiver, IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE))
}
} else {
Toasty.error(context, "Fehlende Berechtigung, erteilen Sie diese beim nächsten App-Start", Toasty.LENGTH_LONG).show()
}
}
private fun uriFromFile(context: Context, file: File): Uri {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID + ".provider", file)
} else {
Uri.fromFile(file)
}
}
private fun installBelowAndroid10(context: Context, file: File, broadcastReceiver: BroadcastReceiver) {
val installIntent = Intent(Intent.ACTION_VIEW)
installIntent.setDataAndType(uriFromFile(context, file), "application/vnd.android.package-archive")
installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
installIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
context.startActivity(installIntent)
context.unregisterReceiver(broadcastReceiver)
}

@ -1,65 +0,0 @@
package com.cyb3rko.techniklogger.utils
import android.Manifest
import android.annotation.SuppressLint
import android.app.AlertDialog
import android.app.Dialog
import android.app.DownloadManager
import android.content.Context.DOWNLOAD_SERVICE
import android.content.pm.PackageManager
import android.graphics.Typeface
import android.net.Uri
import android.os.Bundle
import android.os.Environment
import android.view.Gravity
import android.webkit.URLUtil
import android.widget.TextView
import androidx.appcompat.app.AppCompatDialogFragment
import androidx.core.content.ContextCompat
import androidx.core.view.setPadding
import com.cyb3rko.techniklogger.BuildConfig
import es.dmoral.toasty.Toasty
@SuppressLint("SetTextI18n")
class Updater : AppCompatDialogFragment() {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val sharedPref = activity!!.getSharedPreferences("Safe", 0)
val builder: AlertDialog.Builder = AlertDialog.Builder(context)
val titleView = TextView(context)
titleView.setPadding(32)
titleView.gravity = Gravity.CENTER_HORIZONTAL
titleView.typeface = Typeface.DEFAULT_BOLD
titleView.textSize = 22f
titleView.text = "Neues Update verfügbar"
val messageView = TextView(context)
messageView.setPadding(32)
messageView.gravity = Gravity.CENTER_HORIZONTAL
messageView.textSize = 16f
messageView.text = "Das Update '${sharedPref.getString("neuesteVersion", "")}' steht zum Download bereit!\n\nAktuell installierte Version: " +
"'${BuildConfig.VERSION_NAME}'"
builder.setView(messageView)
.setCancelable(false)
.setCustomTitle(titleView)
.setPositiveButton("Herunterladen") { _, _ ->
if (ContextCompat.checkSelfPermission(context!!, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
val link = "https://cdn.cyb3rko.de/Apps/Technik-Logger/Technik-Logger%20v${sharedPref.getString("neuesteVersion", "")}.apk"
val request = DownloadManager.Request(Uri.parse(link))
.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, URLUtil.guessFileName(link, null, null))
.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
val downloadManager: DownloadManager = activity!!.getSystemService(DOWNLOAD_SERVICE) as DownloadManager
downloadManager.enqueue(request)
} else {
Toasty.error(context!!, "Fehlende Berechtigung, erteilen Sie diese beim nächsten App-Start", Toasty.LENGTH_LONG).show()
}
}
.setNegativeButton("Abbrechen") { _, _ -> }
return builder.create()
}
}

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path
name="files_root"
path="Android/data/${applicationId}" />
<external-path
name="external_files"
path="." />
</paths>
Loading…
Cancel
Save