From fd4e1197fe7f6e2342a90d52c23016a578e27361 Mon Sep 17 00:00:00 2001 From: SnoopyCodeX Date: Sun, 20 Sep 2020 15:16:58 +0800 Subject: [PATCH] Changed the json parsing behaviour and added gson library for a more easier json parsing. --- README.md | 78 +++++----- cdph_updatechecker_app/build.gradle | 1 + .../com/cdph/updatechecker/MainActivity.java | 99 +++++++------ .../src/main/res/layout/main.xml | 2 + cdph_updatechecker_lib/build.gradle | 5 +- .../main/java/com/cdph/app/UpdateChecker.java | 136 ++++++++++++------ .../java/com/cdph/app/json/JSONReader.java | 11 -- 7 files changed, 189 insertions(+), 143 deletions(-) delete mode 100644 cdph_updatechecker_lib/src/main/java/com/cdph/app/json/JSONReader.java diff --git a/README.md b/README.md index 504d08d..f126783 100644 --- a/README.md +++ b/README.md @@ -1,88 +1,78 @@ -### JSON-based Update Checker -[![DepShield Badge](https://depshield.sonatype.org/badges/SnoopyCodeX/repository/depshield.svg)](https://depshield.github.io) - -> ☑ Customizeable ---- -> ☑ Easy to implement ---- -> ☑ JSON-based checker ---- -> ☑ Can download app ---- -> ☑ Can auto install app ---- -> ☑ Automatically check for updates +# JSON-based Update Checker +![DepShield Badge](https://depshield.sonatype.org/badges/SnoopyCodeX/repository/depshield.svg) --- -> ☑ Lightweight library +- [x] Customizeable +- [x] Easy to implement +- [x] JSON-based checker +- [x] Can download app +- [x] Can auto install app +- [x] Automatically check for updates +- [x] Lightweight library +- [x] Uses Google's [Gson Library](https://github.com/google/gson) for json parsing --- -Setup +# Setup --- -> Initialize UpdateChecker +### Initialize UpdateChecker ```java UpdateChecker checker = UpdateChecker.getInstance(context); - ``` --- -> Set custom json reader +### Set custom json reader ```java -checker.setJsonReader(new MyCustomJsonReader()); +checker.setJsonModel(MyModel.class); -private class MyCustomJsonReader extends JSONReader +public class MyModel { - @Override - public NewUpdateInfo readJson(String json) throws Exception - { - JSONObject job = new JSONObject(json); - int vcode = job.getInt("versionCode"); - String vname = job.getString("versionName"); - String url = job.getString("downloadUrl"); - String desc = job.getString("description"); - - return (new NewUpdateInfo(url, desc, vname, vcode)); - } + @SerializedName("description") + List description; + + @SerializedName("name") + String name; + + @SerializedName("version") + String version; + + @SerializedName("downloadUrl") + String downloadUrl; } ``` --- -> Enable auto update +### Enable auto update ```java checker.shouldAutoRun(true); ``` --- -> Enable update on both mobile networks +### Enable update on both mobile networks ```java checker.shouldCheckUpdateOnWifiOnly(false); ``` --- -> Enable auto installation +### Enable auto installation ```java checker.shouldAutoInstall(true); ``` --- -> Set the url of the json file +### Set the url of the json file ```java checker.setUpdateLogsUrl("https://urlhere"); ``` --- -> Downloading the app +### Downloading the app ```java //Returns the filepath of the downloaded app UpdateChecker.downloadUpdate("https://urlHere"); ``` --- -> Installing the app manually +### Installing the app manually ```java UpdateChecker.installApp(file); ``` ---- -> Add listener +### Add listener ```java checker.setOnUpdateDetectedListener(new UpdateChecker.OnUpdateDetectedListener() { @Override - public void onUpdateDetected(NewUpdateInfo info) + public void onUpdateDetected(Object info) {} }); ``` ---- -Support - ---- diff --git a/cdph_updatechecker_app/build.gradle b/cdph_updatechecker_app/build.gradle index 1900f46..55cbb8b 100644 --- a/cdph_updatechecker_app/build.gradle +++ b/cdph_updatechecker_app/build.gradle @@ -21,5 +21,6 @@ android { dependencies { compile project(':cdph_updatechecker_lib') + compile 'com.google.code.gson:gson:2.8.5' compile fileTree(dir: 'libs', include: ['*.jar']) } diff --git a/cdph_updatechecker_app/src/main/java/com/cdph/updatechecker/MainActivity.java b/cdph_updatechecker_app/src/main/java/com/cdph/updatechecker/MainActivity.java index 1c68802..b550d07 100644 --- a/cdph_updatechecker_app/src/main/java/com/cdph/updatechecker/MainActivity.java +++ b/cdph_updatechecker_app/src/main/java/com/cdph/updatechecker/MainActivity.java @@ -1,73 +1,80 @@ package com.cdph.updatechecker; -import android.app.*; -import android.content.*; -import android.os.*; -import org.json.*; +import android.app.Activity; +import android.app.AlertDialog; +import android.content.Context; +import android.os.Bundle; +import android.widget.TextView; +import android.widget.Toast; +import java.util.List; +import com.google.gson.annotations.SerializedName; import com.cdph.app.UpdateChecker; -import com.cdph.app.UpdateChecker.NewUpdateInfo; -import com.cdph.app.json.JSONReader; public class MainActivity extends Activity { + private TextView tv; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); - + + tv = findViewById(R.id.mainTextView); + UpdateChecker.getInstance(this) - .setUpdateLogsUrl("https://pastebin.com/raw/e3q1h4iQ") + .setUpdateLogsUrl("https://pastebin.com/raw/x9JufEML") .shouldAutoRun(true) .shouldAutoInstall(true) - .setJsonReader(new MyCustomJsonReader()) + .setJsonModel(Model.class) .setOnUpdateDetectedListener(new UpdateChecker.OnUpdateDetectedListener() { @Override - public void onUpdateDetected(final UpdateChecker.NewUpdateInfo info) + public void onUpdateDetected(Object info) { - final AlertDialog dlg = new AlertDialog.Builder(MainActivity.this).create(); - - String msg = ""; - msg += info.app_version + "\n"; - msg += info.app_versionName + "\n"; - msg += info.app_updateUrl + "\n"; - msg += info.app_description; - - dlg.setTitle("New Update Detected"); - dlg.setMessage(msg); - dlg.setButton(AlertDialog.BUTTON1, "Update now", new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface di, int btn) + try { + Model model = (Model) info; + String str_curVer = getPackageManager().getPackageInfo(getPackageName(), 0).versionName; + String str_newVer = model.version; + + if(UpdateChecker.compareVersion(str_curVer, str_newVer)) { - dlg.dismiss(); - UpdateChecker.downloadUpdate("https://github.com/SnoopyCodeX/binarymatrixandroid/raw/master/binarymatrix_lwp/app/build/bin/app.apk", "cdph_updatechecker_app.apk"); + String txt = String.format("Name: %s\nVersion: %s\nDownload: %s\nDescription: %s", + model.name, + model.version, + model.downloadUrl, + model.description.get(0) + ); + + AlertDialog dlg = new AlertDialog.Builder(MainActivity.this).create(); + dlg.setCancelable(true); + dlg.setCanceledOnTouchOutside(false); + dlg.setMessage(txt); + dlg.setTitle("Update Available"); + dlg.show(); } - }); - dlg.show(); + else + Toast.makeText(MainActivity.this, "You have the latest version!", Toast.LENGTH_LONG).show(); + } catch(Exception e) { + e.printStackTrace(); + } } - }); + }) + .runUpdateChecker(); } - - private class MyCustomJsonReader extends JSONReader + + public static final class Model { - @Override - public NewUpdateInfo readJson(String json) throws Exception - { - //Parse as jsonObject then get the values - JSONObject job = new JSONObject(json); - int versionCode = job.getInt("versionCode"); - String versionName = job.getString("versionName"); - String downloadUrl = job.getString("url"); - String description = ""; + @SerializedName("description") + List description; + + @SerializedName("version") + String version; - //Parse 'description' as jsonArray then get the values - JSONArray jar = job.getJSONArray("description"); - for(int i = 0; i < jar.length(); i++) - description += jar.getString(i) + "\n"; - description = description.substring(0, description.length()-1); + @SerializedName("name") + String name; - return (new NewUpdateInfo(downloadUrl, versionName, description, versionCode)); - } + @SerializedName("downloadUrl") + String downloadUrl; } } diff --git a/cdph_updatechecker_app/src/main/res/layout/main.xml b/cdph_updatechecker_app/src/main/res/layout/main.xml index b1d869f..ff94348 100644 --- a/cdph_updatechecker_app/src/main/res/layout/main.xml +++ b/cdph_updatechecker_app/src/main/res/layout/main.xml @@ -4,7 +4,9 @@ android:gravity="center"> diff --git a/cdph_updatechecker_lib/build.gradle b/cdph_updatechecker_lib/build.gradle index ee87c51..a5d5045 100644 --- a/cdph_updatechecker_lib/build.gradle +++ b/cdph_updatechecker_lib/build.gradle @@ -8,8 +8,8 @@ android { applicationId "com.cdph.app" minSdkVersion 14 targetSdkVersion 21 - versionCode 21 - versionName "21.1.0w8y20a2" + versionCode 22 + versionName "22.0.0" } buildTypes { release { @@ -20,5 +20,6 @@ android { } dependencies { + compile 'com.google.code.gson:gson:2.8.5' compile fileTree(dir: 'libs', include: ['*.jar']) } diff --git a/cdph_updatechecker_lib/src/main/java/com/cdph/app/UpdateChecker.java b/cdph_updatechecker_lib/src/main/java/com/cdph/app/UpdateChecker.java index 68b47a5..a6ea20a 100644 --- a/cdph_updatechecker_lib/src/main/java/com/cdph/app/UpdateChecker.java +++ b/cdph_updatechecker_lib/src/main/java/com/cdph/app/UpdateChecker.java @@ -28,15 +28,19 @@ import java.net.HttpURLConnection; import java.net.URL; import java.text.NumberFormat; +import java.util.HashMap; -import com.cdph.app.json.JSONReader; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; public final class UpdateChecker { private static OnUpdateDetectedListener listener; private static String updateLogUrl = ""; - private static boolean autoRun = false, autoInstall = false, updateOnWifiOnly = true; - private static JSONReader jsonReader; + private static boolean autoRun = false, + autoInstall = false, + updateOnWifiOnly = true; + private static Class jsonModel; private static Context ctx; /* @@ -133,14 +137,14 @@ public UpdateChecker setOnUpdateDetectedListener(UpdateChecker.OnUpdateDetectedL } /* - * Sets a custom json reader to suit your needs + * Sets a custom json model to suit your needs * - *@param jsonReader - A custom class that extends {com.cdph.app.json.JSONReader} + *@param jsonModel - A model class that will contain the update info *@return UpdateChecker.class */ - public UpdateChecker setJsonReader(T jsonReader) + public UpdateChecker setJsonModel(Class jsonModel) { - this.jsonReader = jsonReader; + this.jsonModel = jsonModel; return this; } @@ -155,7 +159,7 @@ public void runUpdateChecker() if(ConnectivityReceiver.isConnected(ctx)) (new TaskUpdateChecker()).execute(updateLogUrl); else - Toast.makeText(ctx, String.format("[ERROR (runUpdateChecker)]: %s", "You are not connected to a wifi network"), Toast.LENGTH_LONG).show(); + Toast.makeText(ctx, "You are not connected to an active network", Toast.LENGTH_LONG).show(); } catch(Exception e) { e.printStackTrace(); Toast.makeText(ctx, String.format("[ERROR (runUpdateChecker)]: %s", e.getMessage()), Toast.LENGTH_LONG).show(); @@ -168,7 +172,7 @@ public void runUpdateChecker() *@param filePath - The path of the apk to be installed *@return null */ - public static void installApp(String path, String mimeType) + public static void installApp(String path) { try { Uri uri = Uri.parse("file://" + path); @@ -208,40 +212,88 @@ public static File downloadUpdate(String url, String filename) return file; } - public static interface OnUpdateDetectedListener + /* + * Checks and formats version into a + * proper semantic versioning format + * + *@param version - The string version (xx.xx.xx | [major].[minor].[patch]) + */ + public static HashMap toSemanticVersioning(String version) { - public void onUpdateDetected(NewUpdateInfo info) + HashMap semanticVer = new HashMap<>(); + version = version.replaceAll("[a-zA-Z\\-]+", ""); + + if(version.matches("\\d+\\.\\d+\\.\\d+")) + { + String[] vers = version.split("[.]"); + semanticVer.put("major", Integer.parseInt(vers[0])); + semanticVer.put("minor", Integer.parseInt(vers[1])); + semanticVer.put("patch", Integer.parseInt(vers[2])); + } + + if(version.matches("\\d+\\.\\d+")) + { + String[] vers = version.split("[.]"); + semanticVer.put("major", Integer.parseInt(vers[0])); + semanticVer.put("minor", Integer.parseInt(vers[1])); + semanticVer.put("patch", 0); + } + + if(version.matches("\\d+")) + { + semanticVer.put("major", Integer.parseInt(version)); + semanticVer.put("minor", 0); + semanticVer.put("patch", 0); + } + + return semanticVer; } - public static class NewUpdateInfo + /* + * Compares version1 to version2, + * returns true if version1 is greater than + * version2. + * + *@param version1 - String version1 + *@param version2 - String version2 + *@return boolean + */ + public static boolean compareVersion(String version1, String version2) { - public int app_version; - public String app_updateUrl; - public String app_versionName; - public String app_description; + HashMap curVer = UpdateChecker.toSemanticVersioning(version1); + HashMap newVer = UpdateChecker.toSemanticVersioning(version2); + + int cmaj = curVer.get("major"), + cmin = curVer.get("minor"), + cpat = curVer.get("patch"); + + int nmaj = newVer.get("major"), + nmin = newVer.get("minor"), + npat = newVer.get("patch"); - public NewUpdateInfo(String url, String versionName, String description, int version) - { - this.app_version = version; - this.app_versionName = versionName; - this.app_updateUrl = url; - this.app_description = description; - } + return ((cmaj < nmaj) || (cmin < nmin) || (cpat < npat)); + } + + public static interface OnUpdateDetectedListener + { + public void onUpdateDetected(Object info) } - private static class TaskUpdateChecker extends AsyncTask + private static class TaskUpdateChecker extends AsyncTask { private static final int CONNECT_TIMEOUT = 6000; private static final int READ_TIMEOUT = 3000; + private Gson gson; private ProgressDialog dlg; - private String errMsg; + private String errMsg = ""; @Override protected void onPreExecute() { super.onPreExecute(); + gson = new GsonBuilder().create(); dlg = new ProgressDialog(ctx); dlg.setCancelable(false); dlg.setCanceledOnTouchOutside(false); @@ -252,10 +304,8 @@ protected void onPreExecute() } @Override - protected NewUpdateInfo doInBackground(String... params) + protected String doInBackground(String... params) { - NewUpdateInfo info = null; - try { String str_url = params[0]; URL url = new URL(str_url); @@ -278,8 +328,7 @@ protected NewUpdateInfo doInBackground(String... params) json += new String(buffer, 0, len); is.close(); - //Read json - info = jsonReader.readJson(json); + return json; } conn.disconnect(); @@ -288,11 +337,11 @@ protected NewUpdateInfo doInBackground(String... params) errMsg += e.getMessage(); } - return info; + return null; } @Override - protected void onPostExecute(NewUpdateInfo result) + protected void onPostExecute(String result) { super.onPostExecute(result); @@ -300,13 +349,11 @@ protected void onPostExecute(NewUpdateInfo result) if(dlg != null) dlg.dismiss(); - if(listener != null && errMsg == null) - if(ctx.getPackageManager().getPackageInfo(ctx.getPackageName(), 0).versionCode < result.app_version) - listener.onUpdateDetected(result); - else - Toast.makeText(ctx, "You have the latest version!", Toast.LENGTH_LONG).show(); + if(listener != null && errMsg.isEmpty()) + listener.onUpdateDetected(gson.fromJson(result, jsonModel)); else Toast.makeText(ctx, String.format("[ERROR]: %s", errMsg), Toast.LENGTH_LONG).show(); + } catch(Exception e) { e.printStackTrace(); Toast.makeText(ctx, String.format("[ERROR (task_updatechecker)]: %s", e.getMessage()), Toast.LENGTH_LONG).show(); @@ -317,7 +364,7 @@ protected void onPostExecute(NewUpdateInfo result) private static final class TaskDownloadUpdate extends AsyncTask { private ProgressDialog dlg; - private String errMsg, mimeType; + private String errMsg; @Override protected void onPreExecute() @@ -366,14 +413,23 @@ protected File doInBackground(String[] params) cursor.moveToFirst(); int status = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS)); + int curr = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR)); + int maxx = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES)); + int prog = (maxx / curr); + dlg.setProgress(prog); + + if(prog < 100) + dlg.setMessage(String.format("Downloading... (%d%)", prog)); + else + dlg.setMessage("Download finished..."); + if(status == DownloadManager.STATUS_SUCCESSFUL) { String filePath = cursor.getString(cursor.getColumnIndex("local_uri")); file = new File(filePath); - mimeType = dm.getMimeTypeForDownloadedFile(id); if(autoInstall && errMsg == null) - installApp(filePath, mimeType); + installApp(filePath); downloading = false; } diff --git a/cdph_updatechecker_lib/src/main/java/com/cdph/app/json/JSONReader.java b/cdph_updatechecker_lib/src/main/java/com/cdph/app/json/JSONReader.java deleted file mode 100644 index d23e5c1..0000000 --- a/cdph_updatechecker_lib/src/main/java/com/cdph/app/json/JSONReader.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.cdph.app.json; - -import org.json.JSONArray; -import org.json.JSONObject; - -import com.cdph.app.UpdateChecker.NewUpdateInfo; - -public abstract class JSONReader -{ - public abstract NewUpdateInfo readJson(String json) throws Exception -}