瀏覽代碼

mqtt
日志上传下载

ccc 2 月之前
父節點
當前提交
fd1eecbe0f
共有 71 個文件被更改,包括 4147 次插入47 次删除
  1. 5 3
      app/src/main/java/com/sunzee/app/AppApplication.kt
  2. 2 2
      buildSrc/src/main/kotlin/com/quyunshuo/sbm10/buildsrc/ProjectBuildConfig.kt
  3. 6 0
      lib_base/build.gradle
  4. 157 0
      lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/GsonFactory.java
  5. 41 0
      lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/ParseExceptionCallback.java
  6. 27 0
      lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/constructor/ConcurrentMapConstructor.java
  7. 26 0
      lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/constructor/ConcurrentSkipListMapConstructor.java
  8. 40 0
      lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/constructor/EnumMapConstructor.java
  9. 40 0
      lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/constructor/EnumSetConstructor.java
  10. 24 0
      lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/constructor/ExceptionConstructor.java
  11. 28 0
      lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/constructor/InstanceCreatorConstructor.java
  12. 120 0
      lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/constructor/KotlinDataClassDefaultValueConstructor.kt
  13. 26 0
      lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/constructor/LinkedHashMapConstructor.java
  14. 25 0
      lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/constructor/LinkedTreeMapConstructor.java
  15. 27 0
      lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/constructor/ListConstructor.java
  16. 248 0
      lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/constructor/MainConstructor.java
  17. 27 0
      lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/constructor/QueueConstructor.java
  18. 56 0
      lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/constructor/ReflectCreatorConstructor.java
  19. 42 0
      lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/constructor/ReflectSafeCreatorConstructor.java
  20. 27 0
      lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/constructor/SetConstructor.java
  21. 27 0
      lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/constructor/SortedMapConstructor.java
  22. 27 0
      lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/constructor/SortedSetConstructor.java
  23. 43 0
      lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/data/BigDecimalTypeAdapter.java
  24. 50 0
      lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/data/BooleanTypeAdapter.java
  25. 43 0
      lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/data/DoubleTypeAdapter.java
  26. 43 0
      lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/data/FloatTypeAdapter.java
  27. 54 0
      lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/data/IntegerTypeAdapter.java
  28. 45 0
      lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/data/JSONArrayTypeAdapter.java
  29. 45 0
      lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/data/JSONObjectTypeAdapter.java
  30. 54 0
      lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/data/LongTypeAdapter.java
  31. 41 0
      lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/data/StringTypeAdapter.java
  32. 94 0
      lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/element/CollectionTypeAdapter.java
  33. 59 0
      lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/element/CollectionTypeAdapterFactory.java
  34. 179 0
      lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/element/MapTypeAdapter.java
  35. 63 0
      lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/element/MapTypeAdapterFactory.java
  36. 109 0
      lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/element/ReflectiveTypeAdapter.java
  37. 137 0
      lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/element/ReflectiveTypeAdapterFactory.java
  38. 96 0
      lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/element/TypeAdapterRuntimeTypeWrapper.java
  39. 36 0
      lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/other/AutoToNumberStrategy.java
  40. 46 0
      lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/other/ReflectiveFieldBound.java
  41. 202 0
      lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/other/ReflectiveTypeUtils.java
  42. 315 0
      lib_base/src/main/java/com/quyunshuo/sbm10/base/utils/JsonUtils.java
  43. 5 0
      lib_base/src/main/java/com/quyunshuo/sbm10/base/utils/commons/BinaryDecoder.java
  44. 5 0
      lib_base/src/main/java/com/quyunshuo/sbm10/base/utils/commons/BinaryEncoder.java
  45. 32 0
      lib_base/src/main/java/com/quyunshuo/sbm10/base/utils/commons/CharSequenceUtils.java
  46. 5 0
      lib_base/src/main/java/com/quyunshuo/sbm10/base/utils/commons/Decoder.java
  47. 21 0
      lib_base/src/main/java/com/quyunshuo/sbm10/base/utils/commons/DecoderException.java
  48. 610 0
      lib_base/src/main/java/com/quyunshuo/sbm10/base/utils/commons/DigestUtils.java
  49. 5 0
      lib_base/src/main/java/com/quyunshuo/sbm10/base/utils/commons/Encoder.java
  50. 20 0
      lib_base/src/main/java/com/quyunshuo/sbm10/base/utils/commons/EncoderException.java
  51. 216 0
      lib_base/src/main/java/com/quyunshuo/sbm10/base/utils/commons/Hex.java
  52. 190 0
      lib_base/src/main/java/com/quyunshuo/sbm10/base/utils/commons/StringUtils.java
  53. 5 0
      lib_common/src/main/java/com/quyunshuo/sbm10/common/constant/MqName.kt
  54. 115 0
      lib_common/src/main/java/com/quyunshuo/sbm10/common/util/CustomFileNameGenerator.kt
  55. 4 1
      lib_common/src/main/java/com/quyunshuo/sbm10/common/util/FileUtil.kt
  56. 17 17
      lib_common/src/main/java/com/quyunshuo/sbm10/common/util/LogUtils.java
  57. 11 3
      lib_common/src/main/java/com/quyunshuo/sbm10/common/util/XLogUtil.kt
  58. 1 2
      module_backstage/src/main/java/com/module/backstage/activity/setting/SettingActivity.kt
  59. 1 1
      module_home/build.gradle
  60. 5 2
      module_home/src/main/java/com/quyunshuo/module/home/enums/LogoEnum.kt
  61. 1 2
      module_home/src/main/java/com/quyunshuo/module/home/fragment/fragment/BuyFragment.kt
  62. 1 2
      module_home/src/main/java/com/quyunshuo/module/home/fragment/fragment/HomeFragment.kt
  63. 2 3
      module_home/src/main/java/com/quyunshuo/module/home/fragment/fragment/MakeFragment.kt
  64. 1 2
      module_home/src/main/java/com/quyunshuo/module/home/fragment/fragment/UserLoginFragment.kt
  65. 6 0
      module_home/src/main/java/com/quyunshuo/module/home/getui/MqttBaseBean.kt
  66. 1 1
      module_home/src/main/java/com/quyunshuo/module/home/service/ManageMqtt.kt
  67. 7 4
      module_home/src/main/java/com/quyunshuo/module/home/service/MqService.kt
  68. 10 0
      module_home/src/main/java/com/quyunshuo/module/home/service/MqServiceViewModel.kt
  69. 48 0
      module_home/src/main/java/com/quyunshuo/module/home/utils/RemotePushUtil.kt
  70. 0 1
      serialport-api/src/main/java/com/hboxs/serialport/sbc/VboxSerialPortReadThread.java
  71. 0 1
      serialport-api/src/main/java/com/hboxs/serialport/sbc/VboxSerialPortSendQueue.java

+ 5 - 3
app/src/main/java/com/sunzee/app/AppApplication.kt

@@ -4,6 +4,7 @@ import android.app.ActivityManager
 import android.content.Context
 import android.content.Intent
 import android.os.Build
+import android.os.Environment
 import android.os.Process
 import android.text.TextUtils
 import android.util.Log
@@ -15,7 +16,6 @@ import com.hjq.http.request.HttpRequest
 import com.hjq.toast.Toaster
 import com.quyunshuo.sbm10.base.BaseApplication
 import com.quyunshuo.sbm10.common.constant.Heartbeat
-import com.quyunshuo.sbm10.common.util.FileUtil
 import com.quyunshuo.sbm10.common.util.XLogUtil
 import com.quyunshuo.module.home.service.GlobalService
 import com.quyunshuo.module.home.service.MqService
@@ -23,6 +23,7 @@ import dagger.hilt.android.HiltAndroidApp
 import okhttp3.OkHttpClient
 import okhttp3.Response
 import org.greenrobot.eventbus.EventBus
+import java.io.File
 import java.lang.reflect.Type
 
 
@@ -40,6 +41,8 @@ class AppApplication : BaseApplication() {
     override fun onCreate() {
         instances = this
         if (isAppMainProcess()) {
+            XLogUtil.init()
+
             // 开启EventBusAPT,优化反射效率 当组件作为App运行时需要将添加的Index注释掉 因为找不到对应的类了
             EventBus
                 .builder()
@@ -51,7 +54,7 @@ class AppApplication : BaseApplication() {
             //打开串口
             connectDevice()
             //创建设备编号
-            Heartbeat.deviceId = FileUtil.getDeviceId()
+            Heartbeat.deviceId = XLogUtil.getDeviceId()
             initEasyOkHttp()
             val intent = Intent(this, GlobalService::class.java)
             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
@@ -61,7 +64,6 @@ class AppApplication : BaseApplication() {
             }
             //开启MQ
             startService(Intent(this, MqService::class.java))
-            XLogUtil.init()
         }
 
         super.onCreate()

+ 2 - 2
buildSrc/src/main/kotlin/com/quyunshuo/sbm10/buildsrc/ProjectBuildConfig.kt

@@ -11,8 +11,8 @@ object ProjectBuildConfig {
     const val applicationId = "com.quyunshuo.sbm10"
     const val minSdkVersion = 21
     const val targetSdkVersion = 29
-    const val versionCode = 5
-    const val versionName = "1.0.5"
+    const val versionCode = 6
+    const val versionName = "1.0.6"
     const val isAppMode = false
     /**
      * 项目当前的版本状态

+ 6 - 0
lib_base/build.gradle

@@ -95,4 +95,10 @@ dependencies {
     kapt DependencyConfig.JetPack.LifecycleCompilerAPT
 
     debugApi DependencyConfig.GitHub.LeakCanary
+
+    api 'org.jetbrains.kotlin:kotlin-reflect:1.5.10'
+    api 'com.google.code.gson:gson:2.10.1'
+    api ('com.qiniu:qiniu-android-sdk:8.8.+'){
+        exclude (group: 'com.squareup.okhttp3', module: 'okhttp')
+    }
 }

+ 157 - 0
lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/GsonFactory.java

@@ -0,0 +1,157 @@
+package com.quyunshuo.sbm10.base.factory;
+
+import com.google.gson.FieldNamingPolicy;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.InstanceCreator;
+import com.google.gson.ReflectionAccessFilter;
+import com.google.gson.ToNumberStrategy;
+import com.google.gson.TypeAdapterFactory;
+import com.google.gson.internal.Excluder;
+import com.google.gson.internal.bind.TypeAdapters;
+import com.quyunshuo.sbm10.base.factory.constructor.MainConstructor;
+import com.quyunshuo.sbm10.base.factory.data.BigDecimalTypeAdapter;
+import com.quyunshuo.sbm10.base.factory.data.BooleanTypeAdapter;
+import com.quyunshuo.sbm10.base.factory.data.DoubleTypeAdapter;
+import com.quyunshuo.sbm10.base.factory.data.FloatTypeAdapter;
+import com.quyunshuo.sbm10.base.factory.data.IntegerTypeAdapter;
+import com.quyunshuo.sbm10.base.factory.data.JSONArrayTypeAdapter;
+import com.quyunshuo.sbm10.base.factory.data.JSONObjectTypeAdapter;
+import com.quyunshuo.sbm10.base.factory.data.LongTypeAdapter;
+import com.quyunshuo.sbm10.base.factory.data.StringTypeAdapter;
+import com.quyunshuo.sbm10.base.factory.element.CollectionTypeAdapterFactory;
+import com.quyunshuo.sbm10.base.factory.element.MapTypeAdapterFactory;
+import com.quyunshuo.sbm10.base.factory.element.ReflectiveTypeAdapterFactory;
+import com.quyunshuo.sbm10.base.factory.other.AutoToNumberStrategy;
+
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+import java.lang.reflect.Type;
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * author : Android 轮子哥
+ * github : https://github.com/getActivity/GsonFactory
+ * time   : 2020/11/10
+ * desc   : Gson 解析容错适配器
+ */
+@SuppressWarnings("unused")
+public final class GsonFactory {
+
+    private static final HashMap<Type, InstanceCreator<?>> INSTANCE_CREATORS = new HashMap<>(0);
+
+    private static final List<TypeAdapterFactory> TYPE_ADAPTER_FACTORIES = new ArrayList<>();
+
+    private static final List<ReflectionAccessFilter> REFLECTION_ACCESS_FILTERS = new ArrayList<>();
+
+    private static ToNumberStrategy sObjectToNumberStrategy = new AutoToNumberStrategy();
+
+    private static ParseExceptionCallback sParseExceptionCallback;
+
+    private static volatile Gson sGson;
+
+    private GsonFactory() {
+    }
+
+    /**
+     * 获取单例的 Gson 对象
+     */
+    public static Gson getSingletonGson() {
+        // 加入双重校验锁
+        if (sGson == null) {
+            synchronized (GsonFactory.class) {
+                if (sGson == null) {
+                    sGson = newGsonBuilder().create();
+                }
+            }
+        }
+        return sGson;
+    }
+
+    /**
+     * 设置单例的 Gson 对象
+     */
+    public static void setSingletonGson(Gson gson) {
+        sGson = gson;
+    }
+
+    /**
+     * 设置 Json 解析出错回调对象
+     */
+    public static void setParseExceptionCallback(ParseExceptionCallback callback) {
+        GsonFactory.sParseExceptionCallback = callback;
+    }
+
+    /**
+     * 获取 Json 解析出错回调对象(可能为空)
+     */
+    public static ParseExceptionCallback getParseExceptionCallback() {
+        return sParseExceptionCallback;
+    }
+
+    /**
+     * 注册类型解析适配器
+     */
+    public static void registerTypeAdapterFactory(TypeAdapterFactory factory) {
+        TYPE_ADAPTER_FACTORIES.add(factory);
+    }
+
+    /**
+     * 注册构造函数创建器
+     *
+     * @param type    对象类型
+     * @param creator 实例创建器
+     */
+    public static void registerInstanceCreator(Type type, InstanceCreator<?> creator) {
+        INSTANCE_CREATORS.put(type, creator);
+    }
+
+    /**
+     * 添加反射访问过滤器,同等于 {@link GsonBuilder#addReflectionAccessFilter(ReflectionAccessFilter)}
+     */
+    public static void addReflectionAccessFilter(ReflectionAccessFilter filter) {
+        if (filter == null) {
+            return;
+        }
+        REFLECTION_ACCESS_FILTERS.add(0, filter);
+    }
+
+    /**
+     * 设置自动转换数值类型的策略
+     */
+    public static void setObjectToNumberStrategy(ToNumberStrategy objectToNumberStrategy) {
+        GsonFactory.sObjectToNumberStrategy = objectToNumberStrategy;
+    }
+
+    /**
+     * 创建 Gson 构建对象
+     */
+    public static GsonBuilder newGsonBuilder() {
+        GsonBuilder gsonBuilder = new GsonBuilder();
+        MainConstructor mainConstructor = new MainConstructor(INSTANCE_CREATORS, true, REFLECTION_ACCESS_FILTERS);
+        if (sObjectToNumberStrategy != null) {
+            gsonBuilder.setObjectToNumberStrategy(sObjectToNumberStrategy);
+        }
+        gsonBuilder.registerTypeAdapterFactory(TypeAdapters.newFactory(String.class, new StringTypeAdapter()))
+                .registerTypeAdapterFactory(TypeAdapters.newFactory(boolean.class, Boolean.class, new BooleanTypeAdapter()))
+                .registerTypeAdapterFactory(TypeAdapters.newFactory(int.class, Integer.class, new IntegerTypeAdapter()))
+                .registerTypeAdapterFactory(TypeAdapters.newFactory(long.class, Long.class, new LongTypeAdapter()))
+                .registerTypeAdapterFactory(TypeAdapters.newFactory(float.class, Float.class, new FloatTypeAdapter()))
+                .registerTypeAdapterFactory(TypeAdapters.newFactory(double.class, Double.class, new DoubleTypeAdapter()))
+                .registerTypeAdapterFactory(TypeAdapters.newFactory(BigDecimal.class, new BigDecimalTypeAdapter()))
+                .registerTypeAdapterFactory(new CollectionTypeAdapterFactory(mainConstructor))
+                .registerTypeAdapterFactory(new ReflectiveTypeAdapterFactory(mainConstructor, FieldNamingPolicy.IDENTITY, Excluder.DEFAULT))
+                .registerTypeAdapterFactory(new MapTypeAdapterFactory(mainConstructor, false))
+                .registerTypeAdapterFactory(TypeAdapters.newFactory(JSONObject.class, new JSONObjectTypeAdapter()))
+                .registerTypeAdapterFactory(TypeAdapters.newFactory(JSONArray.class, new JSONArrayTypeAdapter()));
+        // 添加到自定义的类型解析适配器,因为在 GsonBuilder.create 方法中会对 List 进行反转,所以这里需要放到最后的位置上,这样就会优先解析
+        for (TypeAdapterFactory typeAdapterFactory : TYPE_ADAPTER_FACTORIES) {
+            gsonBuilder.registerTypeAdapterFactory(typeAdapterFactory);
+        }
+        return gsonBuilder;
+    }
+}

+ 41 - 0
lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/ParseExceptionCallback.java

@@ -0,0 +1,41 @@
+package com.quyunshuo.sbm10.base.factory;
+
+import com.google.gson.reflect.TypeToken;
+import com.google.gson.stream.JsonToken;
+
+/**
+ *    author : Android 轮子哥
+ *    github : https://github.com/getActivity/GsonFactory
+ *    time   : 2021/02/02
+ *    desc   : Json 解析异常回调类
+ */
+public interface ParseExceptionCallback {
+
+    /**
+     * 对象类型解析异常
+     *
+     * @param typeToken             类型 Token
+     * @param fieldName             字段名称(可能为空)
+     * @param jsonToken             后台给定的类型
+     */
+    void onParseObjectException(TypeToken<?> typeToken, String fieldName, JsonToken jsonToken);
+
+    /**
+     * List item 类型解析异常
+     *
+     * @param typeToken             类型 Token
+     * @param fieldName             字段名称(可能为空)
+     * @param listItemJsonToken     List 条目类型(可能为空)
+     */
+    void onParseListItemException(TypeToken<?> typeToken, String fieldName, JsonToken listItemJsonToken);
+
+    /**
+     * Map item 类型解析异常
+     *
+     * @param typeToken             类型 Token
+     * @param fieldName             字段名称(可能为空)
+     * @param mapItemKey            Map 集合中的 key 值,如果等于为 "null" 字符串,则证明后端返回了错误类型的 key 过来
+     * @param mapItemJsonToken      Map 条目类型(可能为空)
+     */
+    void onParseMapItemException(TypeToken<?> typeToken, String fieldName, String mapItemKey, JsonToken mapItemJsonToken);
+}

+ 27 - 0
lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/constructor/ConcurrentMapConstructor.java

@@ -0,0 +1,27 @@
+package com.quyunshuo.sbm10.base.factory.constructor;
+
+import com.google.gson.internal.ObjectConstructor;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+/**
+ *    author : Android 轮子哥
+ *    github : https://github.com/getActivity/GsonFactory
+ *    time   : 2023/08/01
+ *    desc   : ConcurrentMap 创建器
+ */
+public final class ConcurrentMapConstructor implements ObjectConstructor<ConcurrentMap<?, ?>> {
+
+    private static final ConcurrentMapConstructor INSTANCE = new ConcurrentMapConstructor();
+
+    @SuppressWarnings("unchecked")
+    public static  <T extends ObjectConstructor<?>> T getInstance() {
+        return (T) INSTANCE;
+    }
+
+    @Override
+    public ConcurrentMap<?, ?> construct() {
+        return new ConcurrentHashMap<>();
+    }
+}

+ 26 - 0
lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/constructor/ConcurrentSkipListMapConstructor.java

@@ -0,0 +1,26 @@
+package com.quyunshuo.sbm10.base.factory.constructor;
+
+import com.google.gson.internal.ObjectConstructor;
+
+import java.util.concurrent.ConcurrentSkipListMap;
+
+/**
+ *    author : Android 轮子哥
+ *    github : https://github.com/getActivity/GsonFactory
+ *    time   : 2023/08/01
+ *    desc   : ConcurrentSkipListMap 创建器
+ */
+public final class ConcurrentSkipListMapConstructor implements ObjectConstructor<ConcurrentSkipListMap<?, ?>> {
+
+    private static final ConcurrentSkipListMapConstructor INSTANCE = new ConcurrentSkipListMapConstructor();
+
+    @SuppressWarnings("unchecked")
+    public static  <T extends ObjectConstructor<?>> T getInstance() {
+        return (T) INSTANCE;
+    }
+
+    @Override
+    public ConcurrentSkipListMap<?, ?> construct() {
+        return new ConcurrentSkipListMap<>();
+    }
+}

+ 40 - 0
lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/constructor/EnumMapConstructor.java

@@ -0,0 +1,40 @@
+package com.quyunshuo.sbm10.base.factory.constructor;
+
+import com.google.gson.JsonIOException;
+import com.google.gson.internal.ObjectConstructor;
+
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.EnumMap;
+
+/**
+ *    author : Android 轮子哥
+ *    github : https://github.com/getActivity/GsonFactory
+ *    time   : 2023/08/01
+ *    desc   : EnumMap 创建器
+ */
+public final class EnumMapConstructor<T> implements ObjectConstructor<T> {
+
+    private final Type mType;
+
+    public EnumMapConstructor(Type type) {
+        mType = type;
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public T construct() {
+        if (mType instanceof ParameterizedType) {
+            Type elementType = ((ParameterizedType) mType).getActualTypeArguments()[0];
+            if (elementType instanceof Class) {
+                @SuppressWarnings({"unchecked", "rawtypes"})
+                T map = (T) new EnumMap((Class) elementType);
+                return map;
+            } else {
+                throw new JsonIOException("Invalid EnumMap type: " + mType);
+            }
+        } else {
+            throw new JsonIOException("Invalid EnumMap type: " + mType.toString());
+        }
+    }
+}

+ 40 - 0
lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/constructor/EnumSetConstructor.java

@@ -0,0 +1,40 @@
+package com.quyunshuo.sbm10.base.factory.constructor;
+
+import com.google.gson.JsonIOException;
+import com.google.gson.internal.ObjectConstructor;
+
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.EnumSet;
+
+/**
+ *    author : Android 轮子哥
+ *    github : https://github.com/getActivity/GsonFactory
+ *    time   : 2023/08/01
+ *    desc   : EnumSet 创建器
+ */
+public final class EnumSetConstructor<T> implements ObjectConstructor<T> {
+
+    private final Type mType;
+
+    public EnumSetConstructor(Type type) {
+        mType = type;
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public T construct() {
+        if (mType instanceof ParameterizedType) {
+            Type elementType = ((ParameterizedType) mType).getActualTypeArguments()[0];
+            if (elementType instanceof Class) {
+                @SuppressWarnings({"rawtypes"})
+                T set = (T) EnumSet.noneOf((Class)elementType);
+                return set;
+            } else {
+                throw new JsonIOException("Invalid EnumSet type: " + mType);
+            }
+        } else {
+            throw new JsonIOException("Invalid EnumSet type: " + mType.toString());
+        }
+    }
+}

+ 24 - 0
lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/constructor/ExceptionConstructor.java

@@ -0,0 +1,24 @@
+package com.quyunshuo.sbm10.base.factory.constructor;
+
+import com.google.gson.JsonIOException;
+import com.google.gson.internal.ObjectConstructor;
+
+/**
+ *    author : Android 轮子哥
+ *    github : https://github.com/getActivity/GsonFactory
+ *    time   : 2023/08/01
+ *    desc   : 异常的构造器
+ */
+public final class ExceptionConstructor<T> implements ObjectConstructor<T> {
+
+    private final String mExceptionMessage;
+
+    public ExceptionConstructor(String exceptionMessage) {
+        mExceptionMessage = exceptionMessage;
+    }
+
+    @Override
+    public T construct() {
+        throw new JsonIOException(mExceptionMessage);
+    }
+}

+ 28 - 0
lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/constructor/InstanceCreatorConstructor.java

@@ -0,0 +1,28 @@
+package com.quyunshuo.sbm10.base.factory.constructor;
+
+import com.google.gson.InstanceCreator;
+import com.google.gson.internal.ObjectConstructor;
+
+import java.lang.reflect.Type;
+
+/**
+ *    author : Android 轮子哥
+ *    github : https://github.com/getActivity/GsonFactory
+ *    time   : 2023/08/01
+ *    desc   : 自定义的创建器
+ */
+public final class InstanceCreatorConstructor<T> implements ObjectConstructor<T> {
+
+    private final InstanceCreator<T> mInstanceCreator;
+    private final Type mType;
+
+    public InstanceCreatorConstructor(InstanceCreator<T> instanceCreator, Type type) {
+        mInstanceCreator = instanceCreator;
+        mType = type;
+    }
+
+    @Override
+    public T construct() {
+        return mInstanceCreator.createInstance(mType);
+    }
+}

+ 120 - 0
lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/constructor/KotlinDataClassDefaultValueConstructor.kt

@@ -0,0 +1,120 @@
+package com.hjq.gson.factory.constructor
+
+import com.google.gson.Gson
+import com.google.gson.internal.ObjectConstructor
+import com.google.gson.reflect.TypeToken
+import com.quyunshuo.sbm10.base.factory.constructor.MainConstructor
+import kotlin.reflect.KParameter
+import kotlin.reflect.KType
+import kotlin.reflect.full.primaryConstructor
+import kotlin.reflect.jvm.isAccessible
+import kotlin.reflect.jvm.javaType
+
+/**
+ *    author : Android 轮子哥
+ *    github : https://github.com/getActivity/GsonFactory
+ *    time   : 2023/11/25
+ *    desc   : Kotlin Data Class 创建器,用于处理反射创建 data class 类导致默认值不生效的问题
+ */
+class KotlinDataClassDefaultValueConstructor<T : Any>(private val mainConstructor: MainConstructor, private val gson: Gson, private val rawType: Class<*>) :  ObjectConstructor<T?> {
+
+    companion object {
+        /** 构造函数的字段的默认值 */
+        private val ABSENT_VALUE = Any()
+    }
+
+    override fun construct(): T? {
+        val rawTypeKotlin = rawType.kotlin
+        // 寻找 Kotlin 主构造函数,如果找不到就不往下执行
+        val constructor = rawTypeKotlin.primaryConstructor ?: return null
+        constructor.isAccessible = true
+
+        // 是否初始化构造函数中的全部参数
+        var initializedAllParameters = true
+        val constructorSize = constructor.parameters.size
+        val values = Array<Any?>(constructorSize) { ABSENT_VALUE }
+
+        for (i in 0 until constructorSize) {
+            if (values[i] !== ABSENT_VALUE) {
+                continue
+            }
+
+            val parameter = constructor.parameters[i]
+
+            // 判断这个参数是否携带了默认值
+            if (parameter.isOptional) {
+                initializedAllParameters = false
+                continue
+            }
+
+            // 判断这个参数是否标记为空的
+            if (parameter.type.isMarkedNullable) {
+                values[i] = null
+            } else {
+                // 如果这个参数没有标记为可空的,并且没有携带默认值
+                // 就需要赋一个默认值给它,否则会实例化构造函数会出现崩溃
+                // java.lang.IllegalArgumentException: method XxxBean.<init> argument 3 has type int, got java.lang.Object
+                // 如果是基本数据类型就一定会出现崩溃,如果是对象的话,需要同时满足以下条件才会出现崩溃
+                // 1. 后台给这个参数返回 null 的情况下(这种永远不会出现,因为框架内部处理了)
+                // 2. 获取对象的时候,如果没有做判空,也会出现异常
+                values[i] = getTypeDefaultValue(parameter.type)
+            }
+        }
+
+        // 判断构造函数上面所有的参数是否都携带了默认值
+        val result = if (initializedAllParameters) {
+            // 如果是的话,则传入元素全为 Any 的数组进去
+            constructor.call(*values)
+        } else {
+            // 如果不是的话,就传入自定义顺序的 Map 对象(Key 是参数名,Value 是参数值)进去
+            constructor.callBy(IndexedParameterMap(constructor.parameters, values))
+        }
+
+        return result as T
+    }
+
+    private fun getTypeDefaultValue(type: KType): Any? {
+        when (type.classifier) {
+            String::class -> return ""
+            Boolean::class -> return false
+            Int::class -> return 0
+            Long::class -> return 0L
+            Float::class -> return 0.0f
+            Double::class -> return 0.0
+            Short::class -> return 0.toShort()
+            Byte::class -> return 0.toByte()
+            Char::class -> return '\u0000'
+        }
+
+        val javaType = type.javaType
+        val typeToken = TypeToken.get(javaType) ?: return null
+        val objectConstructor = mainConstructor.get(gson, typeToken) ?: return null
+        return objectConstructor.construct()
+    }
+
+    /** 一个简单的 Map,它使用参数索引而不是排序或哈希。 */
+    class IndexedParameterMap(
+        private val parameterKeys: List<KParameter>,
+        private val parameterValues: Array<Any?>,
+    ) : AbstractMutableMap<KParameter, Any?>() {
+
+        override fun put(key: KParameter, value: Any?): Any? = null
+
+        override val entries: MutableSet<MutableMap.MutableEntry<KParameter, Any?>>
+            get() {
+                val allPossibleEntries = parameterKeys.mapIndexed { index, value ->
+                    SimpleEntry<KParameter, Any?>(value, parameterValues[index])
+                }
+                return allPossibleEntries.filterTo(mutableSetOf()) {
+                    it.value !== ABSENT_VALUE
+                }
+            }
+
+        override fun containsKey(key: KParameter) = parameterValues[key.index] !== ABSENT_VALUE
+
+        override fun get(key: KParameter): Any? {
+            val value = parameterValues[key.index]
+            return if (value !== ABSENT_VALUE) value else null
+        }
+    }
+}

+ 26 - 0
lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/constructor/LinkedHashMapConstructor.java

@@ -0,0 +1,26 @@
+package com.quyunshuo.sbm10.base.factory.constructor;
+
+import com.google.gson.internal.ObjectConstructor;
+
+import java.util.LinkedHashMap;
+
+/**
+ *    author : Android 轮子哥
+ *    github : https://github.com/getActivity/GsonFactory
+ *    time   : 2023/08/01
+ *    desc   : LinkedHashMap 创建器
+ */
+public final class LinkedHashMapConstructor implements ObjectConstructor<LinkedHashMap<?, ?>> {
+
+    private static final LinkedHashMapConstructor INSTANCE = new LinkedHashMapConstructor();
+
+    @SuppressWarnings("unchecked")
+    public static  <T extends ObjectConstructor<?>> T getInstance() {
+        return (T) INSTANCE;
+    }
+
+    @Override
+    public LinkedHashMap<?, ?> construct() {
+        return new LinkedHashMap<>();
+    }
+}

+ 25 - 0
lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/constructor/LinkedTreeMapConstructor.java

@@ -0,0 +1,25 @@
+package com.quyunshuo.sbm10.base.factory.constructor;
+
+import com.google.gson.internal.LinkedTreeMap;
+import com.google.gson.internal.ObjectConstructor;
+
+/**
+ *    author : Android 轮子哥
+ *    github : https://github.com/getActivity/GsonFactory
+ *    time   : 2023/08/01
+ *    desc   : LinkedTreeMap 创建器
+ */
+public final class LinkedTreeMapConstructor implements ObjectConstructor<LinkedTreeMap<?, ?>> {
+
+    private static final LinkedTreeMapConstructor INSTANCE = new LinkedTreeMapConstructor();
+
+    @SuppressWarnings("unchecked")
+    public static  <T extends ObjectConstructor<?>> T getInstance() {
+        return (T) INSTANCE;
+    }
+
+    @Override
+    public LinkedTreeMap<?, ?> construct() {
+        return new LinkedTreeMap<>();
+    }
+}

+ 27 - 0
lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/constructor/ListConstructor.java

@@ -0,0 +1,27 @@
+package com.quyunshuo.sbm10.base.factory.constructor;
+
+import com.google.gson.internal.ObjectConstructor;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ *    author : Android 轮子哥
+ *    github : https://github.com/getActivity/GsonFactory
+ *    time   : 2023/08/01
+ *    desc   : List 创建器
+ */
+public final class ListConstructor implements ObjectConstructor<List<?>> {
+
+    private static final ListConstructor INSTANCE = new ListConstructor();
+
+    @SuppressWarnings("unchecked")
+    public static  <T extends ObjectConstructor<?>> T getInstance() {
+        return (T) INSTANCE;
+    }
+
+    @Override
+    public List<?> construct() {
+        return new ArrayList<>();
+    }
+}

+ 248 - 0
lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/constructor/MainConstructor.java

@@ -0,0 +1,248 @@
+package com.quyunshuo.sbm10.base.factory.constructor;
+
+import com.google.gson.Gson;
+import com.google.gson.InstanceCreator;
+import com.google.gson.ReflectionAccessFilter;
+import com.google.gson.ReflectionAccessFilter.FilterResult;
+import com.google.gson.internal.ObjectConstructor;
+import com.google.gson.internal.ReflectionAccessFilterHelper;
+import com.google.gson.internal.reflect.ReflectionHelper;
+import com.google.gson.reflect.TypeToken;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.Collection;
+import java.util.EnumMap;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Queue;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.SortedSet;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ConcurrentNavigableMap;
+
+/**
+ *    author : Android 轮子哥
+ *    github : https://github.com/getActivity/GsonFactory
+ *    time   : 2022/03/30
+ *    desc   : 构造函数构造器,参考:{@link com.google.gson.internal.ConstructorConstructor}
+ */
+public final class MainConstructor {
+    private final Map<Type, InstanceCreator<?>> mInstanceCreators;
+    private final boolean mUseJdkUnsafe;
+    private final List<ReflectionAccessFilter> mReflectionFilters;
+
+    public MainConstructor(Map<Type, InstanceCreator<?>> instanceCreators, boolean useJdkUnsafe, List<ReflectionAccessFilter> reflectionFilters) {
+        mInstanceCreators = instanceCreators;
+        mUseJdkUnsafe = useJdkUnsafe;
+        mReflectionFilters = reflectionFilters;
+    }
+
+    /**
+     * Check if the class can be instantiated by Unsafe allocator. If the instance has interface or abstract modifiers
+     * return an exception message.
+     * @param c instance of the class to be checked
+     * @return if instantiable {@code null}, else a non-{@code null} exception message
+     */
+    static String checkInstantiable(Class<?> c) {
+        int modifiers = c.getModifiers();
+        if (Modifier.isInterface(modifiers)) {
+            return "Interfaces can't be instantiated! Register an InstanceCreator "
+                + "or a TypeAdapter for this type. Interface name: " + c.getName();
+        }
+        if (Modifier.isAbstract(modifiers)) {
+            return "Abstract classes can't be instantiated! Register an InstanceCreator "
+                + "or a TypeAdapter for this type. Class name: " + c.getName();
+        }
+        return null;
+    }
+
+    public <T> ObjectConstructor<T> get(Gson gson, TypeToken<T> typeToken) {
+        final Type type = typeToken.getType();
+        final Class<? super T> rawType = typeToken.getRawType();
+
+        // first try an instance creator
+
+        @SuppressWarnings("unchecked")
+        final InstanceCreator<T> typeCreator = (InstanceCreator<T>) mInstanceCreators.get(type);
+        if (typeCreator != null) {
+            return new InstanceCreatorConstructor<>(typeCreator, type);
+        }
+
+        // Next try raw type match for instance creators
+        @SuppressWarnings("unchecked") // types must agree
+        final InstanceCreator<T> rawTypeCreator =
+            (InstanceCreator<T>) mInstanceCreators.get(rawType);
+        if (rawTypeCreator != null) {
+            return new InstanceCreatorConstructor<>(rawTypeCreator, type);
+        }
+
+        // First consider special constructors before checking for no-args constructors
+        // below to avoid matching internal no-args constructors which might be added in
+        // future JDK versions
+        ObjectConstructor<T> specialConstructor = newSpecialCollectionConstructor(type, rawType);
+        if (specialConstructor != null) {
+            return specialConstructor;
+        }
+
+        ReflectionAccessFilter.FilterResult filterResult = ReflectionAccessFilterHelper.getFilterResult(mReflectionFilters, rawType);
+        ObjectConstructor<T> defaultConstructor = newDefaultConstructor(this, gson, rawType, filterResult);
+        if (defaultConstructor != null) {
+            return defaultConstructor;
+        }
+
+        ObjectConstructor<T> defaultImplementation = newDefaultImplementationConstructor(type, rawType);
+        if (defaultImplementation != null) {
+            return defaultImplementation;
+        }
+
+        // Check whether type is instantiable; otherwise ReflectionAccessFilter recommendation
+        // of adjusting filter suggested below is irrelevant since it would not solve the problem
+        final String exceptionMessage = checkInstantiable(rawType);
+        if (exceptionMessage != null) {
+            return new ExceptionConstructor<>(exceptionMessage);
+        }
+
+        // Consider usage of Unsafe as reflection, so don't use if BLOCK_ALL
+        // Additionally, since it is not calling any constructor at all, don't use if BLOCK_INACCESSIBLE
+        if (filterResult == ReflectionAccessFilter.FilterResult.ALLOW) {
+            // finally try unsafe
+            return newUnsafeAllocator(gson, rawType);
+        } else {
+            final String message = "Unable to create instance of " + rawType + "; ReflectionAccessFilter "
+                + "does not permit using reflection or Unsafe. Register an InstanceCreator or a TypeAdapter "
+                + "for this type or adjust the access filter to allow using reflection.";
+            return new ExceptionConstructor<>(message);
+        }
+    }
+
+    /**
+     * 为没有公共无参数构造函数的特殊 JDK 集合类型创建构造函数
+     */
+    private static <T> ObjectConstructor<T> newSpecialCollectionConstructor(final Type type, Class<? super T> rawType) {
+        if (EnumSet.class.isAssignableFrom(rawType)) {
+            return new EnumSetConstructor<>(type);
+        }
+        // Only support creation of EnumMap, but not of custom subtypes; for them type parameters
+        // and constructor parameter might have completely different meaning
+        else if (rawType == EnumMap.class) {
+            return new EnumMapConstructor<>(type);
+        }
+
+        return null;
+    }
+
+    private static <T> ObjectConstructor<T> newDefaultConstructor(MainConstructor mainConstructor, Gson gson, Class<? super T> rawType, FilterResult filterResult) {
+        // Cannot invoke constructor of abstract class
+        if (Modifier.isAbstract(rawType.getModifiers())) {
+            return null;
+        }
+
+        final Constructor<? super T> constructor;
+        try {
+            constructor = rawType.getDeclaredConstructor();
+        } catch (NoSuchMethodException e) {
+            return null;
+        }
+
+        boolean canAccess = filterResult == FilterResult.ALLOW || (ReflectionAccessFilterHelper.canAccess(constructor, null)
+            // Be a bit more lenient here for BLOCK_ALL; if constructor is accessible and public then allow calling it
+            && (filterResult != FilterResult.BLOCK_ALL || Modifier.isPublic(constructor.getModifiers())));
+
+        if (!canAccess) {
+            final String message = "Unable to invoke no-args constructor of " + rawType + "; "
+                + "constructor is not accessible and ReflectionAccessFilter does not permit making "
+                + "it accessible. Register an InstanceCreator or a TypeAdapter for this type, change "
+                + "the visibility of the constructor or adjust the access filter.";
+            return new ExceptionConstructor<>(message);
+        }
+
+        // Only try to make accessible if allowed; in all other cases checks above should
+        // have verified that constructor is accessible
+        if (filterResult == FilterResult.ALLOW) {
+            final String exceptionMessage = ReflectionHelper.tryMakeAccessible(constructor);
+            if (exceptionMessage != null) {
+                /*
+                 * Create ObjectConstructor which throws exception.
+                 * This keeps backward compatibility (compared to returning `null` which
+                 * would then choose another way of creating object).
+                 * And it supports types which are only serialized but not deserialized
+                 * (compared to directly throwing exception here), e.g. when runtime type
+                 * of object is inaccessible, but compile-time type is accessible.
+                 */
+
+                // New exception is created every time to avoid keeping reference
+                // to exception with potentially long stack trace, causing a
+                // memory leak
+                return new ExceptionConstructor<>(exceptionMessage);
+            }
+        }
+
+        return new ReflectCreatorConstructor<>(mainConstructor, gson, rawType, constructor);
+    }
+
+    /**
+     * Constructors for common interface types like Map and List and their
+     * subtypes.
+     */
+    private static <T> ObjectConstructor<T> newDefaultImplementationConstructor(
+        final Type type, Class<? super T> rawType) {
+
+        /*
+         * IMPORTANT: Must only create instances for classes with public no-args constructor.
+         * For classes with special constructors / factory methods (e.g. EnumSet)
+         * `newSpecialCollectionConstructor` defined above must be used, to avoid no-args
+         * constructor check (which is called before this method) detecting internal no-args
+         * constructors which might be added in a future JDK version
+         */
+
+        if (Collection.class.isAssignableFrom(rawType)) {
+            if (SortedSet.class.isAssignableFrom(rawType)) {
+                return SortedSetConstructor.getInstance();
+            } else if (Set.class.isAssignableFrom(rawType)) {
+                return SetConstructor.getInstance();
+            } else if (Queue.class.isAssignableFrom(rawType)) {
+                return QueueConstructor.getInstance();
+            } else {
+                return ListConstructor.getInstance();
+            }
+        }
+
+        if (Map.class.isAssignableFrom(rawType)) {
+            if (ConcurrentNavigableMap.class.isAssignableFrom(rawType)) {
+                return ConcurrentSkipListMapConstructor.getInstance();
+            } else if (ConcurrentMap.class.isAssignableFrom(rawType)) {
+                return ConcurrentMapConstructor.getInstance();
+            } else if (SortedMap.class.isAssignableFrom(rawType)) {
+                return SortedMapConstructor.getInstance();
+            } else if (type instanceof ParameterizedType && !(String.class.isAssignableFrom(
+                TypeToken.get(((ParameterizedType) type).getActualTypeArguments()[0]).getRawType()))) {
+                return LinkedHashMapConstructor.getInstance();
+            } else {
+                return LinkedTreeMapConstructor.getInstance();
+            }
+        }
+
+        return null;
+    }
+
+    private <T> ObjectConstructor<T> newUnsafeAllocator(Gson gson, final Class<? super T> rawType) {
+        if (mUseJdkUnsafe) {
+            return new ReflectSafeCreatorConstructor<>(this, gson, rawType);
+        } else {
+            final String exceptionMessage = "Unable to create instance of " + rawType + "; usage of JDK Unsafe "
+                + "is disabled. Registering an InstanceCreator or a TypeAdapter for this type, adding a no-args "
+                + "constructor, or enabling usage of JDK Unsafe may fix this problem.";
+            return new ExceptionConstructor<>(exceptionMessage);
+        }
+    }
+
+    @Override
+    public String toString() {
+        return mInstanceCreators.toString();
+    }
+}

+ 27 - 0
lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/constructor/QueueConstructor.java

@@ -0,0 +1,27 @@
+package com.quyunshuo.sbm10.base.factory.constructor;
+
+import com.google.gson.internal.ObjectConstructor;
+
+import java.util.ArrayDeque;
+import java.util.Queue;
+
+/**
+ *    author : Android 轮子哥
+ *    github : https://github.com/getActivity/GsonFactory
+ *    time   : 2023/08/01
+ *    desc   : Queue 创建器
+ */
+public final class QueueConstructor implements ObjectConstructor<Queue<?>> {
+
+    private static final QueueConstructor INSTANCE = new QueueConstructor();
+
+    @SuppressWarnings("unchecked")
+    public static  <T extends ObjectConstructor<?>> T getInstance() {
+        return (T) INSTANCE;
+    }
+
+    @Override
+    public Queue<?> construct() {
+        return new ArrayDeque<>();
+    }
+}

+ 56 - 0
lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/constructor/ReflectCreatorConstructor.java

@@ -0,0 +1,56 @@
+package com.quyunshuo.sbm10.base.factory.constructor;
+
+import com.google.gson.Gson;
+import com.google.gson.internal.ObjectConstructor;
+import com.google.gson.internal.reflect.ReflectionHelper;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+
+/**
+ *    author : Android 轮子哥
+ *    github : https://github.com/getActivity/GsonFactory
+ *    time   : 2023/08/01
+ *    desc   : 反射创建器
+ */
+public final class ReflectCreatorConstructor<T> implements ObjectConstructor<T> {
+
+    private final ObjectConstructor<T> mKotlinDataClassDefaultValueConstructor;
+
+    private final Constructor<? super T> mConstructor;
+
+    public ReflectCreatorConstructor(MainConstructor mainConstructor, Gson gson, Class<? super T> rawType, Constructor<? super T> constructor) {
+        mConstructor = constructor;
+        mKotlinDataClassDefaultValueConstructor = new com.hjq.gson.factory.constructor.KotlinDataClassDefaultValueConstructor<>(mainConstructor, gson, rawType);
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public T construct() {
+        T instance = mKotlinDataClassDefaultValueConstructor.construct();
+
+        if (instance != null) {
+            return instance;
+        }
+
+        try {
+            instance = (T) mConstructor.newInstance();
+            return instance;
+        }
+        // Note: InstantiationException should be impossible because check at start of method made sure
+        //   that class is not abstract
+        catch (InstantiationException e) {
+            throw new RuntimeException("Failed to invoke constructor '" + ReflectionHelper.constructorToString(
+                mConstructor) + "'"
+                + " with no args", e);
+        } catch (InvocationTargetException e) {
+            // don't wrap if cause is unchecked?
+            // JsonParseException ?
+            throw new RuntimeException("Failed to invoke constructor '" + ReflectionHelper.constructorToString(
+                mConstructor) + "'"
+                + " with no args", e.getCause());
+        } catch (IllegalAccessException e) {
+            throw ReflectionHelper.createExceptionForUnexpectedIllegalAccess(e);
+        }
+    }
+}

+ 42 - 0
lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/constructor/ReflectSafeCreatorConstructor.java

@@ -0,0 +1,42 @@
+package com.quyunshuo.sbm10.base.factory.constructor;
+
+import com.google.gson.Gson;
+import com.google.gson.internal.ObjectConstructor;
+import com.google.gson.internal.UnsafeAllocator;
+
+/**
+ *    author : Android 轮子哥
+ *    github : https://github.com/getActivity/GsonFactory
+ *    time   : 2023/08/01
+ *    desc   : 反射(安全)创建器
+ */
+public final class ReflectSafeCreatorConstructor<T> implements ObjectConstructor<T> {
+
+    private final ObjectConstructor<T> mKotlinDataClassDefaultValueConstructor;
+
+    private final Class<? super T> mRawType;
+
+    public ReflectSafeCreatorConstructor(MainConstructor mainConstructor, Gson gson, Class<? super T> rawType) {
+        mRawType = rawType;
+        mKotlinDataClassDefaultValueConstructor = new com.hjq.gson.factory.constructor.KotlinDataClassDefaultValueConstructor<>(mainConstructor, gson, rawType);
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public T construct() {
+        T instance = mKotlinDataClassDefaultValueConstructor.construct();
+
+        if (instance != null) {
+            return instance;
+        }
+
+        try {
+            instance = (T) UnsafeAllocator.INSTANCE.newInstance(mRawType);
+            return instance;
+        } catch (Exception e) {
+            throw new RuntimeException(("Unable to create instance of " + mRawType + ". "
+                + "Registering an InstanceCreator or a TypeAdapter for this type, or adding a no-args "
+                + "constructor may fix this problem."), e);
+        }
+    }
+}

+ 27 - 0
lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/constructor/SetConstructor.java

@@ -0,0 +1,27 @@
+package com.quyunshuo.sbm10.base.factory.constructor;
+
+import com.google.gson.internal.ObjectConstructor;
+
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+/**
+ *    author : Android 轮子哥
+ *    github : https://github.com/getActivity/GsonFactory
+ *    time   : 2023/08/01
+ *    desc   : Set 创建器
+ */
+public final class SetConstructor implements ObjectConstructor<Set<?>> {
+
+    private static final SetConstructor INSTANCE = new SetConstructor();
+
+    @SuppressWarnings("unchecked")
+    public static  <T extends ObjectConstructor<?>> T getInstance() {
+        return (T) INSTANCE;
+    }
+
+    @Override
+    public Set<?> construct() {
+        return new LinkedHashSet<>();
+    }
+}

+ 27 - 0
lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/constructor/SortedMapConstructor.java

@@ -0,0 +1,27 @@
+package com.quyunshuo.sbm10.base.factory.constructor;
+
+import com.google.gson.internal.ObjectConstructor;
+
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+/**
+ *    author : Android 轮子哥
+ *    github : https://github.com/getActivity/GsonFactory
+ *    time   : 2023/08/01
+ *    desc   : SortedMap 创建器
+ */
+public final class SortedMapConstructor implements ObjectConstructor<SortedMap<?, ?>> {
+
+    private static final SortedMapConstructor INSTANCE = new SortedMapConstructor();
+
+    @SuppressWarnings("unchecked")
+    public static  <T extends ObjectConstructor<?>> T getInstance() {
+        return (T) INSTANCE;
+    }
+
+    @Override
+    public SortedMap<?, ?> construct() {
+        return new TreeMap<>();
+    }
+}

+ 27 - 0
lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/constructor/SortedSetConstructor.java

@@ -0,0 +1,27 @@
+package com.quyunshuo.sbm10.base.factory.constructor;
+
+import com.google.gson.internal.ObjectConstructor;
+
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+/**
+ *    author : Android 轮子哥
+ *    github : https://github.com/getActivity/GsonFactory
+ *    time   : 2023/08/01
+ *    desc   : SortedSet 创建器
+ */
+public final class SortedSetConstructor implements ObjectConstructor<SortedSet<?>> {
+
+    private static final SortedSetConstructor INSTANCE = new SortedSetConstructor();
+
+    @SuppressWarnings("unchecked")
+    public static  <T extends ObjectConstructor<?>> T getInstance() {
+        return (T) INSTANCE;
+    }
+
+    @Override
+    public SortedSet<?> construct() {
+        return new TreeSet<>();
+    }
+}

+ 43 - 0
lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/data/BigDecimalTypeAdapter.java

@@ -0,0 +1,43 @@
+package com.quyunshuo.sbm10.base.factory.data;
+
+import com.google.gson.TypeAdapter;
+import com.google.gson.stream.JsonReader;
+import com.google.gson.stream.JsonToken;
+import com.google.gson.stream.JsonWriter;
+
+import java.io.IOException;
+import java.math.BigDecimal;
+
+/**
+ *    author : Android 轮子哥
+ *    github : https://github.com/getActivity/GsonFactory
+ *    time   : 2021/01/01
+ *    desc   : BigDecimal 类型解析适配器,参考:{@link com.google.gson.internal.bind.TypeAdapters#BIG_DECIMAL}
+ */
+public class BigDecimalTypeAdapter extends TypeAdapter<BigDecimal> {
+
+    @Override
+    public BigDecimal read(JsonReader in) throws IOException {
+        JsonToken jsonToken = in.peek();
+        switch (jsonToken) {
+            case NUMBER:
+            case STRING:
+                String result = in.nextString();
+                if (result == null || "".equals(result)) {
+                    return new BigDecimal(0);
+                }
+                return new BigDecimal(result);
+            case NULL:
+                in.nextNull();
+                return null;
+            default:
+                in.skipValue();
+                throw new IllegalArgumentException("The current parser is of type BigDecimal, but the data is of type " + jsonToken);
+        }
+    }
+
+    @Override
+    public void write(JsonWriter out, BigDecimal value) throws IOException {
+        out.value(value);
+    }
+}

+ 50 - 0
lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/data/BooleanTypeAdapter.java

@@ -0,0 +1,50 @@
+package com.quyunshuo.sbm10.base.factory.data;
+
+import com.google.gson.TypeAdapter;
+import com.google.gson.stream.JsonReader;
+import com.google.gson.stream.JsonToken;
+import com.google.gson.stream.JsonWriter;
+
+import java.io.IOException;
+
+/**
+ *    author : Android 轮子哥
+ *    github : https://github.com/getActivity/GsonFactory
+ *    time   : 2020/05/05
+ *    desc   : boolean / Boolean 类型解析适配器,参考:{@link com.google.gson.internal.bind.TypeAdapters#BOOLEAN}
+ */
+public class BooleanTypeAdapter extends TypeAdapter<Boolean> {
+
+    @Override
+    public Boolean read(JsonReader in) throws IOException {
+        JsonToken jsonToken = in.peek();
+        switch (jsonToken) {
+            case BOOLEAN:
+                return in.nextBoolean();
+            case STRING:
+                String result = in.nextString();
+                // 如果后台返回 "true" 或者 "TRUE",则处理为 true,否则为 false
+                if (String.valueOf(true).equalsIgnoreCase(result)) {
+                    return true;
+                } else if (String.valueOf(false).equalsIgnoreCase(result)) {
+                    return false;
+                }
+                // 如果是其他类型,则直接不解析,并且抛给上一层做处理
+                throw new IllegalArgumentException("Data parsing failed, unable to convert " + result + " to boolean type");
+            case NUMBER:
+                // 如果后台返回的是非 0 的数值则处理为 true,否则为 false
+                return in.nextInt() != 0;
+            case NULL:
+                in.nextNull();
+                return null;
+            default:
+                in.skipValue();
+                throw new IllegalArgumentException("The current parser is of type Boolean, but the data is of type " + jsonToken);
+        }
+    }
+
+    @Override
+    public void write(JsonWriter out, Boolean value) throws IOException {
+        out.value(value);
+    }
+}

+ 43 - 0
lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/data/DoubleTypeAdapter.java

@@ -0,0 +1,43 @@
+package com.quyunshuo.sbm10.base.factory.data;
+
+import com.google.gson.TypeAdapter;
+import com.google.gson.stream.JsonReader;
+import com.google.gson.stream.JsonToken;
+import com.google.gson.stream.JsonWriter;
+
+import java.io.IOException;
+
+/**
+ *    author : Android 轮子哥
+ *    github : https://github.com/getActivity/GsonFactory
+ *    time   : 2020/05/05
+ *    desc   : double / Double 类型解析适配器,参考:{@link com.google.gson.internal.bind.TypeAdapters#DOUBLE}
+ */
+public class DoubleTypeAdapter extends TypeAdapter<Double> {
+
+    @Override
+    public Double read(JsonReader in) throws IOException {
+        JsonToken jsonToken = in.peek();
+        switch (jsonToken) {
+            case NUMBER:
+                return in.nextDouble();
+            case STRING:
+                String result = in.nextString();
+                if (result == null || "".equals(result)) {
+                    return 0D;
+                }
+                return Double.parseDouble(result);
+            case NULL:
+                in.nextNull();
+                return null;
+            default:
+                in.skipValue();
+                throw new IllegalArgumentException("The current parser is of type Double, but the data is of type " + jsonToken);
+        }
+    }
+
+    @Override
+    public void write(JsonWriter out, Double value) throws IOException {
+        out.value(value);
+    }
+}

+ 43 - 0
lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/data/FloatTypeAdapter.java

@@ -0,0 +1,43 @@
+package com.quyunshuo.sbm10.base.factory.data;
+
+import com.google.gson.TypeAdapter;
+import com.google.gson.stream.JsonReader;
+import com.google.gson.stream.JsonToken;
+import com.google.gson.stream.JsonWriter;
+
+import java.io.IOException;
+
+/**
+ *    author : Android 轮子哥
+ *    github : https://github.com/getActivity/GsonFactory
+ *    time   : 2020/05/05
+ *    desc   : float / Float 类型解析适配器,参考:{@link com.google.gson.internal.bind.TypeAdapters#FLOAT}
+ */
+public class FloatTypeAdapter extends TypeAdapter<Float> {
+
+    @Override
+    public Float read(JsonReader in) throws IOException {
+        JsonToken jsonToken = in.peek();
+        switch (jsonToken) {
+            case NUMBER:
+                return (float) in.nextDouble();
+            case STRING:
+                String result = in.nextString();
+                if (result == null || "".equals(result)) {
+                    return 0F;
+                }
+                return Float.parseFloat(result);
+            case NULL:
+                in.nextNull();
+                return null;
+            default:
+                in.skipValue();
+                throw new IllegalArgumentException("The current parser is of type Float, but the data is of type " + jsonToken);
+        }
+    }
+
+    @Override
+    public void write(JsonWriter out, Float value) throws IOException {
+        out.value(value);
+    }
+}

+ 54 - 0
lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/data/IntegerTypeAdapter.java

@@ -0,0 +1,54 @@
+package com.quyunshuo.sbm10.base.factory.data;
+
+import com.google.gson.TypeAdapter;
+import com.google.gson.stream.JsonReader;
+import com.google.gson.stream.JsonToken;
+import com.google.gson.stream.JsonWriter;
+
+import java.io.IOException;
+import java.math.BigDecimal;
+
+/**
+ *    author : Android 轮子哥
+ *    github : https://github.com/getActivity/GsonFactory
+ *    time   : 2020/05/05
+ *    desc   : int / Integer 类型解析适配器,参考:{@link com.google.gson.internal.bind.TypeAdapters#INTEGER}
+ */
+public class IntegerTypeAdapter extends TypeAdapter<Integer> {
+
+    @Override
+    public Integer read(JsonReader in) throws IOException {
+        JsonToken jsonToken = in.peek();
+        switch (jsonToken) {
+            case NUMBER:
+                try {
+                    return in.nextInt();
+                } catch (NumberFormatException e) {
+                    // 如果带小数点则会抛出这个异常
+                    return (int) in.nextDouble();
+                }
+            case STRING:
+                String result = in.nextString();
+                if (result == null || "".equals(result)) {
+                    return 0;
+                }
+                try {
+                    return Integer.parseInt(result);
+                } catch (NumberFormatException e) {
+                    // 如果带小数点则会抛出这个异常
+                    return (int) new BigDecimal(result).floatValue();
+                }
+            case NULL:
+                in.nextNull();
+                return null;
+            default:
+                in.skipValue();
+                throw new IllegalArgumentException("The current parser is of type Integer, but the data is of type " + jsonToken);
+        }
+    }
+
+    @Override
+    public void write(JsonWriter out, Integer value) throws IOException {
+        out.value(value);
+    }
+}

+ 45 - 0
lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/data/JSONArrayTypeAdapter.java

@@ -0,0 +1,45 @@
+package com.quyunshuo.sbm10.base.factory.data;
+
+import com.google.gson.JsonElement;
+import com.google.gson.TypeAdapter;
+import com.google.gson.internal.bind.TypeAdapters;
+import com.google.gson.stream.JsonReader;
+import com.google.gson.stream.JsonWriter;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+
+import java.io.IOException;
+
+/**
+ *    author : Android 轮子哥
+ *    github : https://github.com/getActivity/GsonFactory
+ *    time   : 2021/09/30
+ *    desc   : JSONObject 类型解析适配器
+ */
+public class JSONArrayTypeAdapter extends TypeAdapter<JSONArray> {
+
+    private static final TypeAdapter<JsonElement> PROXY = TypeAdapters.JSON_ELEMENT;
+
+    @Override
+    public JSONArray read(JsonReader in) throws IOException {
+        JsonElement read = PROXY.read(in);
+        if (read.isJsonArray()) {
+            try {
+                return new JSONArray(read.toString());
+            } catch (JSONException e) {
+                e.printStackTrace();
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public void write(JsonWriter out, JSONArray value) throws IOException {
+        if (value == null) {
+            out.nullValue();
+            return;
+        }
+        PROXY.write(out, PROXY.fromJson(value.toString()));
+    }
+}

+ 45 - 0
lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/data/JSONObjectTypeAdapter.java

@@ -0,0 +1,45 @@
+package com.quyunshuo.sbm10.base.factory.data;
+
+import com.google.gson.JsonElement;
+import com.google.gson.TypeAdapter;
+import com.google.gson.internal.bind.TypeAdapters;
+import com.google.gson.stream.JsonReader;
+import com.google.gson.stream.JsonWriter;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.IOException;
+
+/**
+ *    author : Android 轮子哥
+ *    github : https://github.com/getActivity/GsonFactory
+ *    time   : 2021/09/30
+ *    desc   : JSONObject 类型解析适配器
+ */
+public class JSONObjectTypeAdapter extends TypeAdapter<JSONObject> {
+
+    private static final TypeAdapter<JsonElement> PROXY = TypeAdapters.JSON_ELEMENT;
+
+    @Override
+    public JSONObject read(JsonReader in) throws IOException {
+        JsonElement read = PROXY.read(in);
+        if (read.isJsonObject()) {
+            try {
+                return new JSONObject(read.toString());
+            } catch (JSONException e) {
+                e.printStackTrace();
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public void write(JsonWriter out, JSONObject value) throws IOException {
+        if (value == null) {
+            out.nullValue();
+            return;
+        }
+        PROXY.write(out, PROXY.fromJson(value.toString()));
+    }
+}

+ 54 - 0
lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/data/LongTypeAdapter.java

@@ -0,0 +1,54 @@
+package com.quyunshuo.sbm10.base.factory.data;
+
+import com.google.gson.TypeAdapter;
+import com.google.gson.stream.JsonReader;
+import com.google.gson.stream.JsonToken;
+import com.google.gson.stream.JsonWriter;
+
+import java.io.IOException;
+import java.math.BigDecimal;
+
+/**
+ *    author : Android 轮子哥
+ *    github : https://github.com/getActivity/GsonFactory
+ *    time   : 2020/05/05
+ *    desc   : long / Long 类型解析适配器,参考:{@link com.google.gson.internal.bind.TypeAdapters#LONG}
+ */
+public class LongTypeAdapter extends TypeAdapter<Long> {
+
+    @Override
+    public Long read(JsonReader in) throws IOException {
+        JsonToken jsonToken = in.peek();
+        switch (jsonToken) {
+            case NUMBER:
+                try {
+                    return in.nextLong();
+                } catch (NumberFormatException e) {
+                    // 如果带小数点则会抛出这个异常
+                    return new BigDecimal(in.nextString()).longValue();
+                }
+            case STRING:
+                String result = in.nextString();
+                if (result == null || "".equals(result)) {
+                    return 0L;
+                }
+                try {
+                    return Long.parseLong(result);
+                } catch (NumberFormatException e) {
+                    // 如果带小数点则会抛出这个异常
+                    return new BigDecimal(result).longValue();
+                }
+            case NULL:
+                in.nextNull();
+                return null;
+            default:
+                in.skipValue();
+                throw new IllegalArgumentException("The current parser is of type Long, but the data is of type " + jsonToken);
+        }
+    }
+
+    @Override
+    public void write(JsonWriter out, Long value) throws IOException {
+        out.value(value);
+    }
+}

+ 41 - 0
lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/data/StringTypeAdapter.java

@@ -0,0 +1,41 @@
+package com.quyunshuo.sbm10.base.factory.data;
+
+import com.google.gson.TypeAdapter;
+import com.google.gson.stream.JsonReader;
+import com.google.gson.stream.JsonToken;
+import com.google.gson.stream.JsonWriter;
+
+import java.io.IOException;
+
+/**
+ *    author : Android 轮子哥
+ *    github : https://github.com/getActivity/GsonFactory
+ *    time   : 2020/05/05
+ *    desc   : String 类型解析适配器,参考:{@link com.google.gson.internal.bind.TypeAdapters#STRING}
+ */
+public class StringTypeAdapter extends TypeAdapter<String> {
+
+    @Override
+    public String read(JsonReader in) throws IOException {
+        JsonToken jsonToken = in.peek();
+        switch (jsonToken) {
+            case STRING:
+            case NUMBER:
+                return in.nextString();
+            case BOOLEAN:
+                // 对于布尔类型比较特殊,需要做针对性处理
+                return Boolean.toString(in.nextBoolean());
+            case NULL:
+                in.nextNull();
+                return null;
+            default:
+                in.skipValue();
+                throw new IllegalArgumentException("The current parser is of type String, but the data is of type " + jsonToken);
+        }
+    }
+
+    @Override
+    public void write(JsonWriter out, String value) throws IOException {
+        out.value(value);
+    }
+}

+ 94 - 0
lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/element/CollectionTypeAdapter.java

@@ -0,0 +1,94 @@
+package com.quyunshuo.sbm10.base.factory.element;
+
+import com.google.gson.Gson;
+import com.google.gson.TypeAdapter;
+import com.google.gson.internal.ObjectConstructor;
+import com.google.gson.reflect.TypeToken;
+import com.google.gson.stream.JsonReader;
+import com.google.gson.stream.JsonToken;
+import com.google.gson.stream.JsonWriter;
+import com.quyunshuo.sbm10.base.factory.GsonFactory;
+import com.quyunshuo.sbm10.base.factory.ParseExceptionCallback;
+
+import java.io.IOException;
+import java.lang.reflect.Type;
+import java.util.Collection;
+
+/**
+ *    author : Android 轮子哥
+ *    github : https://github.com/getActivity/GsonFactory
+ *    time   : 2020/12/08
+ *    desc   : Array 解析适配器,参考:{@link com.google.gson.internal.bind.CollectionTypeAdapterFactory.Adapter}
+ */
+public class CollectionTypeAdapter<E> extends TypeAdapter<Collection<E>> {
+
+    private final TypeAdapter<E> mElementTypeAdapter;
+    private final ObjectConstructor<? extends Collection<E>> mObjectConstructor;
+
+    private TypeToken<?> mTypeToken;
+    private String mFieldName;
+
+    public CollectionTypeAdapter(Gson gson, Type elementType, TypeAdapter<E> elementTypeAdapter, ObjectConstructor<? extends Collection<E>> constructor) {
+        mElementTypeAdapter = new TypeAdapterRuntimeTypeWrapper<>(gson, elementTypeAdapter, elementType);
+        mObjectConstructor = constructor;
+    }
+
+    public void setReflectiveType(TypeToken<?> typeToken, String fieldName) {
+        mTypeToken = typeToken;
+        mFieldName = fieldName;
+    }
+
+    @Override
+    public Collection<E> read(JsonReader in) throws IOException {
+        JsonToken jsonToken = in.peek();
+        Collection<E> collection = mObjectConstructor.construct();
+
+        if (jsonToken == JsonToken.NULL) {
+            in.nextNull();
+            return collection;
+        }
+
+        if (jsonToken != JsonToken.BEGIN_ARRAY) {
+            in.skipValue();
+            ParseExceptionCallback callback = GsonFactory.getParseExceptionCallback();
+            if (callback != null) {
+                callback.onParseObjectException(mTypeToken, mFieldName, jsonToken);
+            }
+            return collection;
+        }
+
+        in.beginArray();
+        while (in.hasNext()) {
+            JsonToken itemJsonToken = null;
+            try {
+                // 获取 item 条目的类型
+                itemJsonToken = in.peek();
+                E instance = mElementTypeAdapter.read(in);
+                collection.add(instance);
+            } catch (IllegalArgumentException e) {
+                e.printStackTrace();
+                ParseExceptionCallback callback = GsonFactory.getParseExceptionCallback();
+                if (callback != null) {
+                    callback.onParseListItemException(mTypeToken, mFieldName, itemJsonToken);
+                }
+            }
+        }
+        in.endArray();
+
+        return collection;
+    }
+
+    @Override
+    public void write(JsonWriter out, Collection<E> collection) throws IOException {
+        if (collection == null) {
+            out.nullValue();
+            return;
+        }
+
+        out.beginArray();
+        for (E element : collection) {
+            mElementTypeAdapter.write(out, element);
+        }
+        out.endArray();
+    }
+}

+ 59 - 0
lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/element/CollectionTypeAdapterFactory.java

@@ -0,0 +1,59 @@
+package com.quyunshuo.sbm10.base.factory.element;
+
+import com.google.gson.Gson;
+import com.google.gson.TypeAdapter;
+import com.google.gson.TypeAdapterFactory;
+import com.google.gson.internal.$Gson$Types;
+import com.google.gson.internal.ObjectConstructor;
+import com.google.gson.reflect.TypeToken;
+import com.quyunshuo.sbm10.base.factory.constructor.MainConstructor;
+import com.quyunshuo.sbm10.base.factory.other.ReflectiveTypeUtils;
+
+import java.lang.reflect.GenericArrayType;
+import java.lang.reflect.Type;
+import java.util.Collection;
+
+/**
+ *    author : Android 轮子哥
+ *    github : https://github.com/getActivity/GsonFactory
+ *    time   : 2020/12/08
+ *    desc   : Array 解析适配器,参考:{@link com.google.gson.internal.bind.CollectionTypeAdapterFactory}
+ */
+public class CollectionTypeAdapterFactory implements TypeAdapterFactory {
+
+    private final MainConstructor mMainConstructor;
+
+    public CollectionTypeAdapterFactory(MainConstructor mainConstructor) {
+        mMainConstructor = mainConstructor;
+    }
+
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    @Override
+    public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
+        Type type = typeToken.getType();
+        Class<? super T> rawType = typeToken.getRawType();
+        // 判断是否包含这种类型
+        if (ReflectiveTypeUtils.containsClass(rawType)) {
+            return null;
+        }
+        if (typeToken.getType() instanceof GenericArrayType ||
+                typeToken.getType() instanceof Class &&
+                ((Class<?>) typeToken.getType()).isArray()) {
+            return null;
+        }
+
+        if (!Collection.class.isAssignableFrom(rawType)) {
+            return null;
+        }
+
+        Type elementType = $Gson$Types.getCollectionElementType(type, rawType);
+        TypeAdapter<?> elementTypeAdapter = gson.getAdapter(TypeToken.get(elementType));
+        ObjectConstructor<T> constructor = mMainConstructor.get(gson, typeToken);
+
+        // create() doesn't define a type parameter
+        CollectionTypeAdapter collectionTypeAdapter =
+                new CollectionTypeAdapter(gson, elementType, elementTypeAdapter, constructor);
+        collectionTypeAdapter.setReflectiveType(typeToken, null);
+        return collectionTypeAdapter;
+    }
+}

+ 179 - 0
lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/element/MapTypeAdapter.java

@@ -0,0 +1,179 @@
+package com.quyunshuo.sbm10.base.factory.element;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonPrimitive;
+import com.google.gson.TypeAdapter;
+import com.google.gson.internal.JsonReaderInternalAccess;
+import com.google.gson.internal.ObjectConstructor;
+import com.google.gson.internal.Streams;
+import com.google.gson.reflect.TypeToken;
+import com.google.gson.stream.JsonReader;
+import com.google.gson.stream.JsonToken;
+import com.google.gson.stream.JsonWriter;
+import com.quyunshuo.sbm10.base.factory.GsonFactory;
+import com.quyunshuo.sbm10.base.factory.ParseExceptionCallback;
+
+import java.io.IOException;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ *    author : Android 轮子哥
+ *    github : https://github.com/getActivity/GsonFactory
+ *    time   : 2022/03/30
+ *    desc   : Map 解析适配器,参考:{@link com.google.gson.internal.bind.MapTypeAdapterFactory.Adapter}
+ */
+public class MapTypeAdapter<K, V> extends TypeAdapter<Map<K, V>> {
+
+    private final TypeAdapter<K> mKeyTypeAdapter;
+    private final TypeAdapter<V> mValueTypeAdapter;
+    private final ObjectConstructor<? extends Map<K, V>> mConstructor;
+    private final boolean mComplexMapKeySerialization;
+
+    private TypeToken<?> mTypeToken;
+    private String mFieldName;
+
+    public MapTypeAdapter(Gson context, Type keyType, TypeAdapter<K> keyTypeAdapter,
+                          Type valueType, TypeAdapter<V> valueTypeAdapter,
+                          ObjectConstructor<? extends Map<K, V>> constructor,
+                          boolean complexMapKeySerialization) {
+        mKeyTypeAdapter = new TypeAdapterRuntimeTypeWrapper<>(context, keyTypeAdapter, keyType);
+        mValueTypeAdapter = new TypeAdapterRuntimeTypeWrapper<>(context, valueTypeAdapter, valueType);
+        mConstructor = constructor;
+        mComplexMapKeySerialization = complexMapKeySerialization;
+    }
+
+    public void setReflectiveType(TypeToken<?> typeToken, String fieldName) {
+        mTypeToken = typeToken;
+        mFieldName = fieldName;
+    }
+
+    @Override
+    public Map<K, V> read(JsonReader in) throws IOException {
+        JsonToken jsonToken = in.peek();
+        Map<K, V> map = mConstructor.construct();
+
+        if (jsonToken == JsonToken.NULL) {
+            in.nextNull();
+            return map;
+        }
+
+        if (jsonToken == JsonToken.BEGIN_ARRAY) {
+            in.beginArray();
+            while (in.hasNext()) {
+                if (in.peek() == JsonToken.BEGIN_ARRAY) {
+                    in.beginArray(); // entry array
+                    K key = mKeyTypeAdapter.read(in);
+                    V value = mValueTypeAdapter.read(in);
+                    map.put(key, value);
+                    in.endArray();
+                } else {
+                    in.skipValue();
+                    ParseExceptionCallback callback = GsonFactory.getParseExceptionCallback();
+                    if (callback != null) {
+                        callback.onParseObjectException(mTypeToken, mFieldName, jsonToken);
+                    }
+                }
+            }
+            in.endArray();
+        } else if (jsonToken == JsonToken.BEGIN_OBJECT) {
+            in.beginObject();
+            while (in.hasNext()) {
+                JsonReaderInternalAccess.INSTANCE.promoteNameToValue(in);
+                JsonToken itemJsonToken = null;
+                K key = null;
+                try {
+                    key = mKeyTypeAdapter.read(in);
+                    // 获取 item 条目的类型
+                    itemJsonToken = in.peek();
+                    V value = mValueTypeAdapter.read(in);
+                    map.put(key, value);
+                } catch (IllegalArgumentException e) {
+                    e.printStackTrace();
+                    ParseExceptionCallback callback = GsonFactory.getParseExceptionCallback();
+                    if (callback != null) {
+                        callback.onParseMapItemException(mTypeToken, mFieldName, String.valueOf(key), itemJsonToken);
+                    }
+                }
+            }
+            in.endObject();
+        } else {
+            in.skipValue();
+            ParseExceptionCallback callback = GsonFactory.getParseExceptionCallback();
+            if (callback != null) {
+                callback.onParseObjectException(mTypeToken, mFieldName, jsonToken);
+            }
+        }
+        return map;
+    }
+
+    @Override
+    public void write(JsonWriter out, Map<K, V> map) throws IOException {
+        if (map == null) {
+            out.nullValue();
+            return;
+        }
+
+        if (!mComplexMapKeySerialization) {
+            out.beginObject();
+            for (Map.Entry<K, V> entry : map.entrySet()) {
+                out.name(String.valueOf(entry.getKey()));
+                mValueTypeAdapter.write(out, entry.getValue());
+            }
+            out.endObject();
+            return;
+        }
+
+        boolean hasComplexKeys = false;
+        List<JsonElement> keys = new ArrayList<>(map.size());
+
+        List<V> values = new ArrayList<>(map.size());
+        for (Map.Entry<K, V> entry : map.entrySet()) {
+            JsonElement keyElement = mKeyTypeAdapter.toJsonTree(entry.getKey());
+            keys.add(keyElement);
+            values.add(entry.getValue());
+            hasComplexKeys |= keyElement.isJsonArray() || keyElement.isJsonObject();
+        }
+
+        if (hasComplexKeys) {
+            out.beginArray();
+            for (int i = 0, size = keys.size(); i < size; i++) {
+                out.beginArray(); // entry array
+                Streams.write(keys.get(i), out);
+                mValueTypeAdapter.write(out, values.get(i));
+                out.endArray();
+            }
+            out.endArray();
+        } else {
+            out.beginObject();
+            for (int i = 0, size = keys.size(); i < size; i++) {
+                JsonElement keyElement = keys.get(i);
+                out.name(keyToString(keyElement));
+                mValueTypeAdapter.write(out, values.get(i));
+            }
+            out.endObject();
+        }
+    }
+
+    private String keyToString(JsonElement keyElement) {
+        if (keyElement.isJsonPrimitive()) {
+            JsonPrimitive primitive = keyElement.getAsJsonPrimitive();
+            if (primitive.isNumber()) {
+                return String.valueOf(primitive.getAsNumber());
+            } else if (primitive.isBoolean()) {
+                return Boolean.toString(primitive.getAsBoolean());
+            } else if (primitive.isString()) {
+                return primitive.getAsString();
+            } else {
+                throw new AssertionError();
+            }
+        } else if (keyElement.isJsonNull()) {
+            return "null";
+        } else {
+            throw new AssertionError();
+        }
+    }
+}

+ 63 - 0
lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/element/MapTypeAdapterFactory.java

@@ -0,0 +1,63 @@
+package com.quyunshuo.sbm10.base.factory.element;
+
+import com.google.gson.Gson;
+import com.google.gson.TypeAdapter;
+import com.google.gson.TypeAdapterFactory;
+import com.google.gson.internal.$Gson$Types;
+import com.google.gson.internal.ObjectConstructor;
+import com.google.gson.internal.bind.TypeAdapters;
+import com.google.gson.reflect.TypeToken;
+import com.quyunshuo.sbm10.base.factory.constructor.MainConstructor;
+
+import java.lang.reflect.Type;
+import java.util.Map;
+
+/**
+ *    author : Android 轮子哥
+ *    github : https://github.com/getActivity/GsonFactory
+ *    time   : 2022/03/30
+ *    desc   : Map 解析适配器,参考:{@link com.google.gson.internal.bind.MapTypeAdapterFactory}
+ */
+public class MapTypeAdapterFactory implements TypeAdapterFactory {
+
+   private final MainConstructor mMainConstructor;
+   final boolean mComplexMapKeySerialization;
+
+   public MapTypeAdapterFactory(MainConstructor mainConstructor,
+                                boolean complexMapKeySerialization) {
+      mMainConstructor = mainConstructor;
+      mComplexMapKeySerialization = complexMapKeySerialization;
+   }
+
+   @SuppressWarnings({"unchecked", "rawtypes"})
+   @Override
+   public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
+      Type type = typeToken.getType();
+
+      Class<? super T> rawType = typeToken.getRawType();
+      if (!Map.class.isAssignableFrom(rawType)) {
+         return null;
+      }
+
+      Class<?> rawTypeOfSrc = $Gson$Types.getRawType(type);
+      Type[] keyAndValueTypes = $Gson$Types.getMapKeyAndValueTypes(type, rawTypeOfSrc);
+      TypeAdapter<?> keyAdapter = getKeyAdapter(gson, keyAndValueTypes[0]);
+      TypeAdapter<?> valueAdapter = gson.getAdapter(TypeToken.get(keyAndValueTypes[1]));
+      ObjectConstructor<T> constructor = mMainConstructor.get(gson, typeToken);
+
+      // we don't define a type parameter for the key or value types
+      MapTypeAdapter result = new MapTypeAdapter(gson, keyAndValueTypes[0], keyAdapter,
+              keyAndValueTypes[1], valueAdapter, constructor, mComplexMapKeySerialization);
+      result.setReflectiveType(typeToken, null);
+      return result;
+   }
+
+   /**
+    * Returns a type adapter that writes the value as a string.
+    */
+   private TypeAdapter<?> getKeyAdapter(Gson context, Type keyType) {
+      return (keyType == boolean.class || keyType == Boolean.class)
+              ? TypeAdapters.BOOLEAN_AS_STRING
+              : context.getAdapter(TypeToken.get(keyType));
+   }
+}

+ 109 - 0
lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/element/ReflectiveTypeAdapter.java

@@ -0,0 +1,109 @@
+package com.quyunshuo.sbm10.base.factory.element;
+
+import com.google.gson.JsonSyntaxException;
+import com.google.gson.TypeAdapter;
+import com.google.gson.internal.ObjectConstructor;
+import com.google.gson.reflect.TypeToken;
+import com.google.gson.stream.JsonReader;
+import com.google.gson.stream.JsonToken;
+import com.google.gson.stream.JsonWriter;
+import com.quyunshuo.sbm10.base.factory.GsonFactory;
+import com.quyunshuo.sbm10.base.factory.ParseExceptionCallback;
+import com.quyunshuo.sbm10.base.factory.other.ReflectiveFieldBound;
+
+import java.io.IOException;
+import java.util.Map;
+
+/**
+ *    author : Android 轮子哥
+ *    github : https://github.com/getActivity/GsonFactory
+ *    time   : 2020/12/08
+ *    desc   : Object 解析适配器,参考:{@link com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.Adapter}
+ */
+public class ReflectiveTypeAdapter<T> extends TypeAdapter<T> {
+
+    private final ObjectConstructor<T> mConstructor;
+    private final Map<String, ReflectiveFieldBound> mBoundFields;
+
+    private TypeToken<?> mTypeToken;
+    private String mFieldName;
+
+    public ReflectiveTypeAdapter(ObjectConstructor<T> constructor, Map<String, ReflectiveFieldBound> fields) {
+        mConstructor = constructor;
+        mBoundFields = fields;
+    }
+
+    public void setReflectiveType(TypeToken<?> typeToken, String fieldName) {
+        mTypeToken = typeToken;
+        mFieldName = fieldName;
+    }
+
+    @Override
+    public T read(JsonReader in) throws IOException {
+        JsonToken jsonToken = in.peek();
+
+        if (jsonToken == JsonToken.NULL) {
+            in.nextNull();
+            return null;
+        }
+
+        if (jsonToken != JsonToken.BEGIN_OBJECT) {
+            in.skipValue();
+            ParseExceptionCallback callback = GsonFactory.getParseExceptionCallback();
+            if (callback != null) {
+                callback.onParseObjectException(mTypeToken, mFieldName, jsonToken);
+            }
+            return null;
+        }
+
+        T instance = mConstructor.construct();
+        in.beginObject();
+        while (in.hasNext()) {
+            String name = in.nextName();
+            ReflectiveFieldBound field = mBoundFields.get(name);
+            if (field == null || !field.isDeserialized()) {
+                in.skipValue();
+                continue;
+            }
+
+            JsonToken peek = in.peek();
+
+            try {
+                field.read(in, instance);
+            } catch (IllegalStateException e) {
+                throw new JsonSyntaxException(e);
+            } catch (IllegalAccessException e) {
+                throw new AssertionError(e);
+            } catch (IllegalArgumentException e) {
+                e.printStackTrace();
+                ParseExceptionCallback callback = GsonFactory.getParseExceptionCallback();
+                if (callback != null) {
+                    callback.onParseObjectException(TypeToken.get(instance.getClass()), field.getFieldName(), peek);
+                }
+            }
+        }
+        in.endObject();
+        return instance;
+    }
+
+    @Override
+    public void write(JsonWriter out, T value) throws IOException {
+        if (value == null) {
+            out.nullValue();
+            return;
+        }
+
+        out.beginObject();
+        for (ReflectiveFieldBound fieldBound : mBoundFields.values()) {
+            try {
+                if (fieldBound.writeField(value)) {
+                    out.name(fieldBound.getFieldName());
+                    fieldBound.write(out, value);
+                }
+            } catch (IllegalAccessException e) {
+                throw new AssertionError(e);
+            }
+        }
+        out.endObject();
+    }
+}

+ 137 - 0
lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/element/ReflectiveTypeAdapterFactory.java

@@ -0,0 +1,137 @@
+package com.quyunshuo.sbm10.base.factory.element;
+
+import com.google.gson.FieldNamingStrategy;
+import com.google.gson.Gson;
+import com.google.gson.TypeAdapter;
+import com.google.gson.TypeAdapterFactory;
+import com.google.gson.annotations.JsonAdapter;
+import com.google.gson.internal.$Gson$Types;
+import com.google.gson.internal.Excluder;
+import com.google.gson.reflect.TypeToken;
+import com.quyunshuo.sbm10.base.factory.constructor.MainConstructor;
+import com.quyunshuo.sbm10.base.factory.other.ReflectiveFieldBound;
+import com.quyunshuo.sbm10.base.factory.other.ReflectiveTypeUtils;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.GenericArrayType;
+import java.lang.reflect.Type;
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ *    author : Android 轮子哥
+ *    github : https://github.com/getActivity/GsonFactory
+ *    time   : 2020/12/08
+ *    desc   : Object 解析适配器,参考:{@link com.google.gson.internal.bind.ReflectiveTypeAdapterFactory}
+ */
+public class ReflectiveTypeAdapterFactory implements TypeAdapterFactory {
+
+    private final MainConstructor mMainConstructor;
+    private final FieldNamingStrategy mFieldNamingPolicy;
+    private final Excluder mExcluder;
+
+    public ReflectiveTypeAdapterFactory(MainConstructor mainConstructor,
+                                        FieldNamingStrategy strategy, Excluder excluder) {
+        mMainConstructor = mainConstructor;
+        mFieldNamingPolicy = strategy;
+        mExcluder = excluder;
+    }
+
+    @Override
+    public <T> TypeAdapter<T> create(Gson gson, final TypeToken<T> type) {
+        Class<? super T> raw = type.getRawType();
+
+        // 判断是否包含这种类型
+        if (ReflectiveTypeUtils.containsClass(raw)) {
+            return null;
+        }
+        // 判断是否是数组
+        if (type.getType() instanceof GenericArrayType ||
+                type.getType() instanceof Class &&
+                 ((Class<?>) type.getType()).isArray()) {
+            return null;
+        }
+        // 如果是基本数据类型
+        if (!Object.class.isAssignableFrom(raw)) {
+            return null;
+        }
+        // 如果是 List 类型
+        if (Collection.class.isAssignableFrom(raw)) {
+            return null;
+        }
+        // 如果是 Map 数组
+        if (Map.class.isAssignableFrom(raw)) {
+            return null;
+        }
+        // 判断是否有自定义解析注解
+        JsonAdapter annotation = raw.getAnnotation(JsonAdapter.class);
+        if (annotation != null) {
+            return null;
+        }
+        // 如果是枚举类型
+        if (Enum.class.isAssignableFrom(raw) && raw != Enum.class) {
+            return null;
+        }
+        ReflectiveTypeAdapter<T> reflectiveTypeAdapter =
+                new ReflectiveTypeAdapter<>(mMainConstructor.get(gson, type), getBoundFields(gson, type, raw));
+        reflectiveTypeAdapter.setReflectiveType(type, null);
+        return reflectiveTypeAdapter;
+    }
+
+    private Map<String, ReflectiveFieldBound> getBoundFields(Gson gson, TypeToken<?> type, Class<?> raw) {
+        Map<String, ReflectiveFieldBound> result = new LinkedHashMap<>();
+        if (raw.isInterface()) {
+            return result;
+        }
+
+        Type declaredType = type.getType();
+        while (raw != Object.class) {
+            Field[] fields = raw.getDeclaredFields();
+            for (Field field : fields) {
+                boolean serialize = excludeField(field, true);
+                boolean deserialize = excludeField(field, false);
+                if (!serialize && !deserialize) {
+                    continue;
+                }
+                field.setAccessible(true);
+                Type fieldType = $Gson$Types.resolve(type.getType(), raw, field.getGenericType());
+                List<String> fieldNames = getFieldNames(field);
+                ReflectiveFieldBound previous = null;
+                for (int i = 0; i < fieldNames.size(); ++i) {
+                    String name = fieldNames.get(i);
+                    if (i != 0) {
+                        // only serialize the default name
+                        serialize = false;
+                    }
+                    ReflectiveFieldBound fieldBound = ReflectiveTypeUtils.createBoundField(gson, mMainConstructor, field, name,
+                            TypeToken.get(fieldType), serialize, deserialize);
+                    ReflectiveFieldBound replaced = result.put(name, fieldBound);
+                    if (previous == null) {
+                        previous = replaced;
+                    }
+                }
+                if (previous != null) {
+                    throw new IllegalArgumentException(declaredType
+                            + " declares multiple JSON fields named " + previous.getFieldName());
+                }
+            }
+            type = TypeToken.get($Gson$Types.resolve(type.getType(), raw, raw.getGenericSuperclass()));
+            raw = type.getRawType();
+        }
+        return result;
+    }
+
+    private boolean excludeField(Field field, boolean serialize) {
+        return excludeField(field, serialize, mExcluder);
+    }
+
+    private static boolean excludeField(Field field, boolean serialize, Excluder excluder) {
+        return !excluder.excludeClass(field.getType(), serialize) && !excluder.excludeField(field, serialize);
+    }
+
+    private List<String> getFieldNames(Field field) {
+        return ReflectiveTypeUtils.getFieldNames(mFieldNamingPolicy, field);
+    }
+}

+ 96 - 0
lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/element/TypeAdapterRuntimeTypeWrapper.java

@@ -0,0 +1,96 @@
+package com.quyunshuo.sbm10.base.factory.element;
+
+import com.google.gson.Gson;
+import com.google.gson.TypeAdapter;
+import com.google.gson.internal.bind.ReflectiveTypeAdapterFactory;
+import com.google.gson.internal.bind.SerializationDelegatingTypeAdapter;
+import com.google.gson.reflect.TypeToken;
+import com.google.gson.stream.JsonReader;
+import com.google.gson.stream.JsonWriter;
+
+import java.io.IOException;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+
+/**
+ *    author : Android 轮子哥
+ *    github : https://github.com/getActivity/GsonFactory
+ *    time   : 2020/12/08
+ *    desc   : Object 解析适配器,参考:{@link com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper}
+ */
+public class TypeAdapterRuntimeTypeWrapper<T> extends TypeAdapter<T> {
+
+    private final Gson mGson;
+    private final TypeAdapter<T> mDelegate;
+    private final Type mType;
+
+    public TypeAdapterRuntimeTypeWrapper(Gson gson, TypeAdapter<T> delegate, Type type) {
+        mGson = gson;
+        mDelegate = delegate;
+        mType = type;
+    }
+
+    @Override
+    public T read(JsonReader in) throws IOException {
+        return mDelegate.read(in);
+    }
+
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    @Override
+    public void write(JsonWriter out, T value) throws IOException {
+        // Order of preference for choosing type adapters
+        // First preference: a type adapter registered for the runtime type
+        // Second preference: a type adapter registered for the declared type
+        // Third preference: reflective type adapter for the runtime type (if it is a sub class of the declared type)
+        // Fourth preference: reflective type adapter for the declared type
+
+        TypeAdapter chosen;
+        Type runtimeType = getRuntimeTypeIfMoreSpecific(mType, value);
+        if (runtimeType != mType) {
+            TypeAdapter runtimeTypeAdapter = mGson.getAdapter(TypeToken.get(runtimeType));
+            if (!(runtimeTypeAdapter instanceof ReflectiveTypeAdapterFactory.Adapter)) {
+                // The user registered a type adapter for the runtime type, so we will use that
+                chosen = runtimeTypeAdapter;
+            } else if (!isReflective(mDelegate)) {
+                // The user registered a type adapter for Base class, so we prefer it over the
+                // reflective type adapter for the runtime type
+                chosen = mDelegate;
+            } else {
+                // Use the type adapter for runtime type
+                chosen = runtimeTypeAdapter;
+            }
+        } else {
+            chosen = mDelegate;
+        }
+        chosen.write(out, value);
+    }
+
+    /**
+     * Returns whether the type adapter uses reflection.
+     *
+     * @param typeAdapter the type adapter to check.
+     */
+    private static boolean isReflective(TypeAdapter<?> typeAdapter) {
+        // Run this in loop in case multiple delegating adapters are nested
+        while (typeAdapter instanceof SerializationDelegatingTypeAdapter) {
+            TypeAdapter<?> delegate = ((SerializationDelegatingTypeAdapter<?>) typeAdapter).getSerializationDelegate();
+            // Break if adapter does not delegate serialization
+            if (delegate == typeAdapter) {
+                break;
+            }
+            typeAdapter = delegate;
+        }
+
+        return typeAdapter instanceof ReflectiveTypeAdapterFactory.Adapter;
+    }
+
+    /**
+     * Finds a compatible runtime type if it is more specific
+     */
+    private static Type getRuntimeTypeIfMoreSpecific(Type type, Object value) {
+        if (value != null && (type instanceof Class<?> || type instanceof TypeVariable<?>)) {
+            type = value.getClass();
+        }
+        return type;
+    }
+}

+ 36 - 0
lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/other/AutoToNumberStrategy.java

@@ -0,0 +1,36 @@
+package com.quyunshuo.sbm10.base.factory.other;
+
+
+import com.google.gson.ToNumberStrategy;
+import com.google.gson.stream.JsonReader;
+
+import java.io.IOException;
+import java.math.BigDecimal;
+
+/**
+ *    author : Android 轮子哥
+ *    github : https://github.com/getActivity/GsonFactory
+ *    time   : 2024/03/11
+ *    desc   : 自动转换数值类型的策略
+ */
+public class AutoToNumberStrategy implements ToNumberStrategy {
+
+    @Override
+    public Number readNumber(JsonReader in) throws IOException {
+        // Github issue 地址:https://github.com/getActivity/GsonFactory/issues/40
+        String numberString = in.nextString();
+        BigDecimal bigDecimal = new BigDecimal(numberString);
+        // 判断这个数值是浮点数还是整数
+        if (bigDecimal.scale() > 0) {
+            // 如果是浮点数,则用 double 类型装载
+            return bigDecimal.doubleValue();
+        }
+
+        // 如果是整数,则用 int 类型或者 long 类型装载
+        if (bigDecimal.compareTo(BigDecimal.valueOf(Integer.MAX_VALUE)) > 0) {
+            return bigDecimal.longValue();
+        } else {
+            return bigDecimal.intValue();
+        }
+    }
+}

+ 46 - 0
lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/other/ReflectiveFieldBound.java

@@ -0,0 +1,46 @@
+package com.quyunshuo.sbm10.base.factory.other;
+
+import com.google.gson.stream.JsonReader;
+import com.google.gson.stream.JsonWriter;
+
+import java.io.IOException;
+
+/**
+ *    author : Android 轮子哥
+ *    github : https://github.com/getActivity/GsonFactory
+ *    time   : 2020/12/08
+ *    desc   : 反射字段捆绑类,参考:{@link com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.BoundField}
+ */
+public abstract class ReflectiveFieldBound {
+
+    /** 字段名称 */
+    private final String mFieldName;
+    /** 序列化标记 */
+    private final boolean mSerialized;
+    /** 反序列化标记 */
+    private final boolean mDeserialized;
+
+    public ReflectiveFieldBound(String name, boolean serialized, boolean deserialized) {
+        mFieldName = name;
+        mSerialized = serialized;
+        mDeserialized = deserialized;
+    }
+
+    public String getFieldName() {
+        return mFieldName;
+    }
+
+    public boolean isDeserialized() {
+        return mDeserialized;
+    }
+
+    public boolean isSerialized() {
+        return mSerialized;
+    }
+
+    public abstract void write(JsonWriter writer, Object value) throws IOException, IllegalAccessException;
+
+    public abstract void read(JsonReader reader, Object value) throws IOException, IllegalAccessException;
+
+    public abstract boolean writeField(Object value) throws IOException, IllegalAccessException;
+}

+ 202 - 0
lib_base/src/main/java/com/quyunshuo/sbm10/base/factory/other/ReflectiveTypeUtils.java

@@ -0,0 +1,202 @@
+package com.quyunshuo.sbm10.base.factory.other;
+
+import com.google.gson.FieldNamingStrategy;
+import com.google.gson.Gson;
+import com.google.gson.TypeAdapter;
+import com.google.gson.TypeAdapterFactory;
+import com.google.gson.annotations.JsonAdapter;
+import com.google.gson.annotations.SerializedName;
+import com.google.gson.reflect.TypeToken;
+import com.google.gson.stream.JsonReader;
+import com.google.gson.stream.JsonWriter;
+import com.quyunshuo.sbm10.base.factory.constructor.MainConstructor;
+import com.quyunshuo.sbm10.base.factory.element.CollectionTypeAdapter;
+import com.quyunshuo.sbm10.base.factory.element.MapTypeAdapter;
+import com.quyunshuo.sbm10.base.factory.element.ReflectiveTypeAdapter;
+import com.quyunshuo.sbm10.base.factory.element.TypeAdapterRuntimeTypeWrapper;
+
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.net.InetAddress;
+import java.net.URI;
+import java.net.URL;
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Currency;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.List;
+import java.util.Locale;
+import java.util.UUID;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicIntegerArray;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.atomic.AtomicLongArray;
+
+/**
+ *    author : Android 轮子哥
+ *    github : https://github.com/getActivity/GsonFactory
+ *    time   : 2020/12/08
+ *    desc   : 反射工具类
+ */
+public class ReflectiveTypeUtils {
+
+    private final static ArrayList<Class<?>> TYPE_TOKENS = new ArrayList<>();
+
+    static {
+        // 添加 Gson 已适配的类型
+        TYPE_TOKENS.add(String.class);
+        TYPE_TOKENS.add(Integer.class);
+        TYPE_TOKENS.add(Boolean.class);
+        TYPE_TOKENS.add(Byte.class);
+        TYPE_TOKENS.add(Short.class);
+        TYPE_TOKENS.add(Long.class);
+        TYPE_TOKENS.add(Double.class);
+        TYPE_TOKENS.add(Float.class);
+        TYPE_TOKENS.add(Number.class);
+        TYPE_TOKENS.add(AtomicInteger.class);
+        TYPE_TOKENS.add(AtomicBoolean.class);
+        TYPE_TOKENS.add(AtomicLong.class);
+        TYPE_TOKENS.add(AtomicLongArray.class);
+        TYPE_TOKENS.add(AtomicIntegerArray.class);
+        TYPE_TOKENS.add(Character.class);
+        TYPE_TOKENS.add(StringBuilder.class);
+        TYPE_TOKENS.add(StringBuffer.class);
+        TYPE_TOKENS.add(BigDecimal.class);
+        TYPE_TOKENS.add(BigInteger.class);
+        TYPE_TOKENS.add(URL.class);
+        TYPE_TOKENS.add(URI.class);
+        TYPE_TOKENS.add(UUID.class);
+        TYPE_TOKENS.add(Currency.class);
+        TYPE_TOKENS.add(Locale.class);
+        TYPE_TOKENS.add(InetAddress.class);
+        TYPE_TOKENS.add(BitSet.class);
+        TYPE_TOKENS.add(Date.class);
+        TYPE_TOKENS.add(GregorianCalendar.class);
+        TYPE_TOKENS.add(Calendar.class);
+        TYPE_TOKENS.add(Time.class);
+        TYPE_TOKENS.add(java.sql.Date.class);
+        TYPE_TOKENS.add(Timestamp.class);
+        TYPE_TOKENS.add(Class.class);
+    }
+
+    public static boolean containsClass(Class<?> clazz) {
+        return TYPE_TOKENS.contains(clazz);
+    }
+
+    public static ReflectiveFieldBound createBoundField(final Gson gson, final MainConstructor mainConstructor, final Field field, final String fieldName,
+                                                        final TypeToken<?> fieldType, boolean serialize, boolean deserialize) {
+
+        return new ReflectiveFieldBound(fieldName, serialize, deserialize) {
+
+            final TypeAdapter<?> typeAdapter = getFieldAdapter(gson, mainConstructor, field, fieldType, fieldName);
+
+            @SuppressWarnings({"unchecked", "rawtypes"})
+            @Override
+            public void write(JsonWriter writer, Object value) throws IOException, IllegalAccessException {
+                Object fieldValue = field.get(value);
+                TypeAdapter typeWrapper = new TypeAdapterRuntimeTypeWrapper(gson, typeAdapter, fieldType.getType());
+                typeWrapper.write(writer, fieldValue);
+            }
+
+            @Override
+            public void read(JsonReader reader, Object value) throws IOException, IllegalAccessException {
+                Object fieldValue = typeAdapter.read(reader);
+                if (fieldValue == null) {
+                    return;
+                }
+                // 如果不为空,则直接赋值,之所以这样写的原因是
+                // 当后台给某个字段赋值 null,例如 { "age" : null } 这种,也会走到这里来
+                // 这样就会导致一个问题,当字段有一个默认值了,后台返回 null 会把默认值给覆盖掉
+                // 如果是在 Kotlin 上面使用,问题会更加严重,明明在字段上面定义了默认值,并且声明了字段不为空
+                // 如果后台不返回还好,就不会走到这里来,啥事没有,但是如果后台硬是返回了 null
+                // Gson 再反射设置进去,这个时候外层的人一旦使用这个字段,就很可能会触发 NullPointerException
+                field.set(value, fieldValue);
+            }
+
+            @Override
+            public boolean writeField(Object value) throws IOException, IllegalAccessException {
+                if (!isSerialized()) {
+                    return false;
+                }
+
+                Object fieldValue = field.get(value);
+                return fieldValue != value;
+            }
+        };
+    }
+
+    public static TypeAdapter<?> getFieldAdapter(Gson gson, MainConstructor mainConstructor, Field field, TypeToken<?> fieldType, String fieldName) {
+        TypeAdapter<?> adapter = null;
+        JsonAdapter annotation = field.getAnnotation(JsonAdapter.class);
+        if (annotation != null) {
+            adapter = getTypeAdapter(mainConstructor, gson, fieldType, annotation);
+        }
+        if (adapter == null) {
+            adapter = gson.getAdapter(fieldType);
+        }
+        if (adapter instanceof CollectionTypeAdapter) {
+            ((CollectionTypeAdapter<?>) adapter).setReflectiveType(TypeToken.get(field.getDeclaringClass()), fieldName);
+        }
+        if (adapter instanceof ReflectiveTypeAdapter) {
+            ((ReflectiveTypeAdapter<?>) adapter).setReflectiveType(TypeToken.get(field.getDeclaringClass()), fieldName);
+        }
+        if (adapter instanceof MapTypeAdapter) {
+            ((MapTypeAdapter<?, ?>) adapter).setReflectiveType(TypeToken.get(field.getDeclaringClass()), fieldName);
+        }
+        return adapter;
+    }
+
+    public static TypeAdapter<?> getTypeAdapter(MainConstructor mainConstructor,
+                                                Gson gson,
+                                                TypeToken<?> fieldType,
+                                                JsonAdapter annotation) {
+        Class<?> value = annotation.value();
+        TypeAdapter<?> typeAdapter;
+
+        if (TypeAdapter.class.isAssignableFrom(value)) {
+            Class<TypeAdapter<?>> typeAdapterClass = (Class<TypeAdapter<?>>) value;
+            typeAdapter = mainConstructor.get(gson, TypeToken.get(typeAdapterClass)).construct();
+        } else if (TypeAdapterFactory.class.isAssignableFrom(value)) {
+            Class<TypeAdapterFactory> typeAdapterFactory = (Class<TypeAdapterFactory>) value;
+            typeAdapter = mainConstructor.get(gson, TypeToken.get(typeAdapterFactory))
+                    .construct()
+                    .create(gson, fieldType);
+        } else {
+            throw new IllegalArgumentException(
+                    "@JsonAdapter value must be TypeAdapter or TypeAdapterFactory reference.");
+        }
+
+        if (typeAdapter != null) {
+            typeAdapter = typeAdapter.nullSafe();
+        }
+
+        return typeAdapter;
+    }
+
+    public static List<String> getFieldNames(FieldNamingStrategy fieldNamingPolicy, Field field) {
+        SerializedName annotation = field.getAnnotation(SerializedName.class);
+        if (annotation == null) {
+            String name = fieldNamingPolicy.translateName(field);
+            return Collections.singletonList(name);
+        }
+
+        String serializedName = annotation.value();
+        String[] alternates = annotation.alternate();
+        if (alternates.length == 0) {
+            return Collections.singletonList(serializedName);
+        }
+
+        List<String> fieldNames = new ArrayList<>(alternates.length + 1);
+        fieldNames.add(serializedName);
+        Collections.addAll(fieldNames, alternates);
+        return fieldNames;
+    }
+}

+ 315 - 0
lib_base/src/main/java/com/quyunshuo/sbm10/base/utils/JsonUtils.java

@@ -0,0 +1,315 @@
+package com.quyunshuo.sbm10.base.utils;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParseException;
+import com.google.gson.JsonParser;
+import com.google.gson.JsonPrimitive;
+import com.google.gson.JsonSyntaxException;
+import com.quyunshuo.sbm10.base.factory.GsonFactory;
+import com.quyunshuo.sbm10.base.utils.commons.StringUtils;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+
+public class JsonUtils {
+
+    /**
+     * 获取Gson实例
+     **/
+    private static Gson getInstance() {
+        //gsonBuilder.registerTypeAdapter(Object.class, new NaturalDeserializer());
+        Gson gson = GsonFactory.getSingletonGson();
+        return gson;
+    }
+
+    /**
+     * 解析集合
+     *
+     * @param json      数据
+     * @param beanClass 泛型
+     * @return 泛型集合
+     */
+    public static <T> List<T> getBeanList(String json, Class<T> beanClass) {
+        return getBeanList(json, null, beanClass);
+    }
+
+    /**
+     * 解析集合
+     *
+     * @param json
+     * @param key       json数据key
+     * @param beanClass 泛型
+     * @return 泛型集合
+     */
+    public static <T> List<T> getBeanList(String json, String key, Class<T> beanClass) {
+        JsonParser parser = new JsonParser();
+        Gson gson = getInstance();
+        JsonElement contentElement = null;
+        List<T> elementList = new ArrayList<T>();
+//    try {
+//       @SuppressWarnings("unused")
+//       JSONObject object = new JSONObject(json);
+//    } catch (JSONException e1) {
+//       return elementList;
+//    }
+        if (StringUtils.isNullOrEmpty(key) || StringUtils.isNullOrEmpty(json)) {
+            contentElement = parser.parse(json).getAsJsonArray();
+        } else {
+            JsonObject jsonObject = parser.parse(json).getAsJsonObject();
+            contentElement = jsonObject.get(key);
+        }
+        if (StringUtils.isNullOrEmpty(String.valueOf(contentElement)))
+            return elementList;
+        if (contentElement.isJsonArray()) {
+            JsonArray jsonArray = contentElement.getAsJsonArray();
+            try {
+                for (int i = 0; i < jsonArray.size(); i++) {
+                    JsonElement jsonObj = jsonArray.get(i);
+                    T entity = gson.fromJson(jsonObj, beanClass);
+                    elementList.add(entity);
+                }
+            } catch (ClassCastException e) {
+            } catch (JsonParseException e) {
+            }
+            return elementList;
+        }
+        return elementList;
+    }
+
+    /**
+     * 解析单个bean
+     *
+     * @param json
+     * @param clazz
+     * @return 泛型
+     */
+    public static <T> T getBean(String json, final Class<T> clazz) {
+        return getBean(json, null, clazz);
+    }
+
+    /**
+     * 解析单个bean
+     *
+     * @param json
+     * @param key   解析的json数据key
+     * @param clazz
+     * @return 泛型
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> T getBean(String json, String key, final Class<T> clazz) {
+        JsonParser parser = new JsonParser();
+        Gson gson = getInstance();
+        JsonElement contentElement = null;
+        try {
+            @SuppressWarnings("unused")
+            JSONObject object = new JSONObject(json);
+        } catch (JSONException e1) {
+            return null;
+        }
+        if (StringUtils.isNullOrEmpty(key)) {
+            contentElement = parser.parse(json).getAsJsonObject();
+        } else {
+            JsonObject jsonObject = parser.parse(json).getAsJsonObject();
+            contentElement = jsonObject.get(key);
+        }
+        if (StringUtils.isNullOrEmpty(String.valueOf(contentElement)))
+            return null;
+        if (contentElement.isJsonPrimitive()) {
+            if (clazz == String.class) {
+                return (T) contentElement.getAsString();
+            } else if (clazz == Integer.class) {
+                return (T) Integer.valueOf(contentElement.getAsString());
+            } else if (clazz == Number.class) {
+                return (T) contentElement.getAsNumber();
+            }
+        } else if (contentElement.isJsonObject()) {
+            JsonObject contentObj = contentElement.getAsJsonObject();
+            T content = null;
+            try {
+                content = gson.fromJson(contentObj, clazz);
+            } catch (ClassCastException e) {
+            } catch (JsonParseException e) {
+                System.out.println(e.getStackTrace().toString());
+            }
+            return content;
+        }
+        return null;
+    }
+
+
+    public static Object getObjectByKey(String json, String key, String targetkey) {
+        JsonParser parser = new JsonParser();
+        JsonElement jsonElement;
+        try {
+            JsonObject jsonObject = parser.parse(json).getAsJsonObject();
+            jsonElement = jsonObject.get(key);
+            return jsonElement.getAsJsonObject().get(targetkey).toString();
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
+    /**
+     * 根据key 解析相关字段
+     * {
+     * "user": {
+     * "name": "John",
+     * "addresses": [
+     * {
+     * "city": "New York",
+     * "zip": 10001
+     * },
+     * {
+     * "city": "London",
+     * "zip": 12345
+     * }
+     * ]
+     * }
+     * }
+     * .getValue(jsonString, "user.name");
+     * getValue(jsonString, "user.addresses[0].city");
+     * getValue(jsonString, "user.addresses[1].zip")
+     *
+     * @return
+     */
+    public static <T> T getValue(String jsonString, String keyPath, Class<T> type) {
+        Object value = getValue(jsonString, keyPath);
+        return type.isInstance(value) ? type.cast(value) : null;
+    }
+
+    public static <T> T getValue(String jsonString, String keyPath) {
+        try {
+            Gson gson = getInstance();
+            JsonElement jsonElement = gson.fromJson(jsonString, JsonElement.class);
+            return getValue(jsonElement, keyPath);
+        } catch (JsonSyntaxException e) {
+            return null;
+        }
+    }
+
+    private static final Pattern ARRAY_PATTERN = Pattern.compile("(.+)\\[(\\d+)\\]");
+
+    /**
+     * 从 JsonElement 中获取指定 Key 的值
+     *
+     * @param jsonElement 已解析的 JsonElement
+     * @param keyPath     支持嵌套和数组的路径
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> T getValue(JsonElement jsonElement, String keyPath) {
+        if (jsonElement == null || keyPath == null) return null;
+
+        String[] keys = keyPath.split("\\.");
+        JsonElement currentElement = jsonElement;
+
+        for (String key : keys) {
+            if (currentElement == null || currentElement.isJsonNull()) break;
+
+            // 处理数组语法,例如 "items[0]"
+            Matcher matcher = ARRAY_PATTERN.matcher(key);
+            if (matcher.matches()) {
+                String arrayKey = matcher.group(1);
+                int index = Integer.parseInt(matcher.group(2));
+
+                currentElement = getElementFromArray(currentElement, arrayKey, index);
+            } else {
+                currentElement = getElementFromObject(currentElement, key);
+            }
+        }
+
+        return currentElement != null ? (T) parseElement(currentElement) : null;
+    }
+
+    private static JsonElement getElementFromObject(JsonElement element, String key) {
+        if (element.isJsonObject()) {
+            return element.getAsJsonObject().get(key);
+        }
+        return null;
+    }
+
+    private static JsonElement getElementFromArray(JsonElement element, String arrayKey, int index) {
+        JsonElement arrayElement = getElementFromObject(element, arrayKey);
+        if (arrayElement != null && arrayElement.isJsonArray()) {
+            JsonArray jsonArray = arrayElement.getAsJsonArray();
+            if (index >= 0 && index < jsonArray.size()) {
+                return jsonArray.get(index);
+            }
+        }
+        return null;
+    }
+
+    private static Object parseElement(JsonElement element) {
+        if (element.isJsonPrimitive()) {
+            JsonPrimitive primitive = element.getAsJsonPrimitive();
+            if (primitive.isBoolean()) return primitive.getAsBoolean();
+            if (primitive.isNumber()) return primitive.getAsNumber();
+            return primitive.getAsString();
+        } else if (element.isJsonArray() || element.isJsonObject()) {
+            return element;
+        }
+        return null;
+    }
+
+    /**
+     * JSONObject生成Json字符串
+     **/
+    public static String getJSONStringByJSONObject(JSONObject jsonobject) {
+        String s;
+        if (jsonobject == null)
+            s = "";
+        else
+            s = jsonobject.toString();
+        return s;
+    }
+
+    /**
+     * JSONObject生成Json字符串
+     **/
+    public static String getJSONString(Object jsonobject) {
+        Gson gson = getInstance();
+        return gson.toJson(jsonobject);
+    }
+
+    /**
+     * 解析JSONObject Json字符串
+     **/
+    public static JSONObject getJSONObjectByJSONString(String str) {
+        str = str.replace("\ufeff", "");
+        JSONObject jsonobject;
+        if (str != null)
+            try {
+                jsonobject = new JSONObject(str);
+            } catch (JSONException _ex) {
+                jsonobject = null;
+            }
+        else
+            jsonobject = null;
+        return jsonobject;
+    }
+
+    /**
+     * 解析JSONArray Json字符串
+     **/
+    public static JSONArray getJSONArrayByJSONString(String str) {
+        JSONArray jsonarray;
+        if (str != null)
+            try {
+                jsonarray = new JSONArray(str);
+            } catch (JSONException _ex) {
+                jsonarray = null;
+            }
+        else
+            jsonarray = null;
+        return jsonarray;
+    }
+}

+ 5 - 0
lib_base/src/main/java/com/quyunshuo/sbm10/base/utils/commons/BinaryDecoder.java

@@ -0,0 +1,5 @@
+package com.quyunshuo.sbm10.base.utils.commons;
+
+public interface BinaryDecoder extends Decoder {
+    byte[] decode(byte[] var1) throws DecoderException;
+}

+ 5 - 0
lib_base/src/main/java/com/quyunshuo/sbm10/base/utils/commons/BinaryEncoder.java

@@ -0,0 +1,5 @@
+package com.quyunshuo.sbm10.base.utils.commons;
+
+public interface BinaryEncoder extends Encoder {
+    byte[] encode(byte[] var1) throws EncoderException;
+}

+ 32 - 0
lib_base/src/main/java/com/quyunshuo/sbm10/base/utils/commons/CharSequenceUtils.java

@@ -0,0 +1,32 @@
+package com.quyunshuo.sbm10.base.utils.commons;
+
+public class CharSequenceUtils {
+    public CharSequenceUtils() {
+    }
+
+    static boolean regionMatches(CharSequence cs, boolean ignoreCase, int thisStart, CharSequence substring, int start, int length) {
+        if (cs instanceof String && substring instanceof String) {
+            return ((String)cs).regionMatches(ignoreCase, thisStart, (String)substring, start, length);
+        } else {
+            int index1 = thisStart;
+            int index2 = start;
+            int tmpLen = length;
+
+            while(tmpLen-- > 0) {
+                char c1 = cs.charAt(index1++);
+                char c2 = substring.charAt(index2++);
+                if (c1 != c2) {
+                    if (!ignoreCase) {
+                        return false;
+                    }
+
+                    if (Character.toUpperCase(c1) != Character.toUpperCase(c2) && Character.toLowerCase(c1) != Character.toLowerCase(c2)) {
+                        return false;
+                    }
+                }
+            }
+
+            return true;
+        }
+    }
+}

+ 5 - 0
lib_base/src/main/java/com/quyunshuo/sbm10/base/utils/commons/Decoder.java

@@ -0,0 +1,5 @@
+package com.quyunshuo.sbm10.base.utils.commons;
+
+public interface Decoder {
+    Object decode(Object var1) throws DecoderException;
+}

+ 21 - 0
lib_base/src/main/java/com/quyunshuo/sbm10/base/utils/commons/DecoderException.java

@@ -0,0 +1,21 @@
+package com.quyunshuo.sbm10.base.utils.commons;
+
+public class DecoderException extends Exception {
+    private static final long serialVersionUID = 1L;
+
+    public DecoderException() {
+    }
+
+    public DecoderException(String message) {
+        super(message);
+    }
+
+    public DecoderException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public DecoderException(Throwable cause) {
+        super(cause);
+    }
+}
+

+ 610 - 0
lib_base/src/main/java/com/quyunshuo/sbm10/base/utils/commons/DigestUtils.java

@@ -0,0 +1,610 @@
+package com.quyunshuo.sbm10.base.utils.commons;
+
+
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.RandomAccessFile;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.file.Files;
+import java.nio.file.OpenOption;
+import java.nio.file.Path;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+public class DigestUtils {
+    private static final int STREAM_BUFFER_LENGTH = 1024;
+    private final MessageDigest messageDigest;
+
+    public static byte[] digest(MessageDigest messageDigest, byte[] data) {
+        return messageDigest.digest(data);
+    }
+
+    public static byte[] digest(MessageDigest messageDigest, ByteBuffer data) {
+        messageDigest.update(data);
+        return messageDigest.digest();
+    }
+
+    public static byte[] digest(MessageDigest messageDigest, File data) throws IOException {
+        return updateDigest(messageDigest, data).digest();
+    }
+
+    public static byte[] digest(MessageDigest messageDigest, InputStream data) throws IOException {
+        return updateDigest(messageDigest, data).digest();
+    }
+
+    public static byte[] digest(MessageDigest messageDigest, Path data, OpenOption... options) throws IOException {
+        return updateDigest(messageDigest, data, options).digest();
+    }
+
+    public static byte[] digest(MessageDigest messageDigest, RandomAccessFile data) throws IOException {
+        return updateDigest(messageDigest, data).digest();
+    }
+
+    public static MessageDigest getDigest(String algorithm) {
+        try {
+            return MessageDigest.getInstance(algorithm);
+        } catch (NoSuchAlgorithmException var2) {
+            NoSuchAlgorithmException e = var2;
+            throw new IllegalArgumentException(e);
+        }
+    }
+
+    public static MessageDigest getDigest(String algorithm, MessageDigest defaultMessageDigest) {
+        try {
+            return MessageDigest.getInstance(algorithm);
+        } catch (Exception var3) {
+            return defaultMessageDigest;
+        }
+    }
+
+    public static MessageDigest getMd2Digest() {
+        return getDigest("MD2");
+    }
+
+    public static MessageDigest getMd5Digest() {
+        return getDigest("MD5");
+    }
+
+    public static MessageDigest getSha1Digest() {
+        return getDigest("SHA-1");
+    }
+
+    public static MessageDigest getSha256Digest() {
+        return getDigest("SHA-256");
+    }
+
+    public static MessageDigest getSha3_224Digest() {
+        return getDigest("SHA3-224");
+    }
+
+    public static MessageDigest getSha3_256Digest() {
+        return getDigest("SHA3-256");
+    }
+
+    public static MessageDigest getSha3_384Digest() {
+        return getDigest("SHA3-384");
+    }
+
+    public static MessageDigest getSha3_512Digest() {
+        return getDigest("SHA3-512");
+    }
+
+    public static MessageDigest getSha384Digest() {
+        return getDigest("SHA-384");
+    }
+
+    public static MessageDigest getSha512_224Digest() {
+        return getDigest("SHA-512/224");
+    }
+
+    public static MessageDigest getSha512_256Digest() {
+        return getDigest("SHA-512/256");
+    }
+
+    public static MessageDigest getSha512Digest() {
+        return getDigest("SHA-512");
+    }
+
+    /** @deprecated */
+    @Deprecated
+    public static MessageDigest getShaDigest() {
+        return getSha1Digest();
+    }
+
+    public static boolean isAvailable(String messageDigestAlgorithm) {
+        return getDigest(messageDigestAlgorithm, (MessageDigest)null) != null;
+    }
+
+    public static byte[] md2(byte[] data) {
+        return getMd2Digest().digest(data);
+    }
+
+    public static byte[] md2(InputStream data) throws IOException {
+        return digest(getMd2Digest(), data);
+    }
+
+    public static byte[] md2(String data) {
+        return md2(StringUtils.getBytesUtf8(data));
+    }
+
+    public static String md2Hex(byte[] data) {
+        return Hex.encodeHexString(md2(data));
+    }
+
+    public static String md2Hex(InputStream data) throws IOException {
+        return Hex.encodeHexString(md2(data));
+    }
+
+    public static String md2Hex(String data) {
+        return Hex.encodeHexString(md2(data));
+    }
+
+    public static byte[] md5(byte[] data) {
+        return getMd5Digest().digest(data);
+    }
+
+    public static byte[] md5(InputStream data) throws IOException {
+        return digest(getMd5Digest(), data);
+    }
+
+    public static byte[] md5(String data) {
+        return md5(StringUtils.getBytesUtf8(data));
+    }
+
+    public static String md5Hex(byte[] data) {
+        return Hex.encodeHexString(md5(data));
+    }
+
+    public static String md5Hex(InputStream data) throws IOException {
+        return Hex.encodeHexString(md5(data));
+    }
+
+    public static String md5Hex(String data) {
+        return Hex.encodeHexString(md5(data));
+    }
+
+    /** @deprecated */
+    @Deprecated
+    public static byte[] sha(byte[] data) {
+        return sha1(data);
+    }
+
+    /** @deprecated */
+    @Deprecated
+    public static byte[] sha(InputStream data) throws IOException {
+        return sha1(data);
+    }
+
+    /** @deprecated */
+    @Deprecated
+    public static byte[] sha(String data) {
+        return sha1(data);
+    }
+
+    public static byte[] sha1(byte[] data) {
+        return getSha1Digest().digest(data);
+    }
+
+    public static byte[] sha1(InputStream data) throws IOException {
+        return digest(getSha1Digest(), data);
+    }
+
+    public static byte[] sha1(String data) {
+        return sha1(StringUtils.getBytesUtf8(data));
+    }
+
+    public static String sha1Hex(byte[] data) {
+        return Hex.encodeHexString(sha1(data));
+    }
+
+    public static String sha1Hex(InputStream data) throws IOException {
+        return Hex.encodeHexString(sha1(data));
+    }
+
+    public static String sha1Hex(String data) {
+        return Hex.encodeHexString(sha1(data));
+    }
+
+    public static byte[] sha256(byte[] data) {
+        return getSha256Digest().digest(data);
+    }
+
+    public static byte[] sha256(InputStream data) throws IOException {
+        return digest(getSha256Digest(), data);
+    }
+
+    public static byte[] sha256(String data) {
+        return sha256(StringUtils.getBytesUtf8(data));
+    }
+
+    public static String sha256Hex(byte[] data) {
+        return Hex.encodeHexString(sha256(data));
+    }
+
+    public static String sha256Hex(InputStream data) throws IOException {
+        return Hex.encodeHexString(sha256(data));
+    }
+
+    public static String sha256Hex(String data) {
+        return Hex.encodeHexString(sha256(data));
+    }
+
+    public static byte[] sha3_224(byte[] data) {
+        return getSha3_224Digest().digest(data);
+    }
+
+    public static byte[] sha3_224(InputStream data) throws IOException {
+        return digest(getSha3_224Digest(), data);
+    }
+
+    public static byte[] sha3_224(String data) {
+        return sha3_224(StringUtils.getBytesUtf8(data));
+    }
+
+    public static String sha3_224Hex(byte[] data) {
+        return Hex.encodeHexString(sha3_224(data));
+    }
+
+    public static String sha3_224Hex(InputStream data) throws IOException {
+        return Hex.encodeHexString(sha3_224(data));
+    }
+
+    public static String sha3_224Hex(String data) {
+        return Hex.encodeHexString(sha3_224(data));
+    }
+
+    public static byte[] sha3_256(byte[] data) {
+        return getSha3_256Digest().digest(data);
+    }
+
+    public static byte[] sha3_256(InputStream data) throws IOException {
+        return digest(getSha3_256Digest(), data);
+    }
+
+    public static byte[] sha3_256(String data) {
+        return sha3_256(StringUtils.getBytesUtf8(data));
+    }
+
+    public static String sha3_256Hex(byte[] data) {
+        return Hex.encodeHexString(sha3_256(data));
+    }
+
+    public static String sha3_256Hex(InputStream data) throws IOException {
+        return Hex.encodeHexString(sha3_256(data));
+    }
+
+    public static String sha3_256Hex(String data) {
+        return Hex.encodeHexString(sha3_256(data));
+    }
+
+    public static byte[] sha3_384(byte[] data) {
+        return getSha3_384Digest().digest(data);
+    }
+
+    public static byte[] sha3_384(InputStream data) throws IOException {
+        return digest(getSha3_384Digest(), data);
+    }
+
+    public static byte[] sha3_384(String data) {
+        return sha3_384(StringUtils.getBytesUtf8(data));
+    }
+
+    public static String sha3_384Hex(byte[] data) {
+        return Hex.encodeHexString(sha3_384(data));
+    }
+
+    public static String sha3_384Hex(InputStream data) throws IOException {
+        return Hex.encodeHexString(sha3_384(data));
+    }
+
+    public static String sha3_384Hex(String data) {
+        return Hex.encodeHexString(sha3_384(data));
+    }
+
+    public static byte[] sha3_512(byte[] data) {
+        return getSha3_512Digest().digest(data);
+    }
+
+    public static byte[] sha3_512(InputStream data) throws IOException {
+        return digest(getSha3_512Digest(), data);
+    }
+
+    public static byte[] sha3_512(String data) {
+        return sha3_512(StringUtils.getBytesUtf8(data));
+    }
+
+    public static String sha3_512Hex(byte[] data) {
+        return Hex.encodeHexString(sha3_512(data));
+    }
+
+    public static String sha3_512Hex(InputStream data) throws IOException {
+        return Hex.encodeHexString(sha3_512(data));
+    }
+
+    public static String sha3_512Hex(String data) {
+        return Hex.encodeHexString(sha3_512(data));
+    }
+
+    public static byte[] sha384(byte[] data) {
+        return getSha384Digest().digest(data);
+    }
+
+    public static byte[] sha384(InputStream data) throws IOException {
+        return digest(getSha384Digest(), data);
+    }
+
+    public static byte[] sha384(String data) {
+        return sha384(StringUtils.getBytesUtf8(data));
+    }
+
+    public static String sha384Hex(byte[] data) {
+        return Hex.encodeHexString(sha384(data));
+    }
+
+    public static String sha384Hex(InputStream data) throws IOException {
+        return Hex.encodeHexString(sha384(data));
+    }
+
+    public static String sha384Hex(String data) {
+        return Hex.encodeHexString(sha384(data));
+    }
+
+    public static byte[] sha512(byte[] data) {
+        return getSha512Digest().digest(data);
+    }
+
+    public static byte[] sha512(InputStream data) throws IOException {
+        return digest(getSha512Digest(), data);
+    }
+
+    public static byte[] sha512(String data) {
+        return sha512(StringUtils.getBytesUtf8(data));
+    }
+
+    public static byte[] sha512_224(byte[] data) {
+        return getSha512_224Digest().digest(data);
+    }
+
+    public static byte[] sha512_224(InputStream data) throws IOException {
+        return digest(getSha512_224Digest(), data);
+    }
+
+    public static byte[] sha512_224(String data) {
+        return sha512_224(StringUtils.getBytesUtf8(data));
+    }
+
+    public static String sha512_224Hex(byte[] data) {
+        return Hex.encodeHexString(sha512_224(data));
+    }
+
+    public static String sha512_224Hex(InputStream data) throws IOException {
+        return Hex.encodeHexString(sha512_224(data));
+    }
+
+    public static String sha512_224Hex(String data) {
+        return Hex.encodeHexString(sha512_224(data));
+    }
+
+    public static byte[] sha512_256(byte[] data) {
+        return getSha512_256Digest().digest(data);
+    }
+
+    public static byte[] sha512_256(InputStream data) throws IOException {
+        return digest(getSha512_256Digest(), data);
+    }
+
+    public static byte[] sha512_256(String data) {
+        return sha512_256(StringUtils.getBytesUtf8(data));
+    }
+
+    public static String sha512_256Hex(byte[] data) {
+        return Hex.encodeHexString(sha512_256(data));
+    }
+
+    public static String sha512_256Hex(InputStream data) throws IOException {
+        return Hex.encodeHexString(sha512_256(data));
+    }
+
+    public static String sha512_256Hex(String data) {
+        return Hex.encodeHexString(sha512_256(data));
+    }
+
+    public static String sha512Hex(byte[] data) {
+        return Hex.encodeHexString(sha512(data));
+    }
+
+    public static String sha512Hex(InputStream data) throws IOException {
+        return Hex.encodeHexString(sha512(data));
+    }
+
+    public static String sha512Hex(String data) {
+        return Hex.encodeHexString(sha512(data));
+    }
+
+    /** @deprecated */
+    @Deprecated
+    public static String shaHex(byte[] data) {
+        return sha1Hex(data);
+    }
+
+    /** @deprecated */
+    @Deprecated
+    public static String shaHex(InputStream data) throws IOException {
+        return sha1Hex(data);
+    }
+
+    /** @deprecated */
+    @Deprecated
+    public static String shaHex(String data) {
+        return sha1Hex(data);
+    }
+
+    public static MessageDigest updateDigest(MessageDigest messageDigest, byte[] valueToDigest) {
+        messageDigest.update(valueToDigest);
+        return messageDigest;
+    }
+
+    public static MessageDigest updateDigest(MessageDigest messageDigest, ByteBuffer valueToDigest) {
+        messageDigest.update(valueToDigest);
+        return messageDigest;
+    }
+
+    public static MessageDigest updateDigest(MessageDigest digest, File data) throws IOException {
+        BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream(data));
+        Throwable var3 = null;
+
+        MessageDigest var4;
+        try {
+            var4 = updateDigest(digest, (InputStream)inputStream);
+        } catch (Throwable var13) {
+            var3 = var13;
+            throw var13;
+        } finally {
+            if (inputStream != null) {
+                if (var3 != null) {
+                    try {
+                        inputStream.close();
+                    } catch (Throwable var12) {
+                        var3.addSuppressed(var12);
+                    }
+                } else {
+                    inputStream.close();
+                }
+            }
+
+        }
+
+        return var4;
+    }
+
+    private static MessageDigest updateDigest(MessageDigest digest, FileChannel data) throws IOException {
+        ByteBuffer buffer = ByteBuffer.allocate(1024);
+
+        while(data.read(buffer) > 0) {
+            buffer.flip();
+            digest.update(buffer);
+            buffer.clear();
+        }
+
+        return digest;
+    }
+
+    public static MessageDigest updateDigest(MessageDigest digest, InputStream inputStream) throws IOException {
+        byte[] buffer = new byte[1024];
+
+        for(int read = inputStream.read(buffer, 0, 1024); read > -1; read = inputStream.read(buffer, 0, 1024)) {
+            digest.update(buffer, 0, read);
+        }
+
+        return digest;
+    }
+
+    public static MessageDigest updateDigest(MessageDigest digest, Path path, OpenOption... options) throws IOException {
+        BufferedInputStream inputStream = new BufferedInputStream(Files.newInputStream(path, options));
+        Throwable var4 = null;
+
+        MessageDigest var5;
+        try {
+            var5 = updateDigest(digest, (InputStream)inputStream);
+        } catch (Throwable var14) {
+            var4 = var14;
+            throw var14;
+        } finally {
+            if (inputStream != null) {
+                if (var4 != null) {
+                    try {
+                        inputStream.close();
+                    } catch (Throwable var13) {
+                        var4.addSuppressed(var13);
+                    }
+                } else {
+                    inputStream.close();
+                }
+            }
+
+        }
+
+        return var5;
+    }
+
+    public static MessageDigest updateDigest(MessageDigest digest, RandomAccessFile data) throws IOException {
+        return updateDigest(digest, data.getChannel());
+    }
+
+    public static MessageDigest updateDigest(MessageDigest messageDigest, String valueToDigest) {
+        messageDigest.update(StringUtils.getBytesUtf8(valueToDigest));
+        return messageDigest;
+    }
+
+    /** @deprecated */
+    @Deprecated
+    public DigestUtils() {
+        this.messageDigest = null;
+    }
+
+    public DigestUtils(MessageDigest digest) {
+        this.messageDigest = digest;
+    }
+
+    public DigestUtils(String name) {
+        this(getDigest(name));
+    }
+
+    public byte[] digest(byte[] data) {
+        return updateDigest(this.messageDigest, data).digest();
+    }
+
+    public byte[] digest(ByteBuffer data) {
+        return updateDigest(this.messageDigest, data).digest();
+    }
+
+    public byte[] digest(File data) throws IOException {
+        return updateDigest(this.messageDigest, data).digest();
+    }
+
+    public byte[] digest(InputStream data) throws IOException {
+        return updateDigest(this.messageDigest, data).digest();
+    }
+
+    public byte[] digest(Path data, OpenOption... options) throws IOException {
+        return updateDigest(this.messageDigest, data, options).digest();
+    }
+
+    public byte[] digest(String data) {
+        return updateDigest(this.messageDigest, data).digest();
+    }
+
+    public String digestAsHex(byte[] data) {
+        return Hex.encodeHexString(this.digest(data));
+    }
+
+    public String digestAsHex(ByteBuffer data) {
+        return Hex.encodeHexString(this.digest(data));
+    }
+
+    public String digestAsHex(File data) throws IOException {
+        return Hex.encodeHexString(this.digest(data));
+    }
+
+    public String digestAsHex(InputStream data) throws IOException {
+        return Hex.encodeHexString(this.digest(data));
+    }
+
+    public String digestAsHex(Path data, OpenOption... options) throws IOException {
+        return Hex.encodeHexString(this.digest(data, options));
+    }
+
+    public String digestAsHex(String data) {
+        return Hex.encodeHexString(this.digest(data));
+    }
+
+    public MessageDigest getMessageDigest() {
+        return this.messageDigest;
+    }
+
+}

+ 5 - 0
lib_base/src/main/java/com/quyunshuo/sbm10/base/utils/commons/Encoder.java

@@ -0,0 +1,5 @@
+package com.quyunshuo.sbm10.base.utils.commons;
+
+public interface Encoder {
+    Object encode(Object var1) throws EncoderException;
+}

+ 20 - 0
lib_base/src/main/java/com/quyunshuo/sbm10/base/utils/commons/EncoderException.java

@@ -0,0 +1,20 @@
+package com.quyunshuo.sbm10.base.utils.commons;
+
+public class EncoderException extends Exception {
+    private static final long serialVersionUID = 1L;
+
+    public EncoderException() {
+    }
+
+    public EncoderException(String message) {
+        super(message);
+    }
+
+    public EncoderException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public EncoderException(Throwable cause) {
+        super(cause);
+    }
+}

+ 216 - 0
lib_base/src/main/java/com/quyunshuo/sbm10/base/utils/commons/Hex.java

@@ -0,0 +1,216 @@
+package com.quyunshuo.sbm10.base.utils.commons;
+
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+
+public class Hex implements BinaryEncoder, BinaryDecoder {
+    public static final Charset DEFAULT_CHARSET;
+    public static final String DEFAULT_CHARSET_NAME = "UTF-8";
+    private static final char[] DIGITS_LOWER;
+    private static final char[] DIGITS_UPPER;
+    private final Charset charset;
+
+    public static byte[] decodeHex(char[] data) throws DecoderException {
+        byte[] out = new byte[data.length >> 1];
+        decodeHex(data, out, 0);
+        return out;
+    }
+
+    public static int decodeHex(char[] data, byte[] out, int outOffset) throws DecoderException {
+        int len = data.length;
+        if ((len & 1) != 0) {
+            throw new DecoderException("Odd number of characters.");
+        } else {
+            int outLen = len >> 1;
+            if (out.length - outOffset < outLen) {
+                throw new DecoderException("Output array is not large enough to accommodate decoded data.");
+            } else {
+                int i = outOffset;
+
+                for(int j = 0; j < len; ++i) {
+                    int f = toDigit(data[j], j) << 4;
+                    ++j;
+                    f |= toDigit(data[j], j);
+                    ++j;
+                    out[i] = (byte)(f & 255);
+                }
+
+                return outLen;
+            }
+        }
+    }
+
+    public static byte[] decodeHex(String data) throws DecoderException {
+        return decodeHex(data.toCharArray());
+    }
+
+    public static char[] encodeHex(byte[] data) {
+        return encodeHex(data, true);
+    }
+
+    public static char[] encodeHex(byte[] data, boolean toLowerCase) {
+        return encodeHex(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER);
+    }
+
+    protected static char[] encodeHex(byte[] data, char[] toDigits) {
+        int l = data.length;
+        char[] out = new char[l << 1];
+        encodeHex(data, 0, data.length, toDigits, out, 0);
+        return out;
+    }
+
+    public static char[] encodeHex(byte[] data, int dataOffset, int dataLen, boolean toLowerCase) {
+        char[] out = new char[dataLen << 1];
+        encodeHex(data, dataOffset, dataLen, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER, out, 0);
+        return out;
+    }
+
+    public static void encodeHex(byte[] data, int dataOffset, int dataLen, boolean toLowerCase, char[] out, int outOffset) {
+        encodeHex(data, dataOffset, dataLen, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER, out, outOffset);
+    }
+
+    private static void encodeHex(byte[] data, int dataOffset, int dataLen, char[] toDigits, char[] out, int outOffset) {
+        int i = dataOffset;
+
+        for(int j = outOffset; i < dataOffset + dataLen; ++i) {
+            out[j++] = toDigits[(240 & data[i]) >>> 4];
+            out[j++] = toDigits[15 & data[i]];
+        }
+
+    }
+
+    public static char[] encodeHex(ByteBuffer data) {
+        return encodeHex(data, true);
+    }
+
+    public static char[] encodeHex(ByteBuffer data, boolean toLowerCase) {
+        return encodeHex(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER);
+    }
+
+    protected static char[] encodeHex(ByteBuffer byteBuffer, char[] toDigits) {
+        return encodeHex(toByteArray(byteBuffer), toDigits);
+    }
+
+    public static String encodeHexString(byte[] data) {
+        return new String(encodeHex(data));
+    }
+
+    public static String encodeHexString(byte[] data, boolean toLowerCase) {
+        return new String(encodeHex(data, toLowerCase));
+    }
+
+    public static String encodeHexString(ByteBuffer data) {
+        return new String(encodeHex(data));
+    }
+
+    public static String encodeHexString(ByteBuffer data, boolean toLowerCase) {
+        return new String(encodeHex(data, toLowerCase));
+    }
+
+    private static byte[] toByteArray(ByteBuffer byteBuffer) {
+        int remaining = byteBuffer.remaining();
+        byte[] byteArray;
+        if (byteBuffer.hasArray()) {
+            byteArray = byteBuffer.array();
+            if (remaining == byteArray.length) {
+                byteBuffer.position(remaining);
+                return byteArray;
+            }
+        }
+
+        byteArray = new byte[remaining];
+        byteBuffer.get(byteArray);
+        return byteArray;
+    }
+
+    protected static int toDigit(char ch, int index) throws DecoderException {
+        int digit = Character.digit(ch, 16);
+        if (digit == -1) {
+            throw new DecoderException("Illegal hexadecimal character " + ch + " at index " + index);
+        } else {
+            return digit;
+        }
+    }
+
+    public Hex() {
+        this.charset = DEFAULT_CHARSET;
+    }
+
+    public Hex(Charset charset) {
+        this.charset = charset;
+    }
+
+    public Hex(String charsetName) {
+        this(Charset.forName(charsetName));
+    }
+
+    public byte[] decode(byte[] array) throws DecoderException {
+        return decodeHex((new String(array, this.getCharset())).toCharArray());
+    }
+
+    public byte[] decode(ByteBuffer buffer) throws DecoderException {
+        return decodeHex((new String(toByteArray(buffer), this.getCharset())).toCharArray());
+    }
+
+    public Object decode(Object object) throws DecoderException {
+        if (object instanceof String) {
+            return this.decode((Object)((String)object).toCharArray());
+        } else if (object instanceof byte[]) {
+            return this.decode((byte[])((byte[])object));
+        } else if (object instanceof ByteBuffer) {
+            return this.decode((ByteBuffer)object);
+        } else {
+            try {
+                return decodeHex((char[])((char[])object));
+            } catch (ClassCastException var3) {
+                ClassCastException e = var3;
+                throw new DecoderException(e.getMessage(), e);
+            }
+        }
+    }
+
+    public byte[] encode(byte[] array) {
+        return encodeHexString(array).getBytes(this.getCharset());
+    }
+
+    public byte[] encode(ByteBuffer array) {
+        return encodeHexString(array).getBytes(this.getCharset());
+    }
+
+    public Object encode(Object object) throws EncoderException {
+        byte[] byteArray;
+        if (object instanceof String) {
+            byteArray = ((String)object).getBytes(this.getCharset());
+        } else if (object instanceof ByteBuffer) {
+            byteArray = toByteArray((ByteBuffer)object);
+        } else {
+            try {
+                byteArray = (byte[])((byte[])object);
+            } catch (ClassCastException var4) {
+                ClassCastException e = var4;
+                throw new EncoderException(e.getMessage(), e);
+            }
+        }
+
+        return encodeHex(byteArray);
+    }
+
+    public Charset getCharset() {
+        return this.charset;
+    }
+
+    public String getCharsetName() {
+        return this.charset.name();
+    }
+
+    public String toString() {
+        return super.toString() + "[charsetName=" + this.charset + "]";
+    }
+
+    static {
+        DEFAULT_CHARSET = StandardCharsets.UTF_8;
+        DIGITS_LOWER = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+        DIGITS_UPPER = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
+    }
+}

+ 190 - 0
lib_base/src/main/java/com/quyunshuo/sbm10/base/utils/commons/StringUtils.java

@@ -0,0 +1,190 @@
+package com.quyunshuo.sbm10.base.utils.commons;
+
+import java.io.UnsupportedEncodingException;
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+
+public class StringUtils {
+    public StringUtils() {
+    }
+    /**
+     * 将整数转换为指定位数的十六进制字符串
+     * @param num 输入整数(支持负数补码转换)
+     * @param bits 目标十六进制位数(1~8)
+     * @param uppercase 是否大写字母
+     * @param truncate 超长时是否截断高位(false时抛异常)
+     * @return 格式化后的十六进制字符串
+     * @throws IllegalArgumentException 参数不合法或数据溢出
+     */
+    public static String intToHex(
+            int num,
+            int bits,
+            boolean uppercase,
+            boolean truncate
+    ) throws IllegalArgumentException {
+        // 参数校验
+        if (bits < 1 || bits > 8) {
+            throw new IllegalArgumentException("Bits must be between 1 and 8");
+        }
+
+        long maxVal = (1L << (bits * 4)) - 1;
+        long minVal = (bits < 8) ? -(1L << (bits * 4 - 1)) : Integer.MIN_VALUE;
+
+        // 溢出检查
+        if (!truncate) {
+            if (num > maxVal || num < minVal) {
+                throw new IllegalArgumentException(
+                        "Value " + num + " out of range for " + bits + " hex digits"
+                );
+            }
+        }
+
+        // 转换为无符号数值(处理补码)
+        long mask = (1L << (bits * 4)) - 1;
+        long unsignedNum = num & mask;
+
+        // 格式化为字符串
+        String format = "%0" + bits + (uppercase ? "X" : "x");
+        return String.format(format, unsignedNum);
+    }
+
+    // 重载简化方法
+    public static String intToHex(int num, int bits) {
+        return intToHex(num, bits, true, true);
+    }
+    public static boolean equals(CharSequence cs1, CharSequence cs2) {
+        if (cs1 == cs2) {
+            return true;
+        } else if (cs1 != null && cs2 != null) {
+            if (cs1 instanceof String && cs2 instanceof String) {
+                return cs1.equals(cs2);
+            } else {
+                return cs1.length() == cs2.length() && CharSequenceUtils.regionMatches(cs1, false, 0, cs2, 0, cs1.length());
+            }
+        } else {
+            return false;
+        }
+    }
+
+    private static ByteBuffer getByteBuffer(String string, Charset charset) {
+        return string == null ? null : ByteBuffer.wrap(string.getBytes(charset));
+    }
+
+    public static ByteBuffer getByteBufferUtf8(String string) {
+        return getByteBuffer(string, StandardCharsets.UTF_8);
+    }
+
+    private static byte[] getBytes(String string, Charset charset) {
+        return string == null ? null : string.getBytes(charset);
+    }
+
+    public static byte[] getBytesIso8859_1(String string) {
+        return getBytes(string, StandardCharsets.ISO_8859_1);
+    }
+
+    public static byte[] getBytesUnchecked(String string, String charsetName) {
+        if (string == null) {
+            return null;
+        } else {
+            try {
+                return string.getBytes(charsetName);
+            } catch (UnsupportedEncodingException var3) {
+                UnsupportedEncodingException e = var3;
+                throw newIllegalStateException(charsetName, e);
+            }
+        }
+    }
+
+    public static byte[] getBytesUsAscii(String string) {
+        return getBytes(string, StandardCharsets.US_ASCII);
+    }
+
+    public static byte[] getBytesUtf16(String string) {
+        return getBytes(string, StandardCharsets.UTF_16);
+    }
+
+    public static byte[] getBytesUtf16Be(String string) {
+        return getBytes(string, StandardCharsets.UTF_16BE);
+    }
+
+    public static byte[] getBytesUtf16Le(String string) {
+        return getBytes(string, StandardCharsets.UTF_16LE);
+    }
+
+    public static byte[] getBytesUtf8(String string) {
+        return getBytes(string, StandardCharsets.UTF_8);
+    }
+
+    private static IllegalStateException newIllegalStateException(String charsetName, UnsupportedEncodingException e) {
+        return new IllegalStateException(charsetName + ": " + e);
+    }
+
+    private static String newString(byte[] bytes, Charset charset) {
+        return bytes == null ? null : new String(bytes, charset);
+    }
+
+    public static String newString(byte[] bytes, String charsetName) {
+        if (bytes == null) {
+            return null;
+        } else {
+            try {
+                return new String(bytes, charsetName);
+            } catch (UnsupportedEncodingException var3) {
+                UnsupportedEncodingException e = var3;
+                throw newIllegalStateException(charsetName, e);
+            }
+        }
+    }
+
+    public static String newStringIso8859_1(byte[] bytes) {
+        return newString(bytes, StandardCharsets.ISO_8859_1);
+    }
+
+    public static String newStringUsAscii(byte[] bytes) {
+        return newString(bytes, StandardCharsets.US_ASCII);
+    }
+
+    public static String newStringUtf16(byte[] bytes) {
+        return newString(bytes, StandardCharsets.UTF_16);
+    }
+
+    public static String newStringUtf16Be(byte[] bytes) {
+        return newString(bytes, StandardCharsets.UTF_16BE);
+    }
+
+    public static String newStringUtf16Le(byte[] bytes) {
+        return newString(bytes, StandardCharsets.UTF_16LE);
+    }
+
+    public static String newStringUtf8(byte[] bytes) {
+        return newString(bytes, StandardCharsets.UTF_8);
+    }
+
+    public static int parseInt(String hex) {
+        return Integer.parseInt(hex, 16);
+    }
+    /**
+     * 严格模式转换(限制输入范围)
+     * @param value 0-65535 范围的整数
+     * @return 4位大写十六进制字符串
+     * @throws IllegalArgumentException 输入超出范围时抛出
+     */
+    public static String intTo4DigitHexStrict(int value) {
+        if (value < 0 || value > 0xFFFF) {
+            throw new IllegalArgumentException(
+                    "Value " + value + " exceeds 16-bit range (0-65535)");
+        }
+        return String.format("%04X", value);
+    }
+    // 判断字符串是否为null或空
+    public static boolean isNullOrEmpty(String str) {
+        return str == null || str.isEmpty();
+    }
+
+    // 判断字符串是否不为null且不为空
+    public static boolean isNotNullOrEmpty(String str) {
+        return !isNullOrEmpty(str);
+    }
+
+}

+ 5 - 0
lib_common/src/main/java/com/quyunshuo/sbm10/common/constant/MqName.kt

@@ -25,4 +25,9 @@ object MqName {
     var updatePrice = "updatePrice"//MQtt修改价格
     var log = "log"//上传log到服务器
     var updateApk = "updateApk"//上传log到服务器
+
+    /**
+     * 服务器接收数据
+     * */
+    var RECEIVE = "receive"//发送成功
 }

+ 115 - 0
lib_common/src/main/java/com/quyunshuo/sbm10/common/util/CustomFileNameGenerator.kt

@@ -0,0 +1,115 @@
+package com.quyunshuo.sbm10.common.util
+
+import android.text.TextUtils
+import android.util.Log
+import com.elvishew.xlog.printer.file.naming.FileNameGenerator
+import com.quyunshuo.sbm10.common.util.FileUtil.makeFilePath
+
+import java.io.BufferedReader
+import java.io.File
+import java.io.FileInputStream
+import java.io.FileNotFoundException
+import java.io.IOException
+import java.io.InputStreamReader
+import java.io.RandomAccessFile
+import java.text.SimpleDateFormat
+import java.util.Date
+import java.util.Locale
+import java.util.Random
+import java.util.TimeZone
+
+class CustomFileNameGenerator : FileNameGenerator {
+    override fun isFileNameChangeable(): Boolean {
+        return false
+    }
+
+    var mLocalDateFormat: ThreadLocal<SimpleDateFormat> = object : ThreadLocal<SimpleDateFormat>() {
+        override fun initialValue(): SimpleDateFormat {
+            return SimpleDateFormat("yyyyMMdd", Locale.US)
+        }
+    }
+
+    override fun generateFileName(logLevel: Int, timestamp: Long): String {
+        val sdf = mLocalDateFormat.get()
+        sdf.timeZone = TimeZone.getDefault()
+        return sdf.format(Date(timestamp)) + "-" + getDeviceId()+".txt"
+    }
+
+    fun getDeviceId(): String {
+        var deviceId = ""
+        val file = File("/storage/emulated/0/mht/deviceid.txt")
+        val fileContent = getFileContent(file)
+        if (file != null && !TextUtils.isEmpty(fileContent)) {
+            //如果存在 直接获取
+            deviceId = fileContent.trim { it <= ' ' }
+        } else {
+            //不存在 先生成再获取
+            writeData()
+            deviceId = getFileContent(file).trim { it <= ' ' }
+        }
+        return deviceId
+    }
+
+    //读取指定目录下的所有TXT文件的文件内容
+    private fun getFileContent(file: File?): String {
+        var content = ""
+        if (!file!!.isDirectory) {  //检查此路径名的文件是否是一个目录(文件夹)
+            if (file.name.endsWith("txt")) { //文件格式为""文件
+                var buffreader: BufferedReader? = null
+                try {
+                    buffreader = BufferedReader(InputStreamReader(FileInputStream(file), "UTF-8"))
+                    content += buffreader.readLine() + "\n"
+                } catch (e: FileNotFoundException) {
+                    LogUtil.d("TestFile", "The File doesn't not exist.")
+                } catch (e: IOException) {
+                } finally {
+                    try {
+                        buffreader?.close()
+                    } catch (e: IOException) {
+                        e.printStackTrace()
+                    }
+                }
+            }
+        }
+        return content
+    }
+
+    private fun writeData() {
+        val filePath = "/storage/emulated/0/mht/"
+        val fileName = "deviceid.txt"
+        var deviceId = ""
+        val l = System.currentTimeMillis()
+        val random = Random()
+        var randomText = ""
+        for (i in 0..3) {
+            val j = random.nextInt(1000)
+            randomText = randomText + j
+        }
+        deviceId = l.toString() + randomText
+        writeTxtToFile(deviceId, filePath, fileName)
+    }
+
+    // 将字符串写入到文本文件中
+    private fun writeTxtToFile(strcontent: String, filePath: String, fileName: String) {
+        //生成文件夹之后,再生成文件,不然会出错
+        makeFilePath(filePath, fileName)
+
+        val strFilePath = filePath + fileName
+        // 每次写入时,都换行写
+        val strContent = strcontent + "\r\n"
+        try {
+            val file = File(strFilePath)
+            if (!file.exists()) {
+                LogUtil.d("TestFile", "Create the file:$strFilePath")
+                file.parentFile.mkdirs()
+                file.createNewFile()
+            }
+            val raf = RandomAccessFile(file, "rwd")
+            raf.seek(file.length())
+            raf.write(strContent.toByteArray())
+            raf.close()
+        } catch (e: Exception) {
+            Log.e("TestFile", "Error on write File:$e")
+        }
+    }
+}

+ 4 - 1
lib_common/src/main/java/com/quyunshuo/sbm10/common/util/FileUtil.kt

@@ -185,8 +185,9 @@ object FileUtil {
     fun makeFilePath(filePath: String, fileName: String): File? {
         var file: File? = null
         makeRootDirectory(filePath)
+        Log.d(TAG, "makeFilePath: "+filePath+":"+fileName)
         try {
-            file = File(filePath + fileName)
+            file = File(fileName)
             if (!file.exists()) {
                 file.createNewFile()
             }
@@ -309,6 +310,8 @@ object FileUtil {
         val format = SimpleDateFormat("yyyyMMdd")
         val date =
             format.format(Date(System.currentTimeMillis())) + "-" + getDeviceId() + ".txt"
+        Log.d(TAG, "getFileName: "+date)
+
         return date
     }
 

+ 17 - 17
lib_common/src/main/java/com/quyunshuo/sbm10/common/util/LogUtils.java

@@ -18,20 +18,20 @@ public class LogUtils {
      */
     public static void logWrite(String logDate){
         String content = format.format(new Date(System.currentTimeMillis()))+":" + logDate + "\r\n";
-        try {
-            mFileOutputStream = new FileOutputStream(createLogFile(), true);
-            mFileOutputStream.write(content.getBytes());
-            mFileOutputStream.close();
-        } catch (Exception e) {
-        }finally {
-            try {
-                if (mFileOutputStream != null) {
-                    mFileOutputStream.close();
-                }
-            } catch (IOException e) {
-                e.printStackTrace();
-            }
-        }
+//        try {
+//            mFileOutputStream = new FileOutputStream(createLogFile(), true);
+//            mFileOutputStream.write(content.getBytes());
+//            mFileOutputStream.close();
+//        } catch (Exception e) {
+//        }finally {
+//            try {
+//                if (mFileOutputStream != null) {
+//                    mFileOutputStream.close();
+//                }
+//            } catch (IOException e) {
+//                e.printStackTrace();
+//            }
+//        }
     }
 
     /**
@@ -70,9 +70,9 @@ public class LogUtils {
     /**
      * 創建log文件,以及文件的路径。
      */
-    public static File createLogFile() {
-        return FileUtil.INSTANCE.makeFilePath(FileUtil.INSTANCE.getFILEPATH(), FileUtil.INSTANCE.getFileName());
-    }
+//    public static File createLogFile() {
+//        return FileUtil.INSTANCE.makeFilePath(FileUtil.INSTANCE.getFILEPATH(), FileUtil.INSTANCE.getFileName());
+//    }
 
 
 }

+ 11 - 3
lib_common/src/main/java/com/quyunshuo/sbm10/common/util/XLogUtil.kt

@@ -1,6 +1,5 @@
 package com.quyunshuo.sbm10.common.util
 
-import android.os.Environment
 import android.util.Log
 import com.elvishew.xlog.LogConfiguration
 import com.elvishew.xlog.LogLevel
@@ -13,15 +12,18 @@ import com.elvishew.xlog.printer.file.FilePrinter
 import com.elvishew.xlog.printer.file.backup.FileSizeBackupStrategy
 import com.elvishew.xlog.printer.file.clean.FileLastModifiedCleanStrategy
 import com.elvishew.xlog.printer.file.naming.DateFileNameGenerator
+import com.elvishew.xlog.printer.file.naming.FileNameGenerator
 import com.elvishew.xlog.printer.file.writer.SimpleWriter
 import com.quyunshuo.sbm10.common.constant.SavaAddress
 import java.io.File
 
+
 /**
  * log 工具类:可以存储成文件。又可以输出,好东西。
  * tips:不要用于循环之中,不然文件大小会非常恐怖。
  */
 object XLogUtil {
+    lateinit var fileName: CustomFileNameGenerator
 
     fun init() {
         val config = LogConfiguration.Builder()
@@ -35,10 +37,12 @@ object XLogUtil {
         val androidPrinter =
             AndroidPrinter(true)
 
+        fileName = CustomFileNameGenerator()
+
         val logFolder = SavaAddress.log
-        createExternalFolder(logFolder)
+         createExternalFolder(logFolder)
         val filePrinter = FilePrinter.Builder(logFolder)
-            .fileNameGenerator(DateFileNameGenerator())//日志文件名格式
+            .fileNameGenerator(fileName)//日志文件名格式
             .backupStrategy(FileSizeBackupStrategy((500 * 1024 * 1024).toLong()))//单个日志文件的大小默认:FileSizeBackupStrategy(1024 * 1024) 500MB
             .cleanStrategy(FileLastModifiedCleanStrategy(10L * 24L * 60L * 60L * 1000L))//日志文件存活时间,单位毫秒 10天
             .flattener(ClassicFlattener())//配置写入文件日志格式:年月日时分秒
@@ -48,6 +52,10 @@ object XLogUtil {
         XLog.init(config, androidPrinter, filePrinter)
     }
 
+    fun getDeviceId(): String {
+        return fileName.getDeviceId()
+    }
+
     fun createExternalFolder(folderName: String?) {
         val folder = File(folderName)
         if (!folder.exists()) {

+ 1 - 2
module_backstage/src/main/java/com/module/backstage/activity/setting/SettingActivity.kt

@@ -54,7 +54,6 @@ import com.quyunshuo.sbm10.common.constant.RouteUrl.Main.MainActivity
 import com.quyunshuo.sbm10.common.constant.event.ApiMessageEvent
 import com.quyunshuo.sbm10.common.enums.ConnectStateEnum
 import com.quyunshuo.sbm10.common.ui.BaseActivity
-import com.quyunshuo.sbm10.common.util.FileUtil
 import com.quyunshuo.sbm10.base.utils.LanguageUtil
 import com.quyunshuo.sbm10.common.constant.PayName
 import com.quyunshuo.sbm10.common.util.LongClickUtils
@@ -172,7 +171,7 @@ class SettingActivity : BaseActivity<BackstageActivitySettingBinding, SettingVie
         mBinding.tvCrateVersion.text =UiUtil.getStringRes(R.string.body_version)+":" +  SBCHeartbeat.crateVersion
         mBinding.tvAppVersion.text =
             "App:" + packageManager.getPackageInfo(packageName, 0).versionName
-        val deviceId = FileUtil.getDeviceId()
+        val deviceId = XLogUtil.getDeviceId()
         if (deviceId.isNotEmpty()) {
             mBinding.tvDevDogtag.text =
                 UiUtil.getStringRes(R.string.home_dev_id) + deviceId.substring(deviceId.length - 6)

+ 1 - 1
module_home/build.gradle

@@ -28,6 +28,6 @@ dependencies {
     implementation project(path: ':module_pay')
     implementation 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.2.4'
     implementation 'org.eclipse.paho:org.eclipse.paho.android.service:1.1.1'
-    implementation project(path: ':lib_base')
+    api project(path: ':lib_base')
 
 }

+ 5 - 2
module_home/src/main/java/com/quyunshuo/module/home/enums/LogoEnum.kt

@@ -1,14 +1,18 @@
 package com.quyunshuo.module.home.enums
 
+import android.util.Log
 import com.quyunshuo.sbm10.base.addressenum.PayEnum
 import com.quyunshuo.sbm10.common.util.UiUtil
 import com.quyunshuo.module.home.R
 
 //还需要增加宽度和高度的自定义。因为每个logo都不一样。
+private  val TAG = "LogoEnum"
+
 enum class LogoEnum(val code:String, val navId:Int,val width:Int,val height:Int) {
     SUNZEE_LOGO("1", R.drawable.logo,141,58),
     SUNZEE_LOGO1("2", R.drawable.logo_1,141,58),
-    SEVEN_CLOUD_LOGO("7777", R.drawable.logo_sevencloud,141,58);
+    SEVEN_CLOUD_LOGO("7777", R.drawable.logo_sevencloud,141,58),
+    NO_LOGO("0000", R.drawable.logo_sevencloud,0,0);
 
     companion object {
         fun getEnumByValue(code: String): LogoEnum? {
@@ -19,6 +23,5 @@ enum class LogoEnum(val code:String, val navId:Int,val width:Int,val height:Int)
             }
             return null
         }
-
     }
 }

+ 1 - 2
module_home/src/main/java/com/quyunshuo/module/home/fragment/fragment/BuyFragment.kt

@@ -24,7 +24,6 @@ import com.quyunshuo.sbm10.base.utils.RegisterEventBus
 import com.quyunshuo.sbm10.base.utils.SpUtils
 import com.quyunshuo.sbm10.common.constant.MMKVName
 import com.quyunshuo.sbm10.common.ui.BaseFragment
-import com.quyunshuo.sbm10.common.util.FileUtil
 import com.quyunshuo.sbm10.common.util.UiUtil
 import com.quyunshuo.sbm10.common.util.XLogUtil
 import com.quyunshuo.module.home.R
@@ -69,7 +68,7 @@ class BuyFragment : BaseFragment<HomeFragmentBuyBinding, BuyFragmentVM>(),
     override fun HomeFragmentBuyBinding.initView() {
         startRefreshime()
 
-        val deviceId = FileUtil.getDeviceId()
+        val deviceId = XLogUtil.getDeviceId()
         if (deviceId.isNotEmpty()) {
             tvClientId.text =
                 UiUtil.getStringRes(R.string.home_dev_id) + deviceId.substring(deviceId.length - 6)

+ 1 - 2
module_home/src/main/java/com/quyunshuo/module/home/fragment/fragment/HomeFragment.kt

@@ -40,7 +40,6 @@ import com.quyunshuo.sbm10.common.constant.MqName
 import com.quyunshuo.sbm10.common.constant.PayName
 import com.quyunshuo.sbm10.common.constant.event.ApiMessageEvent
 import com.quyunshuo.sbm10.common.ui.BaseFragment
-import com.quyunshuo.sbm10.common.util.FileUtil
 import com.quyunshuo.sbm10.common.util.LongClickUtils
 import com.quyunshuo.sbm10.common.util.ToastUtil
 import com.quyunshuo.sbm10.common.util.UiUtil
@@ -136,7 +135,7 @@ class HomeFragment : BaseFragment<HomeFragmentHomeBinding, HomeFragmentVM>(), Vi
 
         })
         clHomeBg.setOnTouchListener(this@HomeFragment)
-        val deviceId = FileUtil.getDeviceId()
+        val deviceId = XLogUtil.getDeviceId()
         if (deviceId.isNotEmpty()) {
             tvClientId.text =
                 UiUtil.getStringRes(R.string.home_dev_id) + deviceId.substring(deviceId.length - 6)

+ 2 - 3
module_home/src/main/java/com/quyunshuo/module/home/fragment/fragment/MakeFragment.kt

@@ -40,7 +40,6 @@ import com.quyunshuo.module.home.enums.LogoEnum
 import com.quyunshuo.module.home.fragment.vm.MakeFragmentVM
 import com.quyunshuo.module.home.utils.SimplePlayerUtil
 import com.quyunshuo.module.home.weight.ProgressView
-import com.quyunshuo.sbm10.common.util.FileUtil
 import com.quyunshuo.sbm10.common.util.UiUtil
 import dagger.hilt.android.AndroidEntryPoint
 import kotlinx.coroutines.CoroutineScope
@@ -81,7 +80,7 @@ class MakeFragment : BaseFragment<HomeFragmentMakeBinding, MakeFragmentVM>(), Li
 
     @SuppressLint("SetTextI18n")
     override fun HomeFragmentMakeBinding.initView() {
-        val deviceId = FileUtil.getDeviceId()
+        val deviceId = XLogUtil.getDeviceId()
         if (deviceId.isNotEmpty()) {
             tvClientId.text =
                 UiUtil.getStringRes(R.string.home_dev_id) + deviceId.substring(deviceId.length - 6)
@@ -196,7 +195,7 @@ class MakeFragment : BaseFragment<HomeFragmentMakeBinding, MakeFragmentVM>(), Li
         plannedSpeed = 1
         // 设置叶子对象的属性,例如坐标等
         mBinding.progressView.addLeaf(leaf1)
-        mBinding.progressView.maxProgress = 95f
+        mBinding.progressView.maxProgress = 97f
         jobHandler = CoroutineScope(Dispatchers.Main).launch {
             while (true) {
                 myHandler.sendEmptyMessage(1)

+ 1 - 2
module_home/src/main/java/com/quyunshuo/module/home/fragment/fragment/UserLoginFragment.kt

@@ -21,7 +21,6 @@ import com.quyunshuo.sbm10.common.constant.MMKVName
 import com.quyunshuo.sbm10.common.constant.RouteUrl
 import com.quyunshuo.sbm10.common.keyboard.KeyboardView
 import com.quyunshuo.sbm10.common.ui.BaseFragment
-import com.quyunshuo.sbm10.common.util.FileUtil
 import com.quyunshuo.sbm10.common.util.LongClickUtils
 import com.quyunshuo.sbm10.common.util.ToastUtil
 import com.quyunshuo.sbm10.common.util.UiUtil
@@ -70,7 +69,7 @@ class UserLoginFragment : BaseFragment<HomeFragmentUserloginBinding, UserLoginFr
         homeReturnToUpperLevel.setOnClickListener(this@UserLoginFragment)
         homeLoginSetting.setOnClickListener(this@UserLoginFragment)
         Log.d(TAG, "backstage_product_2 initView1: " + UiUtil.getStringRes(R.string.home_login))
-        tvDeviceId.text = UiUtil.getStringRes(R.string.home_dev_id) + FileUtil.getDeviceId()
+        tvDeviceId.text = UiUtil.getStringRes(R.string.home_dev_id) + XLogUtil.getDeviceId()
         language2ArrayAdapter =
             this@UserLoginFragment.context?.let { ArrayAdapter<String>(it, R.layout.spinner_login) }
         language2ArrayAdapter!!.addAll(*usernamesNew)

+ 6 - 0
module_home/src/main/java/com/quyunshuo/module/home/getui/MqttBaseBean.kt

@@ -0,0 +1,6 @@
+package com.quyunshuo.module.home.getui
+
+/**
+ * 推送数据实体
+ */
+data class MqttBaseBean(val kind_data: String, val kind: String, val key: String, val token: String)

+ 1 - 1
module_home/src/main/java/com/quyunshuo/module/home/service/ManageMqtt.kt

@@ -103,7 +103,7 @@ class ManageMqtt @Inject constructor() {
                             .post(
                                 MqttMessageBean(
                                     topicName,
-                                    MqName.messageArrived,
+                                    MqName.RECEIVE,
                                     str1
                                 )
                             )

+ 7 - 4
module_home/src/main/java/com/quyunshuo/module/home/service/MqService.kt

@@ -19,11 +19,11 @@ import com.quyunshuo.sbm10.common.constant.MMKVName
 import com.quyunshuo.sbm10.common.constant.MqName
 import com.quyunshuo.sbm10.common.constant.SavaAddress
 import com.quyunshuo.sbm10.common.enums.ConnectStateEnum
-import com.quyunshuo.sbm10.common.util.FileUtil
 import com.quyunshuo.sbm10.common.util.ToastUtil
 import com.quyunshuo.sbm10.common.util.UiUtil
 import com.quyunshuo.module.home.R
 import com.quyunshuo.module.home.receiver.MqttHelper
+import com.quyunshuo.sbm10.common.util.XLogUtil
 import com.rabbitmq.client.AMQP
 import com.rabbitmq.client.Channel
 import com.rabbitmq.client.Connection
@@ -64,7 +64,7 @@ class MqService : Service() {
     var connect: Boolean = false
     val handler: Handler = object : Handler() {
         override fun handleMessage(msg: Message) {
-            mqServiceViewModel.getMessage(msg)
+            mqServiceViewModel.getMtMessage(msg)
         }
     }
 
@@ -155,6 +155,9 @@ class MqService : Service() {
                     ToastUtil.switchToastStyleToWarn(UiUtil.getStringRes(R.string.mqtt_con_state))
                 }
             }
+            MqName.RECEIVE -> {
+                mqServiceViewModel.getMQTTMessage(message.content)
+            }
         }
     }
 
@@ -205,7 +208,7 @@ class MqService : Service() {
         val machineType: String = SpUtils.getString(MMKVName.MACHINE_TYPE, SavaAddress.MACHINE_TYPE)!!
         Log.d(TAG, "$data: mq getAddQueue: $machineType")
         // SharedPreferencesUtils.setParam(Name.QUEUE_DATA, data);
-        if (("" == FileUtil.getDeviceId())) {
+        if (("" == XLogUtil.getDeviceId())) {
             //如果没有id,肯定是新机器,无创建过队列,直接 return;
             Log.d(TAG, "mq,没有id,直接跳出")
             return
@@ -255,7 +258,7 @@ class MqService : Service() {
                 ) {
                     queueName = Heartbeat.deviceId!!
                 } else {
-                    queueName = FileUtil.getDeviceId()
+                    queueName = XLogUtil.getDeviceId()
                 }
                 try {
                     //1. 连接

+ 10 - 0
module_home/src/main/java/com/quyunshuo/module/home/service/MqServiceViewModel.kt

@@ -59,4 +59,14 @@ class MqServiceViewModel @Inject constructor(
         remotePushUtil.getMessage(msg)
 
     }
+
+    fun getMQTTMessage(msg: String) {
+        Log.d("backinfo","getMQTTMessage:"+msg)
+        remotePushUtil.getMqttMessage(msg)
+    }
+
+    fun getMtMessage(msg: Message) {
+        remotePushUtil.getMessage(msg)
+
+    }
 }

+ 48 - 0
module_home/src/main/java/com/quyunshuo/module/home/utils/RemotePushUtil.kt

@@ -9,6 +9,10 @@ import android.util.Log
 import com.google.gson.Gson
 import com.hboxs.serialport.plc.message.Message
 import com.hboxs.serialport.plc.thread.ThreadSettingParam
+import com.qiniu.android.http.ResponseInfo
+import com.qiniu.android.storage.UpCompletionHandler
+import com.qiniu.android.storage.UploadManager
+import com.qiniu.android.storage.UploadOptions
 import com.quyunshuo.sbm10.base.BaseApplication
 import com.quyunshuo.sbm10.base.BaseApplication.Companion.context
 import com.quyunshuo.sbm10.base.addressenum.PlcSettingAddressEnum
@@ -27,6 +31,8 @@ import com.quyunshuo.module.home.R
 import com.quyunshuo.module.home.bean.AlarmClockBean
 import com.quyunshuo.module.home.bean.PaySuccessBean
 import com.quyunshuo.module.home.getui.BaseBean
+import com.quyunshuo.module.home.getui.MqttBaseBean
+import com.quyunshuo.sbm10.base.utils.JsonUtils
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.delay
@@ -39,6 +45,7 @@ import okhttp3.Response
 import org.greenrobot.eventbus.EventBus
 import org.greenrobot.eventbus.Subscribe
 import org.greenrobot.eventbus.ThreadMode
+import org.json.JSONObject
 import java.io.ByteArrayOutputStream
 import java.io.DataInputStream
 import java.io.File
@@ -184,7 +191,48 @@ class RemotePushUtil @Inject constructor() {
             else -> {}
         }
     }
+    fun getMqttMessage(msg: String) {
+        Log.d(TAG, "MqttMessage:" + msg)
+        var kindStr = JsonUtils.getValue(msg, "dataContent", String::class.java)
+        var DataBean = JsonUtils.getBean(kindStr, MqttBaseBean::class.java)
+        var msgId = JsonUtils.getValue(msg, "msgId", String::class.java)
+        Log.d(TAG, "11111111111111:" + JsonUtils.getJSONString(DataBean))
+        val kind: String = DataBean.kind
+        when (kind) {
+            MqName.log -> {
+                uploadLog(DataBean)
+            }
+        }
+    }
+    fun uploadLog(mqtt: MqttBaseBean) {
+        try {
+            var filePath = "/storage/emulated/0/logdata/${mqtt.kind_data}.txt"
+            val uploadManager = UploadManager()
+            val uploadFile: File = File(filePath)
+            val uploadFileKey: String =  mqtt.key
+                .trim()
+            Log.d(TAG, "uploadLog: "+filePath)
+            val options = UploadOptions(null, null, false,
+                { key, percent ->
+                }, { // 当需要取消时,此处返回 true,SDK 内部会多次检查返回值,当返回值为 true 时会取消上传操作
+                    false
+                })
+            uploadManager.put(uploadFile,uploadFileKey,mqtt.token,object : UpCompletionHandler {
+                override fun complete(key: String?, info: ResponseInfo?, response: JSONObject?) {
+                    Log.d(TAG, "complete:" +  JsonUtils.getJSONString(info))
+                    if (info != null && info.isOK()) {
+                        // 上传成功
+                    } else {
+                        Log.d(TAG, "失败:" +  JsonUtils.getJSONString(info))
+                        // 上传失败
+                    }
+                }
 
+            },options)
+        } catch (e: IOException) {
+            Log.e("QiniuLab", e.message!!)
+        }
+    }
 
     /**
      * 远程推送apk或图片

+ 0 - 1
serialport-api/src/main/java/com/hboxs/serialport/sbc/VboxSerialPortReadThread.java

@@ -13,7 +13,6 @@ import com.hboxs.serialport.sbc.frame.VboxResponseFrame;
 import com.quyunshuo.sbm10.common.constant.MMKVName;
 import com.quyunshuo.sbm10.common.util.ByteUtils;
 import com.quyunshuo.sbm10.common.util.LogUtil;
-import com.quyunshuo.sbm10.common.util.LogUtils;
 import com.quyunshuo.sbm10.common.util.XLogUtil;
 
 import org.greenrobot.eventbus.EventBus;

+ 0 - 1
serialport-api/src/main/java/com/hboxs/serialport/sbc/VboxSerialPortSendQueue.java

@@ -9,7 +9,6 @@ import android.util.Log;
 
 import com.hboxs.serialport.sbc.frame.VboxCommandFrame;
 import com.hboxs.serialport.sbc.frame.VboxOrder;
-import com.quyunshuo.sbm10.common.util.LogUtils;
 import com.quyunshuo.sbm10.common.util.XLogUtil;
 
 import java.util.LinkedList;