Runt
2025-08-05 546cf3cc5df3fd55e10672e474c246582b947689
网络请求加密
网络请求优化
弹窗优化
1 files deleted
7 files added
8 files modified
865 ■■■■ changed files
libmvi/build.gradle.kts 4 ●●●● patch | view | raw | blame | history
libmvi/src/main/java/com/runt/open/mvi/data/PhoneDevice.java 4 ●●●● patch | view | raw | blame | history
libmvi/src/main/java/com/runt/open/mvi/retrofit/Interceptor/AddHeadersInterceptor.java 41 ●●●●● patch | view | raw | blame | history
libmvi/src/main/java/com/runt/open/mvi/retrofit/Interceptor/EncryptInterceptor.java 20 ●●●●● patch | view | raw | blame | history
libmvi/src/main/java/com/runt/open/mvi/retrofit/Interceptor/HttpLoggingInterceptor.java 36 ●●●● patch | view | raw | blame | history
libmvi/src/main/java/com/runt/open/mvi/retrofit/Interceptor/LogEncryptInterceptor.java 19 ●●●●● patch | view | raw | blame | history
libmvi/src/main/java/com/runt/open/mvi/retrofit/Interceptor/OpenInterceptor.java 117 ●●●●● patch | view | raw | blame | history
libmvi/src/main/java/com/runt/open/mvi/retrofit/converter/DecryptGsonConverterFactory.java 58 ●●●●● patch | view | raw | blame | history
libmvi/src/main/java/com/runt/open/mvi/retrofit/converter/DecryptGsonResponseBodyConverter.java 98 ●●●●● patch | view | raw | blame | history
libmvi/src/main/java/com/runt/open/mvi/retrofit/converter/EncryptGsonRequestBodyConverter.java 43 ●●●●● patch | view | raw | blame | history
libmvi/src/main/java/com/runt/open/mvi/retrofit/converter/GsonConverterFactory.java 2 ●●● patch | view | raw | blame | history
libmvi/src/main/java/com/runt/open/mvi/retrofit/utils/RSAUtils.java 180 ●●●●● patch | view | raw | blame | history
libmvi/src/main/java/com/runt/open/mvi/retrofit/utils/RetrofitUtils.java 175 ●●●● patch | view | raw | blame | history
libmvi/src/main/java/com/runt/open/mvi/utils/DeviceIdUtils.java 2 ●●● patch | view | raw | blame | history
libmvi/src/main/java/com/runt/open/mvi/utils/DeviceUtil.java 52 ●●●●● patch | view | raw | blame | history
libmvi/src/main/java/com/runt/open/mvi/views/PublicViews.kt 14 ●●●● patch | view | raw | blame | history
libmvi/build.gradle.kts
@@ -17,12 +17,12 @@
        debug {
            isMinifyEnabled = false
            buildConfigField("String","HOST_IP_ADDR","\"http://192.168.28.9:8080/\"")
            buildConfigField("String","HOST_IP_ADDR","\"http://192.168.28.89:8080/\"")
            proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt") , "proguard-rules.pro")
        }
        release {
            isMinifyEnabled = false
            buildConfigField("String","HOST_IP_ADDR","\"http://192.168.28.9:8080/\"")
            buildConfigField("String","HOST_IP_ADDR","\"http://192.168.28.175:8888/advert/\"")
            proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt") , "proguard-rules.pro")
        }
    }
libmvi/src/main/java/com/runt/open/mvi/data/PhoneDevice.java
@@ -4,7 +4,7 @@
import android.os.Build;
import com.runt.open.mvi.retrofit.utils.NetWorkUtils;
import com.runt.open.mvi.utils.DeviceUtil;
import com.runt.open.mvi.utils.DeviceIdUtils;
/**
@@ -20,7 +20,7 @@
    static PhoneDevice device;
    public static void setDevice(Context context) {
        device = new PhoneDevice(Build.BRAND,Build.MODEL,Build.VERSION.SDK_INT+"",Build.VERSION.RELEASE, DeviceUtil.getSerialNumber(context), NetWorkUtils.getNetIp());
        device = new PhoneDevice(Build.BRAND,Build.MODEL,Build.VERSION.SDK_INT+"",Build.VERSION.RELEASE, DeviceIdUtils.getDeviceId(context), NetWorkUtils.getNetIp());
    }
    public static PhoneDevice getDevice() {
libmvi/src/main/java/com/runt/open/mvi/retrofit/Interceptor/AddHeadersInterceptor.java
File was deleted
libmvi/src/main/java/com/runt/open/mvi/retrofit/Interceptor/EncryptInterceptor.java
New file
@@ -0,0 +1,20 @@
package com.runt.open.mvi.retrofit.Interceptor;
import java.io.IOException;
import okhttp3.Response;
/**
 * @purpose  加密拦截器
 * @author Runt (qingingrunt2010@qq.com)
 * @date  2021-10-8.
 */
public class EncryptInterceptor extends OpenInterceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        return chain.proceed(encryptRequest(chain.request()));
    }
}
libmvi/src/main/java/com/runt/open/mvi/retrofit/Interceptor/HttpLoggingInterceptor.java
@@ -2,13 +2,9 @@
import android.util.Log;
import com.google.gson.Gson;
import com.runt.open.mvi.OpenApplication;
import com.runt.open.mvi.data.PhoneDevice;
import com.runt.open.mvi.retrofit.net.NetWorkCost;
import com.runt.open.mvi.retrofit.net.NetWorkListener;
import com.runt.open.mvi.retrofit.utils.HttpPrintUtils;
import com.runt.open.mvi.utils.DeviceUtil;
import org.json.JSONArray;
import org.json.JSONException;
@@ -40,31 +36,17 @@
 * @purpose Created by Runt (qingingrunt2010@qq.com) on 2020-10-21.
 */
public class HttpLoggingInterceptor extends AddHeadersInterceptor {
public class HttpLoggingInterceptor extends OpenInterceptor {
    final String TAG = "HttpLogging";
    private boolean printLog ;
    public HttpLoggingInterceptor(){
        this(true);
    }
    public HttpLoggingInterceptor(boolean printLog) {
        this.printLog = printLog;
    }
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request requestTemp = chain.request();
        int hashCode = requestTemp.hashCode();
        if(printLog) {
            Log.d(TAG, "hashcode:" + hashCode);
        }
        Request.Builder requestBuild = requestTemp.newBuilder()
                .addHeader("device", new Gson().toJson(PhoneDevice.getDevice()))
                .addHeader("appVersion",  DeviceUtil.getAppVersionName(OpenApplication.Companion.getApplication()))
                .addHeader("os", DeviceUtil.isHarmonyOS()? "harmony" : "android");
        Request.Builder requestBuild = addHeaders(requestTemp);
        /*if(UserBean.getUser() != null){
            requestBuild.addHeader("token",UserBean.getUser().getToken());
        }*/
@@ -74,7 +56,7 @@
        try {
            logArrays.addAll(getRequestLog(request));
            int position = logArrays.size() +2;
            response = chain.proceed(request);
            response = proceed(chain,request);
            logArrays.addAll(getResponseLog(response));
            NetWorkCost netWorkCost = NetWorkListener.workCostMap.get(hashCode);
            if(netWorkCost != null) {
@@ -84,9 +66,7 @@
            new Thread(){
                @Override
                public void run() {
                    if(printLog) {
                        HttpPrintUtils.getInstance().printLog(logArrays, true);//线程安全方法,需在新线程执行,避免阻塞当前线程,导致程序无响应
                    }
                }
            }.start();
        } catch (JSONException e) {
@@ -107,9 +87,7 @@
            new Thread(){
                @Override
                public void run() {
                    if(printLog) {
                        HttpPrintUtils.getInstance().printLog(logArrays, false);//线程安全方法,需在新线程执行,避免阻塞当前线程,导致程序无响应
                    }
                }
            }.start();
            throw e;//抛出异常,用于请求接收信息
@@ -117,12 +95,16 @@
        return response;
    }
    protected Response proceed(Chain chain,Request request) throws IOException {
        return chain.proceed(request);
    }
    /**
     * 请求数据信息
     * @param request
     * @return
     */
    private ArrayList<String> getRequestLog(Request request) throws IOException, JSONException {
    protected ArrayList<String> getRequestLog(Request request) throws IOException, JSONException {
        RequestBody requestBody = request.body();
        ArrayList<String> logArrays = new ArrayList<>();
        String requestStartMessage = "--> " + request.method() + ' ' + URLDecoder.decode(request.url().toString() ,"UTF-8")+ ' ' ;
@@ -195,7 +177,7 @@
     * @throws IOException
     * @throws JSONException
     */
    private ArrayList<String> getResponseLog(Response response) throws IOException, JSONException {
    protected ArrayList<String> getResponseLog(Response response) throws IOException, JSONException {
        ArrayList<String> logArrays = new ArrayList<>();
        ResponseBody responseBody = response.body();
        long contentLength = responseBody.contentLength();
libmvi/src/main/java/com/runt/open/mvi/retrofit/Interceptor/LogEncryptInterceptor.java
New file
@@ -0,0 +1,19 @@
package com.runt.open.mvi.retrofit.Interceptor;
import java.io.IOException;
import okhttp3.Request;
import okhttp3.Response;
/**
 * @author Runt(qingingrunt2010 @ qq.com)
 * @purpose
 * @date 8/4/25
 */
public class LogEncryptInterceptor extends HttpLoggingInterceptor{
    @Override
    protected Response proceed(Chain chain, Request request) throws IOException {
        return super.proceed(chain, encryptRequest(request));
    }
}
libmvi/src/main/java/com/runt/open/mvi/retrofit/Interceptor/OpenInterceptor.java
New file
@@ -0,0 +1,117 @@
package com.runt.open.mvi.retrofit.Interceptor;
import com.google.gson.Gson;
import com.runt.open.mvi.OpenApplication;
import com.runt.open.mvi.data.PhoneDevice;
import com.runt.open.mvi.retrofit.utils.RSAUtils;
import com.runt.open.mvi.utils.DeviceUtil;
import org.json.JSONObject;
import java.io.IOException;
import java.net.URLDecoder;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;
import okhttp3.FormBody;
import okhttp3.Headers;
import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okio.Buffer;
/**
 * My father is Object, ites purpose of   添加header拦截器
 *
 * @purpose Created by Runt (qingingrunt2010@qq.com) on 2021-10-8.
 */
public class OpenInterceptor implements Interceptor {
    protected final Charset UTF8 = Charset.forName("UTF-8");
    protected final String ENCRYPT = "encrypt";
    @Override
    public Response intercept(Chain chain) throws IOException {
        return chain.proceed(addHeaders(chain.request()).build().newBuilder().build());
    }
    protected Request.Builder addHeaders(Request request){
        Request.Builder requestBuild = request.newBuilder()
                .addHeader("device", new Gson().toJson(PhoneDevice.getDevice()))
                .addHeader("appVersion", DeviceUtil.getAppVersionName(OpenApplication.Companion.getApplication()))
                .addHeader("os", DeviceUtil.isHarmonyOS()? "harmony" : "android");
        /*if(UserBean.getUser() != null){
            requestBuild.addHeader("token", UserBean.getUser().getToken());
        }*/
        return requestBuild;
    }
    //加密
    protected Request encryptRequest(Request request) throws IOException {
        Headers headers = request.headers();
        RequestBody requestBody = request.body();
        Request.Builder builder = addHeaders(request);;
        for(int i = 0 ; i < headers.size() ; i ++){
            builder.addHeader(headers.name(i),headers.value(i));
        }
        if(requestBody != null){
            Charset charset = UTF8;
            MediaType contentType = requestBody.contentType();
            if (contentType != null) {
                charset = contentType.charset(UTF8);
            }
            HashMap param = new HashMap();
            if(requestBody instanceof MultipartBody){
                MultipartBody body = (MultipartBody) requestBody;
                for(MultipartBody.Part part:body.parts()){
                    Buffer buffer1 = new Buffer();
                    part.body().writeTo(buffer1);
                    String str=buffer1.readString(charset).replaceAll("%(?![0-9a-fA-F]{2})","%25");
                    param.put(part.headers().get(part.headers().name(0)), URLDecoder.decode(str, "UTF-8"));
                }
                MultipartBody.Builder mbuilder = new MultipartBody.Builder().setType(MultipartBody.FORM);
                mbuilder.addFormDataPart(ENCRYPT,encryptParam(param));
                builder.post(mbuilder.build());
            }else if(requestBody instanceof FormBody){
                FormBody body = (FormBody) requestBody;
                for(int i = 0 ; i < body.size() ; i ++ ){
                    param.put(body.name(i),body.value(i));
                }
                FormBody.Builder formBuild = new FormBody.Builder();
                formBuild.add(ENCRYPT,encryptParam(param));
                builder.post(formBuild.build());
            }else{
                Buffer buffer = new Buffer();
                requestBody.writeTo(buffer);
                String str = buffer.readString(charset);
                String encrypt = encryptJson(str);
                param.put(ENCRYPT,encrypt);
                builder.post(RequestBody.create(MediaType.parse("application/json;charset=utf-8"), new JSONObject(param).toString()));
            }
        }
        return builder.build();
    }
    /**
     * 加密传递的参数
     * @param params
     * @return
     */
    protected String encryptParam(Map<String, Object> params){
        return encryptJson(new JSONObject(params).toString());
    }
    protected String encryptJson(String json){
        try {
            return RSAUtils.encrypt(json,RSAUtils.getPublicKey(RSAUtils.PUBLIC_KEY));
        }catch (Exception e){
            e.printStackTrace();
            return e.getMessage();
        }
    }
}
libmvi/src/main/java/com/runt/open/mvi/retrofit/converter/DecryptGsonConverterFactory.java
New file
@@ -0,0 +1,58 @@
package com.runt.open.mvi.retrofit.converter;
import com.google.gson.Gson;
import com.google.gson.TypeAdapter;
import com.google.gson.reflect.TypeToken;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;
import retrofit2.Converter;
import retrofit2.Retrofit;
/**
 * @purpose   解密gson转换
 * @author Runt (qingingrunt2010@qq.com)
 * @date  2021-7-22.
 */
public class DecryptGsonConverterFactory extends Converter.Factory {
    public static DecryptGsonConverterFactory create() {
        return create(new Gson(),false);
    }
    public static DecryptGsonConverterFactory create(boolean transHump) {
        return create(new Gson(),transHump);
    }
    public static DecryptGsonConverterFactory create(Gson gson,boolean transHump) {
        return new DecryptGsonConverterFactory(gson,transHump);
    }
    private final Gson gson;
    private final boolean transHump;
    public DecryptGsonConverterFactory(Gson gson, boolean transHump) {
        if (gson == null) throw new NullPointerException("gson == null");
        this.gson = gson;
        this.transHump = transHump;
    }
    @Override
    public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
                                                            Retrofit retrofit) {
        TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
        return new DecryptGsonResponseBodyConverter<>(gson, adapter,transHump);
    }
    @Override
    public Converter<?, RequestBody> requestBodyConverter(Type type,
                                                          Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
        TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
        return new EncryptGsonRequestBodyConverter<>(gson, adapter);
    }
}
libmvi/src/main/java/com/runt/open/mvi/retrofit/converter/DecryptGsonResponseBodyConverter.java
New file
@@ -0,0 +1,98 @@
package com.runt.open.mvi.retrofit.converter;
import android.text.TextUtils;
import android.util.Log;
import com.google.gson.Gson;
import com.google.gson.JsonIOException;
import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.runt.open.mvi.BuildConfig;
import com.runt.open.mvi.retrofit.utils.RSAUtils;
import com.runt.open.mvi.utils.GsonUtils;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import okhttp3.ResponseBody;
import retrofit2.Converter;
/**
 * @purpose 解密gson转换器
 * @author Runt (qingingrunt2010@qq.com)
 * @date  2021-7-22.
 */
public class DecryptGsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {
    private final Gson gson;
    private final TypeAdapter<T> adapter;
    private final Charset UTF_8 = Charset.forName("UTF-8");
    private final boolean transHump;//驼峰转换
    private final String ENCRYPT = "encrypt";
    public DecryptGsonResponseBodyConverter(Gson gson, TypeAdapter<T> adapter, boolean transHump) {
        this.gson = gson;
        this.adapter = adapter;
        this.transHump = transHump;
    }
    @Override
    public T convert(ResponseBody value) throws IOException {
        String response = null;
        try {
            String val = new String(value.bytes(),UTF_8);
            response = decryptJsonStr(val);//解密
        } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
            e.printStackTrace();
            response = "{\"code\":412,\"message\":\""+"解密数据出错"+e.getMessage()+"\"}";
        } catch (JSONException e) {
            e.printStackTrace();
            response = "{\"code\":414,\"message\":\"非标准json\"}";
        }catch (Exception e){
            e.printStackTrace();
            JsonReader jsonReader = gson.newJsonReader(value.charStream());
            return adapter.read(jsonReader);
        } finally {
            if(response==null){
                return null;
            }
            InputStream inputStream = new ByteArrayInputStream(response.getBytes());
            JsonReader jsonReader = gson.newJsonReader(new InputStreamReader(inputStream, UTF_8));
            T result = adapter.read(jsonReader);
            if (jsonReader.peek() != JsonToken.END_DOCUMENT) {
                throw new JsonIOException("JSON document was not fully consumed.");
            }
            value.close();
            return result;
        }
    }
    /**
     * 解密json
     * @param body
     * @return
     * @throws Exception
     */
    protected String decryptJsonStr(String body) throws Exception {
        if(BuildConfig.DEBUG) {
            Log.e("Converter", "decryptJsonStr body:" + body);
        }
        if(TextUtils.isEmpty(body)){
        }else if(body.indexOf("{") == 0) {
            JSONObject json = new JSONObject(body);
            body = RSAUtils.decrypt(json.getString(ENCRYPT), RSAUtils.getPublicKey(RSAUtils.PUBLIC_KEY));//
            //Log.e("Converter", "decryptJsonStr body:" + body);
        }
        return transHump? GsonUtils.toHumpJson(body):body;
    }
}
libmvi/src/main/java/com/runt/open/mvi/retrofit/converter/EncryptGsonRequestBodyConverter.java
New file
@@ -0,0 +1,43 @@
package com.runt.open.mvi.retrofit.converter;
import com.google.gson.Gson;
import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.nio.charset.Charset;
import okhttp3.MediaType;
import okhttp3.RequestBody;
import okio.Buffer;
import retrofit2.Converter;
/**
 * @author Runt(qingingrunt2010 @ qq.com)
 * @purpose 加密gson转换器
 * @date 8/4/25
 */
public class EncryptGsonRequestBodyConverter<T> implements Converter<T, RequestBody> {
    private static final MediaType MEDIA_TYPE = MediaType.parse("application/json; charset=UTF-8");
    private static final Charset UTF_8 = Charset.forName("UTF-8");
    private final Gson gson;
    private final TypeAdapter<T> adapter;
    EncryptGsonRequestBodyConverter(Gson gson, TypeAdapter<T> adapter) {
        this.gson = gson;
        this.adapter = adapter;
    }
    @Override
    public RequestBody convert(T value) throws IOException {
        Buffer buffer = new Buffer();
        Writer writer = new OutputStreamWriter(buffer.outputStream(), UTF_8);
        JsonWriter jsonWriter = gson.newJsonWriter(writer);
        adapter.write(jsonWriter, value);
        jsonWriter.close();
        return RequestBody.create(MEDIA_TYPE, buffer.readByteString());
    }
}
libmvi/src/main/java/com/runt/open/mvi/retrofit/converter/GsonConverterFactory.java
@@ -15,7 +15,7 @@
import retrofit2.Retrofit;
/**
 * My father is Object, ites purpose of     解密gson转换
 * My father is Object, ites purpose of     gson转换
 *
 * @purpose Created by Runt (qingingrunt2010@qq.com) on 2021-7-22.
 */
libmvi/src/main/java/com/runt/open/mvi/retrofit/utils/RSAUtils.java
New file
@@ -0,0 +1,180 @@
package com.runt.open.mvi.retrofit.utils;
import android.util.Base64;
import java.io.ByteArrayOutputStream;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.Cipher;
public class RSAUtils {
    //客户端私钥
    public static final String PRIVATE_KEY = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALBGei0scHoOjTLImPHvASaGqYNrdLie0ckWp74Nkqv7FVeXPOvWEG8_jRJCVjJ1grr8SGd9sVY2sxn5XIz7fUEBfx7Vm8m0DaCNBWJpFLGw9xiaVZ2AUKoNyTD4NgZobbwZbt6ZNB6_fggPrGF18pq6GPyCndX1JW8ZiZKj33VBAgMBAAECgYB0q-EX3y7_CnyYXT8l-mxHhJ_T9R6HR89QimcyGqe2nvRMSjSvX7r29xg3OqL0uORzQKHnpcDncELw8SQ5yAbpENeIsD0dvdFlkoyFYU4ljeUbJ46binwwg20TNARjTbpNos9zbhTPh8qixdblxppXA1WC18HtXhixgca5bNG9lQJBAPQfNdpNdDL9l8Tw4hYVuDMszcFuZYbHbm0S4xcwqj-dXNWBztNf5W_K92-N5GIoHbOypkGzjlBjSZi_oKA0HusCQQC42irhw682CG44mKdP6YRDxy6OaauVX4yE9WnsbO8JFSSc9ZCKMMD0F3NGtytDrVMAJxG1iPWXa4ptEdtgwCmDAkAUW1npR1YuPllekdu4jb0bf1v1ClirAYxiyhVnxKYdweiQ4U827yM5zEoP4lwuFzxK1NXqWqe-alkjxK8HTPFbAkAviQLf_adP2MknSrIzzZQSreTeAHR8PA7xnf54KucpScOZjVh3AOSNoH4nYDEC_U5LysA2E5s8Lg5xz9a_QYsrAkEAwV6gNED7_SYDsYyEWimQ6znUb_QSY-sSChnSCY-ILG1wpynBHw_t1Oi3ljl6gL_cYKG1O3uwOtvZtb-Vr1bNkQ";
    //服务器公钥
    public static final String PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVj4BkEYtlv8z4quUUrkRvW4xuWQvXegMuLKPQZky8LObbxfFZniSvQ4gllFlyFuCjeeInjyQFPC3ARdbihV3P88drBsB2gCG9lwlCkgMjZfSc/hxC4VirsHbGGSIN5oPyCZMQNAUnIojpKBRlE0TJmHvP+FpAe46Yb+oPs8R5DQIDAQAB";
    /**
     * RSA最大加密明文大小
     */
    private static final int MAX_ENCRYPT_BLOCK = 117;
    /**
     * RSA最大解密密文大小
     */
    private static final int MAX_DECRYPT_BLOCK = 128;
    static final String KEY_RSA = "RSA"; //android标准 “RSA/ECB/PKCS1Padding” 服务端标准 “RSA”
    /**
     * 获取密钥对
     *
     * @return 密钥对
     */
    public static KeyPair getKeyPair() throws Exception {
        KeyPairGenerator generator = KeyPairGenerator.getInstance(KEY_RSA);
        generator.initialize(1024);
        return generator.generateKeyPair();
    }
    /**
     * 获取私钥
     *
     * @param privateKey 私钥字符串
     * @return
     */
    public static PrivateKey getPrivateKey(String privateKey) throws Exception {
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_RSA);
        byte[] decodedKey = Base64.decode(privateKey.getBytes(), Base64.URL_SAFE);
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(decodedKey);
        return keyFactory.generatePrivate(keySpec);
    }
    /**
     * 获取公钥
     *
     * @param publicKey 公钥字符串
     * @return
     */
    public static PublicKey getPublicKey(String publicKey) throws Exception {
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_RSA);
        byte[] decodedKey = Base64.decode(publicKey.getBytes(), Base64.DEFAULT);
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(decodedKey);
        return keyFactory.generatePublic(keySpec);
    }
    /**
     * RSA加密
     *
     * @param data 待加密数据
     * @param key 密钥
     * @return
     */
    public static String encrypt(String data, Key key) throws Exception {
        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        cipher.init(Cipher.ENCRYPT_MODE, key);
        int inputLen = data.getBytes().length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offset = 0;
        byte[] cache;
        int i = 0;
        // 对数据分段加密
        while (inputLen - offset > 0) {
            if (inputLen - offset > MAX_ENCRYPT_BLOCK) {
                cache = cipher.doFinal(data.getBytes(), offset, MAX_ENCRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(data.getBytes(), offset, inputLen - offset);
            }
            out.write(cache, 0, cache.length);
            i++;
            offset = i * MAX_ENCRYPT_BLOCK;
        }
        byte[] encryptedData = out.toByteArray();
        out.close();
        // 获取加密内容使用base64进行编码,并以UTF-8为标准转化成字符串
        // 加密后的字符串
        return Base64.encodeToString(encryptedData,Base64.URL_SAFE | Base64.NO_WRAP);
    }
    /**
     * RSA解密
     *
     * @param data 待解密数据
     * @param key 密钥
     * @return
     */
    public static String decrypt(String data, Key key) throws Exception {
        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        cipher.init(Cipher.DECRYPT_MODE, key);
        byte[] dataBytes = Base64.decode(data.getBytes(), Base64.URL_SAFE);
        int inputLen = dataBytes.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offset = 0;
        byte[] cache;
        int i = 0;
        // 对数据分段解密
        while (inputLen - offset > 0) {
            if (inputLen - offset > MAX_DECRYPT_BLOCK) {
                cache = cipher.doFinal(dataBytes, offset, MAX_DECRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(dataBytes, offset, inputLen - offset);
            }
            out.write(cache, 0, cache.length);
            i++;
            offset = i * MAX_DECRYPT_BLOCK;
        }
        byte[] decryptedData = out.toByteArray();
        out.close();
        // 解密后的内容
        return new String(decryptedData, "UTF-8");
    }
    /**
     * 签名
     *
     * @param data 待签名数据
     * @param privateKey 私钥
     * @return 签名
     */
    public static String sign(String data, PrivateKey privateKey) throws Exception {
        byte[] keyBytes = privateKey.getEncoded();
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_RSA);
        PrivateKey key = keyFactory.generatePrivate(keySpec);
        Signature signature = Signature.getInstance("MD5withRSA");
        signature.initSign(key);
        signature.update(data.getBytes());
        return  Base64.encodeToString(signature.sign(),Base64.DEFAULT);
    }
    /**
     * 验签
     *
     * @param srcData 原始字符串
     * @param publicKey 公钥
     * @param sign 签名
     * @return 是否验签通过
     */
    public static boolean verify(String srcData, PublicKey publicKey, String sign) throws Exception {
        byte[] keyBytes = publicKey.getEncoded();
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_RSA);
        PublicKey key = keyFactory.generatePublic(keySpec);
        Signature signature = Signature.getInstance("MD5withRSA");
        signature.initVerify(key);
        signature.update(srcData.getBytes());
        return signature.verify(Base64.decode(sign.getBytes(),Base64.DEFAULT));
    }
}
libmvi/src/main/java/com/runt/open/mvi/retrofit/utils/RetrofitUtils.java
@@ -2,14 +2,18 @@
import com.runt.open.mvi.BuildConfig;
import com.runt.open.mvi.retrofit.Interceptor.AddHeadersInterceptor;
import com.runt.open.mvi.retrofit.Interceptor.LogEncryptInterceptor;
import com.runt.open.mvi.retrofit.Interceptor.OpenInterceptor;
import com.runt.open.mvi.retrofit.Interceptor.EncryptInterceptor;
import com.runt.open.mvi.retrofit.Interceptor.HttpLoggingInterceptor;
import com.runt.open.mvi.retrofit.converter.DecryptGsonConverterFactory;
import com.runt.open.mvi.retrofit.converter.GsonConverterFactory;
import com.runt.open.mvi.retrofit.net.NetWorkListener;
import java.util.Collections;
import java.util.concurrent.TimeUnit;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Protocol;
import retrofit2.Retrofit;
@@ -23,13 +27,11 @@
public class RetrofitUtils {
    static RetrofitUtils instance;
    Retrofit retrofit/*log输出,驼峰转换*/,unHumpRetrofit/*log输出,不强制驼峰转换*/,
            unLogRetrofit/*log不输出,驼峰转换*/,unLogHumpRetorfit/*log不输出,不强制驼峰转换*/;
    Retrofit retrofit/*log输出*/,humpRetrofit/*log输出,强制驼峰转换*/,
            unLogRetrofit/*log不输出*/,unLogHumpRetrofit/*log不输出,强制驼峰转换*/,
            encryptRetrofit/*加密log输出*/,humpEncryptRetrofit/*加密log输出,强制驼峰转换*/,
            unLogEncryptRetrofit/*加密log不输出*/,unLogHumpEncryptRetrofit/*加密log不输出,强制驼峰转换*/;
    OkHttpClient.Builder builder = new OkHttpClient.Builder()
            .addInterceptor(new AddHeadersInterceptor());
    OkHttpClient.Builder logBuilder = new OkHttpClient.Builder()
            .addInterceptor(new HttpLoggingInterceptor());//log打印拦截器
    public static RetrofitUtils getInstance() {
        if(instance == null){
@@ -47,38 +49,22 @@
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .build();
    }
    public <T> T getTempRetrofit(Class<T> clas,String url) {
        Interceptor interceptor = BuildConfig.DEBUG ? new HttpLoggingInterceptor() : new OpenInterceptor();
        return getRetrofit(getOkHttpClient(new OkHttpClient.Builder().addInterceptor(interceptor)),
                new Retrofit.Builder().addConverterFactory(GsonConverterFactory.create(true)),url).create(clas);
    }
    /**
     * log输出,gson驼峰转换
     * log输出
     * @return
     */
    public <T> T getRetrofit(Class<T> clas) {
        if(retrofit == null){
            retrofit = getRetrofit(getOkHttpClient(logBuilder),
                    new Retrofit.Builder().addConverterFactory(GsonConverterFactory.create(true))) ;
        }
        if(!BuildConfig.DEBUG){//正式版 不打印log
            return getUnLogRetrofit(clas);
        }
        return retrofit.create(clas);
    }
    public <T> T getTempRetrofit(Class<T> clas,String url) {
        return getRetrofit(getOkHttpClient(new OkHttpClient.Builder().addInterceptor(new HttpLoggingInterceptor(BuildConfig.DEBUG))),
                new Retrofit.Builder().addConverterFactory(GsonConverterFactory.create(true)),url).create(clas);
    }
    /**
     * log输出,gson不转换驼峰
     * @return
     */
    public <T> T getUnHumpRetrofit(Class<T> clas) {
        if(unHumpRetrofit == null){
            unHumpRetrofit = getRetrofit(getOkHttpClient(logBuilder),
                    new Retrofit.Builder().addConverterFactory(GsonConverterFactory.create())) ;
        }
        if(!BuildConfig.DEBUG){//正式版 不打印log
            return getUnLogHumpRetorfit(clas);
        }
        return unHumpRetrofit.create(clas);
        return getRetrofit(clas,false,false,true);
    }
    /**
@@ -86,23 +72,128 @@
     * @return
     */
    public <T> T  getUnLogRetrofit(Class<T> clas) {
        if(unLogRetrofit == null){
            unLogRetrofit = getRetrofit(getOkHttpClient(builder),
                    new Retrofit.Builder().addConverterFactory(GsonConverterFactory.create(true))) ;
        }
        return unLogRetrofit.create(clas);
        return getRetrofit(clas,false,false,false);
    }
    /**
     * log不输出,gson不转换驼峰
     * log输出,gson转换驼峰
     * @return
     */
    public <T> T getHumpRetrofit(Class<T> clas) {
        if(!BuildConfig.DEBUG){//正式版 不打印log
            return getUnLogHumpRetorfit(clas);
        }
        return getRetrofit(clas,true,false,true);
    }
    /**
     * log不输出,gson转换驼峰
     * @return
     */
    public <T> T getUnLogHumpRetorfit(Class<T> clas) {
        if(unLogHumpRetorfit == null){
            unLogHumpRetorfit = getRetrofit(getOkHttpClient(builder),
                    new Retrofit.Builder().addConverterFactory(GsonConverterFactory.create())) ;
        return getRetrofit(clas,true,false,false);
        }
        return unLogHumpRetorfit.create(clas);
    /**
     * 加密log输出
     * @return
     */
    public <T> T getEncrptRetrofit(Class<T> clas) {
        if(!BuildConfig.DEBUG){//正式版 不打印log
            return getUnLogEncryptRetrofit(clas);
        }
        return getRetrofit(clas,false,true,true);
    }
    /**
     * 加密log不输出
     * @return
     */
    public <T> T  getUnLogEncryptRetrofit(Class<T> clas) {
        return getRetrofit(clas,false,true,false);
    }
    /**
     * 加密log输出 gson转换驼峰
     * @return
     */
    public <T> T  getHumpEncryptRetrofit(Class<T> clas) {
        if(!BuildConfig.DEBUG){//正式版 不打印log
            return getUnLogHumpEncryptRetrofit(clas);
        }
        return getRetrofit(clas,true,true,true);
    }
    /**
     * 加密log不输出 gson转换驼峰
     * @return
     */
    public <T> T  getUnLogHumpEncryptRetrofit(Class<T> clas) {
        return getRetrofit(clas,true,true,false);
    }
    private <T> T getRetrofit(Class<T> clzz,boolean transHump,boolean encrypt,boolean log){
        Retrofit temp = null;
        if(transHump && encrypt && log){
            if(humpEncryptRetrofit == null){
                humpEncryptRetrofit = initRetrofit(transHump,encrypt,log);
            }
            temp = humpEncryptRetrofit;
        }else if(transHump && encrypt && !log ){
            if(unLogHumpEncryptRetrofit == null){
                unLogHumpEncryptRetrofit = initRetrofit(transHump,encrypt,log);
            }
            temp = unLogHumpEncryptRetrofit;
        }else if(transHump && !encrypt && !log ){
            if(unLogHumpRetrofit == null){
                unLogHumpRetrofit = initRetrofit(transHump,encrypt,log);
            }
            temp = unLogHumpRetrofit;
        }else if(!transHump && !encrypt && !log ){
            if(unLogRetrofit == null){
                unLogRetrofit = initRetrofit(transHump,encrypt,log);
            }
            temp = unLogRetrofit;
        }else if(!transHump && !encrypt && log ){
            if(retrofit == null){
                retrofit = initRetrofit(transHump,encrypt,log);
            }
            temp = retrofit;
        }else if(!transHump && encrypt && log ){
            if(encryptRetrofit == null){
                encryptRetrofit = initRetrofit(transHump,encrypt,log);
            }
            temp = encryptRetrofit;
        }else if(!transHump && encrypt && !log ){
            if(unLogEncryptRetrofit == null){
                unLogEncryptRetrofit = initRetrofit(transHump,encrypt,log);
            }
            temp = unLogEncryptRetrofit;
        }else if(transHump && !encrypt && log ){
            if(humpRetrofit == null){
                humpRetrofit = initRetrofit(transHump,encrypt,log);
            }
            temp = humpRetrofit;
        }
        return temp.create(clzz);
    }
    private Retrofit initRetrofit(boolean transHump,boolean encrypt,boolean log){
        Retrofit.Builder builder = new Retrofit.Builder();
        builder.addConverterFactory(encrypt ? DecryptGsonConverterFactory.create(transHump) : GsonConverterFactory.create(transHump));
        OkHttpClient.Builder httpBuilder = new OkHttpClient.Builder();
        if(log && encrypt){
            httpBuilder.addInterceptor(new LogEncryptInterceptor());//log打印加密拦截器
        } else if (log && !encrypt) {
            httpBuilder.addInterceptor(new HttpLoggingInterceptor());//log打印拦截器
        } else if (!log && encrypt) {
            httpBuilder.addInterceptor(new EncryptInterceptor());//加密拦截器
        } else if (!log && !encrypt) {
            httpBuilder.addInterceptor(new OpenInterceptor());//拦截器
        }
        OkHttpClient httpClient = getOkHttpClient(httpBuilder);
        return getRetrofit(httpClient,builder);
    }
    private OkHttpClient getOkHttpClient(OkHttpClient.Builder builder){
libmvi/src/main/java/com/runt/open/mvi/utils/DeviceIdUtils.java
@@ -51,7 +51,7 @@
            TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
            return tm.getDeviceId();
        } catch (Exception e) {
            //e.printStackTrace();
            e.printStackTrace();
        }
        return "";
    }
libmvi/src/main/java/com/runt/open/mvi/utils/DeviceUtil.java
@@ -1,21 +1,16 @@
package com.runt.open.mvi.utils;
import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.Point;
import android.os.Build;
import android.provider.Settings;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Display;
import android.view.WindowManager;
import androidx.core.app.ActivityCompat;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
@@ -43,8 +38,7 @@
        sb.append("设备厂商:");//设备型号
        sb.append(getDeviceBrand() + "\t");//设备型号
        sb.append("程序版本号:" + getAppVersionCode(context) + " " + getAppVersionName(context) + "\t");//程序版本号
        sb.append("设备唯一标识符:" + getSerialNumber(context));
        sb.append("\n设备imei:" + getIMEI(context));
        sb.append("设备唯一标识符:" + DeviceIdUtils.getDeviceId(context));
        String str = sb.toString() + " \n";
        str += getDisplayInfomation(context) + " \n";
        str += getDensity(context) + " \n";
@@ -291,50 +285,6 @@
        }
        return 0;
    }
    public static String getSerialNumber(Context context) {
        String serial = "";
        try {
            if (Build.VERSION.SDK_INT >= 28) {//9.0+
                if (ActivityCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
                    Log.i(TAG, "getMEID meid: READ_PHONE_STATE" );
                    ActivityCompat.requestPermissions((Activity) context, new String[]{Manifest.permission.READ_PHONE_STATE}, 1567);
                } else {
                    serial = Build.getSerial();
                }
            } else if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N) {//8.0+
                serial = Build.SERIAL;
            } else {//8.0-
                Class<?> c = Class.forName("android.os.SystemProperties");
                Method get = c.getMethod("get", String.class);
                serial = (String) get.invoke(c, "ro.serialno");
            }
        } catch (Exception e) {
            Log.e("e", "读取设备序列号异常:" + e.toString());
        }
        return serial;
    }
    public static  String getIMEI(Context context) {
        String deviceId = "";
        TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
        if (null != tm) {
            if (ActivityCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
                Log.i(TAG, "getMEID meid: READ_PHONE_STATE" );
                ActivityCompat.requestPermissions((Activity) context, new String[]{Manifest.permission.READ_PHONE_STATE}, 1567);
            } else {
                if (tm.getDeviceId() != null) {
                    deviceId = tm.getDeviceId();
                } else {
                    deviceId = Settings.Secure.getString(context.getApplicationContext().getContentResolver(), Settings.Secure.ANDROID_ID);
                }
            }
            Log.d("deviceId--->", deviceId);
        }
        return "";
    }
    public static  String getMEID() {
libmvi/src/main/java/com/runt/open/mvi/views/PublicViews.kt
@@ -1,5 +1,6 @@
package com.runt.open.mvi.views
import android.util.Log
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
@@ -72,10 +73,13 @@
fun MessageDialog(message : MessageState){
    if(message.isVisible){
        Dialog(onDismissRequest = {
            if(message.cancelDissmiss){
            //系统响应
            Log.i("PublicViews" , "MessageDialog: onDismiss")
            if(message.touchOutside){
                message.setDismiss.invoke()
            }
                message.onCancelRequest.invoke()
            message.onDismissRequest.invoke()
            }
        }) {
            Card(
                modifier = Modifier
@@ -104,10 +108,11 @@
                        if(!message.cancelText.equals("")){
                            Spacer(modifier = Modifier.weight(1f))
                            Button(onClick = {
                                message.onCancelRequest.invoke()
                                if(message.cancelDissmiss){
                                    message.setDismiss.invoke()
                                    message.onDismissRequest.invoke()
                                }
                                message.onCancelRequest.invoke()
                            },
                                colors = ButtonDefaults.buttonColors(
                                    containerColor = Color.Gray,      // 背景色
@@ -119,10 +124,11 @@
                        }
                        Spacer(modifier = Modifier.weight(1f))
                        Button(onClick = {
                            message.onConfirmRequest.invoke()
                            if(message.confirmDissmiss){
                                message.setDismiss.invoke()
                                message.onDismissRequest.invoke()
                            }
                            message.onConfirmRequest.invoke()
                        }) {
                            Text(text = message.confirmText)
                        }