1 files deleted
7 files added
8 files modified
| | |
| | | |
| | | 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") |
| | | } |
| | | } |
| | |
| | | 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; |
| | | |
| | | |
| | | /** |
| | |
| | | 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() { |
New file |
| | |
| | | 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())); |
| | | } |
| | | |
| | | } |
| | |
| | | |
| | | 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; |
| | |
| | | * @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()); |
| | | }*/ |
| | |
| | | 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) { |
| | |
| | | new Thread(){ |
| | | @Override |
| | | public void run() { |
| | | if(printLog) { |
| | | HttpPrintUtils.getInstance().printLog(logArrays, true);//线程安全方法,需在新线程执行,避免阻塞当前线程,导致程序无响应 |
| | | } |
| | | } |
| | | }.start(); |
| | | } catch (JSONException e) { |
| | |
| | | new Thread(){ |
| | | @Override |
| | | public void run() { |
| | | if(printLog) { |
| | | HttpPrintUtils.getInstance().printLog(logArrays, false);//线程安全方法,需在新线程执行,避免阻塞当前线程,导致程序无响应 |
| | | } |
| | | } |
| | | }.start(); |
| | | throw e;//抛出异常,用于请求接收信息 |
| | |
| | | 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")+ ' ' ; |
| | |
| | | * @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(); |
New file |
| | |
| | | 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)); |
| | | } |
| | | } |
New file |
| | |
| | | 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(); |
| | | } |
| | | } |
| | | } |
New file |
| | |
| | | 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); |
| | | } |
| | | } |
New file |
| | |
| | | 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; |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | 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()); |
| | | } |
| | | } |
| | |
| | | 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. |
| | | */ |
New file |
| | |
| | | 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)); |
| | | } |
| | | |
| | | } |
| | |
| | | |
| | | |
| | | 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; |
| | |
| | | |
| | | 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){ |
| | |
| | | .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); |
| | | } |
| | | |
| | | /** |
| | |
| | | * @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){ |
| | |
| | | TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); |
| | | return tm.getDeviceId(); |
| | | } catch (Exception e) { |
| | | //e.printStackTrace(); |
| | | e.printStackTrace(); |
| | | } |
| | | return ""; |
| | | } |
| | |
| | | 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; |
| | |
| | | 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"; |
| | |
| | | } |
| | | |
| | | 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() { |
| | |
| | | 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 |
| | |
| | | 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 |
| | |
| | | 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, // 背景色 |
| | |
| | | } |
| | | 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) |
| | | } |