From 74b53d7630a2ec0086daf6d0120f40de32378d63 Mon Sep 17 00:00:00 2001 From: Niko Diamadis Date: Mon, 27 Jun 2022 14:13:30 +0200 Subject: [PATCH] Aktualisiere Installer und optimiere Updater-Code --- app/build.gradle | 1 - app/src/main/AndroidManifest.xml | 1 + .../com/cyb3rko/techniklogger/MainActivity.kt | 7 +- .../com/cyb3rko/techniklogger/UpdateUtils.kt | 77 --------- .../techniklogger/update/DownloadApk.kt | 152 +++++++++++++++++ .../cyb3rko/techniklogger/update/Updater.kt | 79 +++++++++ installer/.gitignore | 1 - installer/build.gradle | 43 ----- installer/consumer-rules.pro | 0 installer/proguard-rules.pro | 21 --- installer/src/main/AndroidManifest.xml | 8 - .../com/cyb3rko/installer/DownloadApk.java | 161 ------------------ settings.gradle | 5 +- 13 files changed, 238 insertions(+), 318 deletions(-) delete mode 100644 app/src/main/java/com/cyb3rko/techniklogger/UpdateUtils.kt create mode 100644 app/src/main/java/com/cyb3rko/techniklogger/update/DownloadApk.kt create mode 100644 app/src/main/java/com/cyb3rko/techniklogger/update/Updater.kt delete mode 100644 installer/.gitignore delete mode 100644 installer/build.gradle delete mode 100644 installer/consumer-rules.pro delete mode 100644 installer/proguard-rules.pro delete mode 100644 installer/src/main/AndroidManifest.xml delete mode 100644 installer/src/main/java/com/cyb3rko/installer/DownloadApk.java diff --git a/app/build.gradle b/app/build.gradle index aba0cb1..c7fb330 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -74,5 +74,4 @@ dependencies { implementation 'com.google.android.material:material:1.6.1' implementation 'com.google.firebase:firebase-crashlytics-ktx' // BOM versioning implementation 'com.itextpdf:itextpdf:5.5.13.2' - implementation project(':installer') } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index f61898c..853ab09 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -5,6 +5,7 @@ + - downloadApk(context, newestVersion) - } - .show() -} - -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" - DownloadApk(context).startDownloadingApk(link) - } else { - Toasty.error(context, "Fehlende Berechtigung, erteile diese beim nächsten App-Start", Toasty.LENGTH_LONG).show() - } -} diff --git a/app/src/main/java/com/cyb3rko/techniklogger/update/DownloadApk.kt b/app/src/main/java/com/cyb3rko/techniklogger/update/DownloadApk.kt new file mode 100644 index 0000000..3f4393e --- /dev/null +++ b/app/src/main/java/com/cyb3rko/techniklogger/update/DownloadApk.kt @@ -0,0 +1,152 @@ +package com.cyb3rko.techniklogger.update + +import android.app.ProgressDialog +import android.content.Context +import android.content.Intent +import android.net.Uri +import android.os.AsyncTask +import android.os.Build +import android.os.Environment +import android.util.Log +import android.webkit.URLUtil +import android.widget.Toast +import androidx.appcompat.app.AppCompatActivity +import androidx.core.content.FileProvider +import java.io.File +import java.io.FileOutputStream +import java.io.IOException +import java.net.HttpURLConnection +import java.net.MalformedURLException +import java.net.URL + +/** + * Created by piashsarker on 1/16/18, rewritten by Cyb3rKo on 12/21/20. + */ + +class DownloadApk(var context: Context) : AppCompatActivity() { + + @JvmOverloads + fun startDownloadingApk(url: String, fileName: String = "App Update") { + if (URLUtil.isValidUrl(url)) { + DownloadNewVersion(context, url, fileName).execute() + } + } + + @Suppress("DEPRECATION") + private class DownloadNewVersion( + val context: Context, + val downloadUrl: String, + val fileName: String + ): AsyncTask() { + private lateinit var bar: ProgressDialog + override fun onPreExecute() { + super.onPreExecute() + bar = ProgressDialog(context).apply { + setCancelable(false) + setMessage("Downloading...") + isIndeterminate = true + setCanceledOnTouchOutside(false) + show() + } + } + + override fun onProgressUpdate(vararg values: Int?) { + super.onProgressUpdate(*values) + var msg = "" + val progress = values[0] + if (progress != null) { + bar.progress = progress + msg = if (progress > 99) "Finishing... " else "Downloading... $progress%" + } + + bar.apply { + isIndeterminate = false + max = 100 + setMessage(msg) + } + } + + override fun onPostExecute(result: Boolean?) { + super.onPostExecute(result) + bar.dismiss() + if (result != null && result) { + Toast.makeText(context, "Update Done", Toast.LENGTH_SHORT).show() + } else { + Toast.makeText(context, "Error: Try Again", Toast.LENGTH_SHORT).show() + } + } + + override fun doInBackground(vararg p0: String?): Boolean { + var flag = false + + try { + val path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).toString() + "/" + var outputFile = File("$path$fileName.apk") + var repetition = 1 + while (outputFile.exists()) { + outputFile = File("$path$fileName ($repetition).apk") + repetition++ + } + + val directory = File(path) + if (!directory.exists()) { + directory.mkdirs() + } + + val url = URL(downloadUrl) + val c = url.openConnection() as HttpURLConnection + c.requestMethod = "GET" + c.connect() + + val fos = FileOutputStream(outputFile) + val inputStream = c.inputStream + val totalSize = c.contentLength.toFloat() //size of apk + + val buffer = ByteArray(1024) + var len1: Int + var per: Float + var downloaded = 0f + while (inputStream.read(buffer).also { len1 = it } != -1) { + fos.write(buffer, 0, len1) + downloaded += len1 + per = (downloaded * 100 / totalSize) + publishProgress(per.toInt()) + } + fos.close() + inputStream.close() + openNewVersion(outputFile.path) + flag = true + } catch (e: MalformedURLException) { + Log.e("DownloadApk", "Update Error: " + e.message) + flag = false + } catch (e: IOException) { + e.printStackTrace() + } + + return flag + } + + private fun openNewVersion(location: String) { + val intent = Intent(Intent.ACTION_VIEW) + intent.setDataAndType( + getUriFromFile(location), + "application/vnd.android.package-archive" + ) + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) + context.startActivity(intent) + } + + private fun getUriFromFile(filePath: String): Uri { + return if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { + Uri.fromFile(File(filePath)) + } else { + FileProvider.getUriForFile( + context, + context.packageName + ".provider", + File(filePath) + ) + } + } + } +} diff --git a/app/src/main/java/com/cyb3rko/techniklogger/update/Updater.kt b/app/src/main/java/com/cyb3rko/techniklogger/update/Updater.kt new file mode 100644 index 0000000..cd80eb8 --- /dev/null +++ b/app/src/main/java/com/cyb3rko/techniklogger/update/Updater.kt @@ -0,0 +1,79 @@ +package com.cyb3rko.techniklogger.update + +import android.Manifest +import android.content.Context +import android.content.pm.PackageManager +import android.util.Base64 +import android.util.Log +import androidx.core.app.ActivityCompat +import androidx.core.content.ContextCompat +import com.androidnetworking.AndroidNetworking +import com.androidnetworking.error.ANError +import com.androidnetworking.interfaces.StringRequestListener +import com.cyb3rko.techniklogger.BuildConfig +import com.cyb3rko.techniklogger.MainActivity +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import es.dmoral.toasty.Toasty +import java.nio.charset.StandardCharsets + +internal object Updater { + 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?) { + try { + var parts = response!!.split("content\":\"") + var parts2 = parts[1].split("\",\"target") + val content = String(Base64.decode(parts2[0], Base64.DEFAULT), StandardCharsets.UTF_8) + + parts = content.split("versionCode ") + parts2 = parts[1].split("\n") + val neuesterVersionCode = parts2[0].toInt() + parts = parts2[1].split("\"") + parts2 = parts[1].split("\"") + 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.WRITE_EXTERNAL_STORAGE), 1 + ) + } else { + Log.d(activity.toString(), "App auf dem neuesten Stand") + } + } catch (e: Exception) { + Toasty.error(activity, "Update-Check fehlgeschlagen", Toasty.LENGTH_LONG).show() + } + } + + override fun onError(anError: ANError?) { + Log.d(activity.toString(), "Update-Abfrage fehlgeschlagen: ${anError!!.errorBody.trimIndent()}") + } + }) + } + + private fun showDownloadDialog(context: Context, newestVersion: String) { + MaterialAlertDialogBuilder(context) + .setTitle("Neues Update verfügbar") + .setMessage("Das Update '$newestVersion' steht zum Download bereit!\n\nAktuell installierte Version: '${BuildConfig.VERSION_NAME}'") + .setPositiveButton("Herunterladen") { _, _ -> + downloadApk(context, newestVersion) + } + .show() + } + + 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" + DownloadApk(context).startDownloadingApk(link, "Technik-Logger $newestVersion") + } else { + Toasty.error(context, "Fehlende Berechtigung, erteile diese beim nächsten App-Start", Toasty.LENGTH_LONG).show() + } + } +} diff --git a/installer/.gitignore b/installer/.gitignore deleted file mode 100644 index 42afabf..0000000 --- a/installer/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build \ No newline at end of file diff --git a/installer/build.gradle b/installer/build.gradle deleted file mode 100644 index 67abf1b..0000000 --- a/installer/build.gradle +++ /dev/null @@ -1,43 +0,0 @@ -plugins { - id 'com.android.library' - id 'kotlin-android' -} - -android { - compileSdkVersion 31 - buildToolsVersion "30.0.3" - - defaultConfig { - minSdkVersion 19 - targetSdkVersion 31 - - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - consumerProguardFiles "consumer-rules.pro" - } - - buildTypes { - debug { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' - } - release { - minifyEnabled true - proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' - } - } - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } - kotlinOptions { - jvmTarget = '1.8' - } -} - -dependencies { - - implementation "org.jetbrains.kotlin:kotlin-stdlib:1.5.20" - implementation 'androidx.core:core-ktx:1.6.0' - implementation 'androidx.appcompat:appcompat:1.3.1' - implementation 'com.google.android.material:material:1.4.0' -} \ No newline at end of file diff --git a/installer/consumer-rules.pro b/installer/consumer-rules.pro deleted file mode 100644 index e69de29..0000000 diff --git a/installer/proguard-rules.pro b/installer/proguard-rules.pro deleted file mode 100644 index 481bb43..0000000 --- a/installer/proguard-rules.pro +++ /dev/null @@ -1,21 +0,0 @@ -# Add project specific ProGuard rules here. -# You can control the set of applied configuration files using the -# proguardFiles setting in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} - -# Uncomment this to preserve the line number information for -# debugging stack traces. -#-keepattributes SourceFile,LineNumberTable - -# If you keep the line number information, uncomment this to -# hide the original source file name. -#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/installer/src/main/AndroidManifest.xml b/installer/src/main/AndroidManifest.xml deleted file mode 100644 index d68c97f..0000000 --- a/installer/src/main/AndroidManifest.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/installer/src/main/java/com/cyb3rko/installer/DownloadApk.java b/installer/src/main/java/com/cyb3rko/installer/DownloadApk.java deleted file mode 100644 index b4b3d5f..0000000 --- a/installer/src/main/java/com/cyb3rko/installer/DownloadApk.java +++ /dev/null @@ -1,161 +0,0 @@ -package com.cyb3rko.installer; - -import android.app.Activity; -import android.app.ProgressDialog; -import android.content.Context; -import android.content.Intent; -import android.net.Uri; -import android.os.AsyncTask; -import android.os.Build; -import android.os.Environment; -import android.util.Log; -import android.widget.Toast; -import androidx.core.content.FileProvider; -import java.io.File; -import java.io.FileOutputStream; -import java.io.InputStream; -import java.net.HttpURLConnection; -import java.net.MalformedURLException; -import java.net.URL; - -public class DownloadApk extends Activity { - private static Context context; - private static String downloadUrl; - private static String fileName; - private static final String TAG = "DownloadApk"; - - public DownloadApk(Context context){ - DownloadApk.context = context; - } - - public void startDownloadingApk(String url){ - downloadUrl = url; - fileName = url.split("Technik-Logger/")[1].replace("%20", " "); - if (downloadUrl != null){ - new DownloadNewVersion(context).execute(); - } - } - - private static class DownloadNewVersion extends AsyncTask { - private ProgressDialog bar; - private final Context context; - - DownloadNewVersion(Context context) { - this.context = context; - } - - @Override - protected void onPreExecute() { - super.onPreExecute(); - if (bar == null){ - bar = new ProgressDialog(context); - bar.setCancelable(false); - bar.setMessage("Lädt herunter..."); - bar.setIndeterminate(true); - bar.setCanceledOnTouchOutside(false); - bar.show(); - } - } - - protected void onProgressUpdate(Integer... progress) { - super.onProgressUpdate(progress); - bar.setIndeterminate(false); - bar.setMax(100); - bar.setProgress(progress[0]); - String msg = ""; - if (progress[0] > 99) { - msg = "Beenden... "; - } else { - msg = "Herunterladen... " + progress[0] + "%"; - } - bar.setMessage(msg); - } - - @Override - protected void onPostExecute(Boolean result) { - super.onPostExecute(result); - if (bar.isShowing() && bar != null) { - bar.dismiss(); - bar = null; - } - - if (result) { - Toast.makeText(context,"Download erfolgreich", Toast.LENGTH_SHORT).show(); - } else { - Toast.makeText(context,"Download fehlgeschlagen", Toast.LENGTH_SHORT).show(); - } - } - - @Override - protected Boolean doInBackground(String... arg0) { - boolean flag = false; - try { - String destination = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).toString() + "/"; - File outputFile = new File(destination + fileName); - if (outputFile.exists()) { - try { - openNewVersion(outputFile.getPath()); - return true; - } catch (Exception ignored) { - } - } - outputFile.createNewFile(); - - File directory = new File(destination); - if (!directory.exists()) { - directory.mkdirs(); - } - - URL url = new URL(downloadUrl); - HttpURLConnection c = (HttpURLConnection) url.openConnection(); - c.setRequestMethod("GET"); - c.connect(); - - FileOutputStream fos = new FileOutputStream(outputFile); - InputStream is = c.getInputStream(); - - // size of apk - int total_size = c.getContentLength(); - - byte[] buffer = new byte[1024]; - int len1; - int per; - int downloaded = 0; - while ((len1 = is.read(buffer)) != -1) { - fos.write(buffer, 0, len1); - downloaded += len1; - per = downloaded * 100 / total_size; - publishProgress(per); - } - fos.close(); - is.close(); - openNewVersion(outputFile.getPath()); - flag = true; - } catch (MalformedURLException e) { - Log.e(TAG, "Update-Fehler: " + e.getMessage()); - flag = false; - } catch (Exception e) { - e.printStackTrace(); - Log.e(TAG, "Update-Fehler: " + e.getMessage()); - } - return flag; - } - } - - private static void openNewVersion(String filePath) { - Intent intent = new Intent(Intent.ACTION_VIEW); - intent.setDataAndType(getUriFromFile(filePath), "application/vnd.android.package-archive"); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - context.startActivity(intent); - } - - private static Uri getUriFromFile(String filePath) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { - return Uri.fromFile(new File(filePath)); - } else { - return FileProvider.getUriForFile(context, context.getApplicationContext().getPackageName() + ".provider", - new File(filePath)); - } - } -} diff --git a/settings.gradle b/settings.gradle index e566ff0..7edb7b7 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,3 +1,2 @@ -include ':installer' -include ':app' -rootProject.name = "Technik-Logger" \ No newline at end of file +rootProject.name = "Technik-Logger" +include ':app' \ No newline at end of file