Use jackson instead, default enable minify on debug.Version compare fix

This commit is contained in:
ZaneYork 2020-03-10 18:12:21 +08:00
parent 7fd7e00511
commit b4e8917f8d
15 changed files with 144 additions and 80 deletions

View File

@ -18,8 +18,13 @@ android {
buildTypes {
release {
minifyEnabled false
shrinkResources false
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
debug {
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
@ -53,11 +58,15 @@ dependencies {
implementation group: 'com.google.guava', name: 'guava', version: '28.2-android'
// https://mvnrepository.com/artifact/org.zeroturnaround/zt-zip
implementation group: 'org.zeroturnaround', name: 'zt-zip', version: '1.14'
// https://mvnrepository.com/artifact/com.google.code.gson/gson
implementation group: 'com.google.code.gson', name: 'gson', version: '2.8.6'
// https://mvnrepository.com/artifact/org.apache.commons/commons-lang3
implementation group: 'org.apache.commons', name: 'commons-lang3', version: '3.9'
// https://mvnrepository.com/artifact/commons-io/commons-io
implementation group: 'commons-io', name: 'commons-io', version: '2.6'
implementation 'com.lzy.net:okgo:3.0.4'
// https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core
implementation group: 'com.fasterxml.jackson.core', name: 'jackson-core', version: '2.10.3'
implementation group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.10.3'
implementation group: 'com.fasterxml.jackson.core', name: 'jackson-annotations', version: '2.10.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'

View File

@ -19,9 +19,9 @@
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
-keepnames class com.path.to.your.ParcelableArg
-keepnames class com.path.to.your.SerializableArg
-keepnames class com.path.to.your.EnumArg
#-keepnames class com.path.to.your.ParcelableArg
#-keepnames class com.path.to.your.SerializableArg
#-keepnames class com.path.to.your.EnumArg
-dontwarn javax.lang.model.element.Modifier
@ -118,34 +118,15 @@
static *** getCurrentEnvironment (...);
}
##---------------Begin: proguard configuration for Gson ----------
# Gson uses generic type information stored in a class file when working with fields. Proguard
# removes such information by default, so configure it to keep all of it.
# For Jackson
-keepattributes Signature
# For using GSON @Expose annotation
-keepattributes *Annotation*
-keep class sun.misc.Unsafe { *; }
-dontwarn org.codehaus.jackson.**
-dontwarn com.fasterxml.jackson.databind.**
-keep class org.codehaus.jackson.** { *;}
-keep class com.fasterxml.jackson.** { *; }
# Gson specific classes
-dontwarn sun.misc.**
#-keep class com.google.gson.stream.** { *; }
# Application classes that will be serialized/deserialized over Gson
-keep class com.google.gson.examples.android.model.** { <fields>; }
# Prevent proguard from stripping interface information from TypeAdapter, TypeAdapterFactory,
# JsonSerializer, JsonDeserializer instances (so they can be used in @JsonAdapter)
-keep class * implements com.google.gson.TypeAdapter
-keep class * implements com.google.gson.TypeAdapterFactory
-keep class * implements com.google.gson.JsonSerializer
-keep class * implements com.google.gson.JsonDeserializer
# Prevent R8 from leaving Data object members always null
-keepclassmembers,allowobfuscation class * {
@com.google.gson.annotations.SerializedName <fields>;
}
##---------------End: proguard configuration for Gson ----------
#okhttp
-dontwarn okhttp3.**
-keep class okhttp3.**{*;}

View File

@ -13,4 +13,7 @@ public class ModManifestEntry {
private String Description;
private Set<ModManifestEntry> Dependencies;
private ModManifestEntry ContentPackFor;
private String MinimumVersion;
private Boolean IsRequired;
}

View File

@ -10,10 +10,10 @@ import android.os.Build;
import android.os.Environment;
import android.util.Log;
import com.fasterxml.jackson.core.type.TypeReference;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.io.Files;
import com.google.gson.reflect.TypeToken;
import com.zane.smapiinstaller.BuildConfig;
import com.zane.smapiinstaller.R;
import com.zane.smapiinstaller.constant.Constants;
@ -59,8 +59,7 @@ public class ApkPatcher {
public String extract() {
PackageManager packageManager = context.getPackageManager();
List<String> packageNames = FileUtils.getAssetJson(context, "package_names.json", new TypeToken<List<String>>() {
}.getType());
List<String> packageNames = FileUtils.getAssetJson(context, "package_names.json", new TypeReference<List<String>>() { });
if (packageNames == null) {
errorMessage.set(context.getString(R.string.error_game_not_found));
return null;

View File

@ -10,10 +10,10 @@ import android.util.Log;
import android.view.View;
import com.afollestad.materialdialogs.MaterialDialog;
import com.fasterxml.jackson.core.type.TypeReference;
import com.google.common.base.Predicate;
import com.google.common.collect.Lists;
import com.google.common.io.ByteStreams;
import com.google.gson.reflect.TypeToken;
import com.zane.smapiinstaller.R;
import com.zane.smapiinstaller.entity.ApkFilesManifest;
import com.zane.smapiinstaller.entity.ManifestEntry;
@ -131,8 +131,7 @@ public class CommonLogic {
}
public static boolean unpackSmapiFiles(Context context, String apkPath, boolean checkMod) {
List<ManifestEntry> manifestEntries = com.zane.smapiinstaller.utils.FileUtils.getAssetJson(context, "smapi_files_manifest.json", new TypeToken<List<ManifestEntry>>() {
}.getType());
List<ManifestEntry> manifestEntries = com.zane.smapiinstaller.utils.FileUtils.getAssetJson(context, "smapi_files_manifest.json", new TypeReference<List<ManifestEntry>>() { });
if (manifestEntries == null)
return false;
File basePath = new File(Environment.getExternalStorageDirectory() + "/StardewValley/");

View File

@ -2,13 +2,13 @@ package com.zane.smapiinstaller.logic;
import android.view.View;
import com.google.gson.Gson;
import com.lzy.okgo.OkGo;
import com.lzy.okgo.callback.StringCallback;
import com.lzy.okgo.model.Response;
import com.zane.smapiinstaller.constant.Constants;
import com.zane.smapiinstaller.entity.DownloadableContentList;
import com.zane.smapiinstaller.utils.FileUtils;
import com.zane.smapiinstaller.utils.JSONUtil;
public class DownloadabeContentManager {
@ -28,8 +28,8 @@ public class DownloadabeContentManager {
OkGo.<String>get(Constants.DLC_LIST_UPDATE_URL).execute(new StringCallback(){
@Override
public void onSuccess(Response<String> response) {
DownloadableContentList content = new Gson().fromJson(response.body(), DownloadableContentList.class);
if(downloadableContentList.getVersion() < content.getVersion()) {
DownloadableContentList content = JSONUtil.fromJson(response.body(), DownloadableContentList.class);
if(content != null && downloadableContentList.getVersion() < content.getVersion()) {
FileUtils.writeAssetJson(root.getContext(), "downloadable_content_list.json", content);
downloadableContentList = content;
}

View File

@ -6,6 +6,7 @@ import android.util.Log;
import android.view.View;
import com.afollestad.materialdialogs.DialogAction;
import com.fasterxml.jackson.core.type.TypeReference;
import com.google.common.base.Joiner;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableList;
@ -14,7 +15,6 @@ import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimaps;
import com.google.common.collect.Queues;
import com.google.gson.reflect.TypeToken;
import com.zane.smapiinstaller.R;
import com.zane.smapiinstaller.constant.Constants;
import com.zane.smapiinstaller.entity.ModManifestEntry;
@ -51,8 +51,7 @@ public class ModAssetsManager {
boolean foundManifest = false;
for (File file : currentFile.listFiles(File::isFile)) {
if (StringUtils.equalsIgnoreCase(file.getName(), "manifest.json")) {
ModManifestEntry manifest = FileUtils.getFileJson(file, new TypeToken<ModManifestEntry>() {
}.getType());
ModManifestEntry manifest = FileUtils.getFileJson(file, ModManifestEntry.class);
foundManifest = true;
if (manifest != null) {
manifest.setAssetPath(file.getParentFile().getAbsolutePath());
@ -81,8 +80,7 @@ public class ModAssetsManager {
boolean foundManifest = false;
for (File file : currentFile.listFiles(File::isFile)) {
if (StringUtils.equalsIgnoreCase(file.getName(), "manifest.json")) {
ModManifestEntry manifest = FileUtils.getFileJson(file, new TypeToken<ModManifestEntry>() {
}.getType());
ModManifestEntry manifest = FileUtils.getFileJson(file, ModManifestEntry.class);
foundManifest = true;
if (manifest != null) {
manifest.setAssetPath(file.getParentFile().getAbsolutePath());
@ -101,8 +99,7 @@ public class ModAssetsManager {
public boolean installDefaultMods() {
Activity context = CommonLogic.getActivityFromView(root);
List<ModManifestEntry> modManifestEntries = FileUtils.getAssetJson(context, "mods_manifest.json", new TypeToken<List<ModManifestEntry>>() {
}.getType());
List<ModManifestEntry> modManifestEntries = FileUtils.getAssetJson(context, "mods_manifest.json", new TypeReference<List<ModManifestEntry>>() { });
if (modManifestEntries == null)
return false;
File modFolder = new File(Environment.getExternalStorageDirectory(), Constants.MOD_PATH);
@ -179,6 +176,9 @@ public class ModAssetsManager {
Iterable<String> dependencyErrors = Iterables.filter(Iterables.transform(installedModMap.values(), mod -> {
if (mod.getDependencies() != null) {
ArrayList<ModManifestEntry> unsatisfiedDependencies = Lists.newArrayList(Iterables.filter(mod.getDependencies(), dependency -> {
if(dependency.getIsRequired() != null && !dependency.getIsRequired()) {
return false;
}
ImmutableList<ModManifestEntry> entries = installedModMap.get(dependency.getUniqueID());
if (entries.size() != 1)
return true;
@ -186,10 +186,10 @@ public class ModAssetsManager {
if (StringUtils.isBlank(version)) {
return true;
}
if (StringUtils.isBlank(dependency.getVersion())) {
if (StringUtils.isBlank(dependency.getMinimumVersion())) {
return false;
}
if (VersionUtil.compareVersion(version, dependency.getVersion()) < 0) {
if (VersionUtil.compareVersion(version, dependency.getMinimumVersion()) < 0) {
return true;
}
return false;
@ -219,16 +219,19 @@ public class ModAssetsManager {
Iterable<String> dependencyErrors = Iterables.filter(Iterables.transform(installedModMap.values(), mod -> {
ModManifestEntry dependency = mod.getContentPackFor();
if (dependency != null) {
if(dependency.getIsRequired() != null && !dependency.getIsRequired()) {
return null;
}
ImmutableList<ModManifestEntry> entries = installedModMap.get(dependency.getUniqueID());
if (entries.size() != 1)
return root.getContext().getString(R.string.error_depends_on_mod, mod.getUniqueID(), dependency.getUniqueID());
String version = entries.get(0).getVersion();
if (!StringUtils.isBlank(version)) {
if (StringUtils.isBlank(dependency.getVersion())) {
if (StringUtils.isBlank(dependency.getMinimumVersion())) {
return null;
}
if (VersionUtil.compareVersion(version, dependency.getVersion()) < 0) {
return root.getContext().getString(R.string.error_depends_on_mod, mod.getUniqueID(), dependency.getUniqueID());
if (VersionUtil.compareVersion(version, dependency.getMinimumVersion()) < 0) {
return root.getContext().getString(R.string.error_depends_on_mod_version, mod.getUniqueID(), dependency.getUniqueID(), dependency.getMinimumVersion());
}
}
return null;

View File

@ -7,10 +7,10 @@ import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import com.google.gson.Gson;
import com.zane.smapiinstaller.R;
import com.zane.smapiinstaller.logic.CommonLogic;
import com.zane.smapiinstaller.utils.FileUtils;
import com.zane.smapiinstaller.utils.JSONUtil;
import java.io.File;
import java.io.FileOutputStream;
@ -54,7 +54,7 @@ public class ConfigEditFragment extends Fragment {
}
@OnClick(R.id.button_config_save) void onConfigSave() {
try {
new Gson().fromJson(editText.getText().toString(), Object.class);
JSONUtil.checkJson(editText.getText().toString());
FileOutputStream outputStream = new FileOutputStream(configPath);
try(OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream)){
outputStreamWriter.write(editText.getText().toString());

View File

@ -2,13 +2,14 @@ package com.zane.smapiinstaller.utils;
import android.content.Context;
import android.os.Environment;
import android.util.Log;
import com.fasterxml.jackson.core.type.TypeReference;
import com.google.common.hash.Hashing;
import com.google.common.io.ByteStreams;
import com.google.common.io.CharStreams;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.apache.commons.io.input.BOMInputStream;
import org.apache.commons.lang3.StringUtils;
import java.io.File;
@ -36,18 +37,16 @@ public class FileUtils {
public static InputStream getLocalAsset(Context context, String filename) throws IOException {
File file = new File(context.getFilesDir(), filename);
if (file.exists()) {
return new FileInputStream(file);
return new BOMInputStream(new FileInputStream(file));
}
return context.getAssets().open(filename);
}
public static <T> T getFileJson(File file, Type type) {
public static <T> T getFileJson(File file, TypeReference<T> type) {
try {
InputStream inputStream = new FileInputStream(file);
try (InputStreamReader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8)) {
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.setLenient();
return gsonBuilder.create().fromJson(CharStreams.toString(reader), type);
try (InputStreamReader reader = new InputStreamReader(new BOMInputStream(inputStream), StandardCharsets.UTF_8)) {
return JSONUtil.fromJson(CharStreams.toString(reader), type);
}
} catch (Exception ignored) {
}
@ -57,10 +56,8 @@ public class FileUtils {
public static <T> T getFileJson(File file, Class<T> tClass) {
try {
InputStream inputStream = new FileInputStream(file);
try (InputStreamReader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8)) {
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.setLenient();
return gsonBuilder.create().fromJson(CharStreams.toString(reader), tClass);
try (InputStreamReader reader = new InputStreamReader(new BOMInputStream(inputStream), StandardCharsets.UTF_8)) {
return JSONUtil.fromJson(CharStreams.toString(reader), tClass);
}
} catch (Exception ignored) {
}
@ -73,7 +70,7 @@ public class FileUtils {
File file = new File(context.getFilesDir(), tmpFilename);
FileOutputStream outputStream = new FileOutputStream(file);
try (OutputStreamWriter writer = new OutputStreamWriter(outputStream, StandardCharsets.UTF_8)) {
writer.write(new Gson().toJson(content));
writer.write(JSONUtil.toJson(content));
} finally {
org.zeroturnaround.zip.commons.FileUtils.moveFile(file, new File(context.getFilesDir(), filename));
}
@ -85,18 +82,18 @@ public class FileUtils {
try {
InputStream inputStream = getLocalAsset(context, filename);
try (InputStreamReader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8)) {
return new Gson().fromJson(CharStreams.toString(reader), tClass);
return JSONUtil.fromJson(CharStreams.toString(reader), tClass);
}
} catch (IOException ignored) {
}
return null;
}
public static <T> T getAssetJson(Context context, String filename, Type type) {
public static <T> T getAssetJson(Context context, String filename, TypeReference<T> type) {
try {
InputStream inputStream = getLocalAsset(context, filename);
try (InputStreamReader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8)) {
return new Gson().fromJson(CharStreams.toString(reader), type);
return JSONUtil.fromJson(CharStreams.toString(reader), type);
}
} catch (IOException ignored) {
}

View File

@ -0,0 +1,44 @@
package com.zane.smapiinstaller.utils;
import android.util.Log;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.json.JsonReadFeature;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
public class JSONUtil {
private static final ObjectMapper mapper = new ObjectMapper();
static {
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,false);
mapper.configure(JsonReadFeature.ALLOW_TRAILING_COMMA.mappedFeature(), true);
mapper.configure(JsonReadFeature.ALLOW_MISSING_VALUES.mappedFeature(), true);
mapper.configure(JsonReadFeature.ALLOW_JAVA_COMMENTS.mappedFeature(), true);
}
public static String toJson(Object object) throws Exception {
return mapper.writeValueAsString(object);
}
public static void checkJson(String jsonString) throws JsonProcessingException {
mapper.readValue(jsonString, Object.class);
}
public static <T> T fromJson(String jsonString, Class<T> cls) {
try {
return mapper.readValue(jsonString, cls);
} catch (JsonProcessingException e) {
Log.e("JSON", "Deserialize error", e);
}
return null;
}
public static <T> T fromJson(String jsonString, TypeReference<T> type) {
try {
return mapper.readValue(jsonString, type);
} catch (JsonProcessingException e) {
Log.e("JSON", "Deserialize error", e);
}
return null;
}
}

View File

@ -4,22 +4,41 @@ import com.google.common.base.CharMatcher;
import com.google.common.base.Splitter;
import com.google.common.collect.Iterables;
import org.apache.commons.lang3.StringUtils;
import java.math.BigDecimal;
import java.util.List;
public class VersionUtil {
private static int parseVersionSection(String version) {
private static int compareVersionSection(String sectionA, String sectionB) {
try {
return Integer.parseInt(version);
return Integer.compare(Integer.parseInt(sectionA), Integer.parseInt(sectionB));
} catch (Exception ignored) {
}
List<String> list = Splitter.on("-").splitToList(version);
switch (list.get(0).toLowerCase()) {
case "alpha":
return -2;
case "beta":
List<String> listA = Splitter.on("-").splitToList(sectionA);
List<String> listB = Splitter.on("-").splitToList(sectionB);
int i;
for (i = 0; i < listA.size() && i < listB.size(); i++) {
Integer intA = null;
Integer intB = null;
try {
intA = Integer.parseInt(listA.get(i));
return Integer.compare(intA, Integer.parseInt(listB.get(i)));
} catch (Exception ignored) {
try {
intB = Integer.parseInt(listB.get(i));
} catch (Exception ignored2) {
}
}
if(StringUtils.equals(listA.get(i), listB.get(i)))
continue;
if(intA != null && intB == null)
return 1;
else if(intA == null)
return -1;
return listA.get(i).compareTo(listB.get(i));
}
return 0;
return Integer.compare(listA.size(), listB.size());
}
private static boolean isZero(List<String> versionSections) {
return !Iterables.filter(versionSections, version -> {
@ -44,10 +63,16 @@ public class VersionUtil {
}
return 1;
}
int compare = Integer.compare(parseVersionSection(versionSectionsA.get(i)), parseVersionSection(versionSectionsB.get(i)));
int compare = compareVersionSection(versionSectionsA.get(i), versionSectionsB.get(i));
if(compare != 0)
return compare;
}
if(versionSectionsA.size() < versionSectionsB.size()) {
if(isZero(versionSectionsB.subList(versionSectionsA.size(), versionSectionsB.size()))) {
return 0;
}
return -1;
}
return 0;
}
}

View File

@ -53,4 +53,5 @@
<string name="downloading">正在下載: %d KB / %d KB</string>
<string name="menu_about">關於</string>
<string name="android_version_confirm">你的系統版本過老可能會導致0Harmony無效建議升級到安卓6及以上版本</string>
<string name="error_depends_on_mod_version" >The %s is depends on %s %s version or later, please update it first</string>
</resources>

View File

@ -53,4 +53,5 @@
<string name="downloading">正在下載: %d KB / %d KB</string>
<string name="menu_about">關於</string>
<string name="android_version_confirm">你的系統版本過老可能會導致0Harmony無效建議升級到安卓6及以上版本</string>
<string name="error_depends_on_mod_version" >The %s is depends on %s %s version or later, please update it first</string>
</resources>

View File

@ -53,4 +53,5 @@
<string name="downloading">正在下载: %d KB / %d KB</string>
<string name="menu_about">关于</string>
<string name="android_version_confirm">你的系统版本过老可能会导致0Harmony无效建议升级到安卓6及以上版本</string>
<string name="error_depends_on_mod_version" >%s依赖%s %s版本请先更新它</string>
</resources>

View File

@ -56,4 +56,5 @@
<string name="hello_blank_fragment">Hello blank fragment</string>
<string name="menu_about">About</string>
<string name="android_version_confirm">You device system version is too old for MonoMod, this may leads to crash of 0Harmony framework, update to Android M or later if possible</string>
<string name="error_depends_on_mod_version">The %s is depends on %s %s version or later, please update it first</string>
</resources>