19 files added
4 files modified
| | |
| | | } |
| | | |
| | | buildTypes { |
| | | debug{ |
| | | minifyEnabled false |
| | | buildConfigField 'String','HOST_IP_ADDR','"http://192.168.100.82:8080/"' |
| | | buildConfigField 'String','ENVIRONMENT','"release"' |
| | | resValue "string", "app_name", "趣为帮扶测试" |
| | | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' |
| | | } |
| | | release { |
| | | minifyEnabled false |
| | | buildConfigField 'String','HOST_IP_ADDR','"http://192.168.100.82:8080/"' |
| | | buildConfigField 'String','ENVIRONMENT','"release"' |
| | | resValue "string", "app_name", "趣为帮扶" |
| | | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' |
| | | } |
| | | } |
| | |
| | | implementation 'com.github.d-max:spots-dialog:1.1@aar'//loading view |
| | | implementation 'com.google.code.gson:gson:2.8.6' |
| | | implementation 'com.ansen.http:okhttpencapsulation:1.0.1'//版本更新下载 |
| | | implementation 'com.squareup.okhttp3:okhttp:3.12.1' |
| | | implementation 'com.squareup.retrofit2:retrofit:2.3.0' |
| | | implementation 'com.squareup.okhttp3:okhttp:4.9.0' |
| | | implementation 'com.squareup.retrofit2:retrofit:2.9.0' |
| | | //RXjava和retrofit结合 |
| | | implementation 'com.squareup.retrofit2:adapter-rxjava2:2.2.0' |
| | | implementation 'com.squareup.retrofit2:adapter-rxjava2:2.9.0' |
| | | implementation 'com.permissionx.guolindev:permissionx:1.2.2' //权限依赖让你推广你就发群里?没有别的群了? |
| | | implementation 'com.github.bumptech.glide:glide:4.12.0' |
| | | annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0' |
| | |
| | | tools:ignore="ProtectedPermissions" |
| | | package="com.duqing.missions" > |
| | | |
| | | |
| | | <uses-permission android:name="android.permission.CALL_PHONE" /> |
| | | <uses-permission android:name="android.permission.INTERNET" /> |
| | | <uses-permission android:name="android.permission.GET_TASKS" /> |
| | | <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> |
| | | <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> |
| | | <uses-permission android:name="android.permission.READ_PHONE_STATE" /> |
| | | <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> |
| | | <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> |
| | | <uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" /> |
| | | <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> |
| | | <!--写入SD卡的权限:如果你希望保存相机拍照后的照片--> |
| | | <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> |
| | | <!--读取SD卡的权限:打开相册选取图片所必须的权限--> |
| | | <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> |
| | | <!--android Q 安装权限--> |
| | | <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" /> |
| | | <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" |
| | | tools:ignore="ProtectedPermissions" /> |
| | | <uses-permission android:name="android.permission.WAKE_LOCK" /> |
| | | <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" /> |
| | | <application |
| | | android:name=".MyApplication" |
| | |
| | | android:label="@string/app_name" |
| | | android:roundIcon="@mipmap/ic_launcher_round" |
| | | android:supportsRtl="true" |
| | | android:networkSecurityConfig="@xml/network_security_config" |
| | | android:theme="@style/Theme.Missions" > |
| | | <activity |
| | | android:name=".ui.main.MainActivity" |
New file |
| | |
| | | package com.duqing.missions.base.model; |
| | | |
| | | import androidx.lifecycle.MutableLiveData; |
| | | import androidx.lifecycle.ViewModel; |
| | | |
| | | /** |
| | | * Created by Administrator on 2021/11/5 0005. |
| | | */ |
| | | public class ItemViewModel<T> extends ViewModel { |
| | | |
| | | MutableLiveData<T> liveData = new MutableLiveData<>(); |
| | | |
| | | public MutableLiveData<T> getLiveData() { |
| | | return liveData; |
| | | } |
| | | } |
New file |
| | |
| | | package com.duqing.missions.retrofit; |
| | | |
| | | import android.os.Handler; |
| | | import android.os.Looper; |
| | | |
| | | import androidx.annotation.NonNull; |
| | | |
| | | import java.util.concurrent.Executor; |
| | | |
| | | import io.reactivex.Scheduler; |
| | | import io.reactivex.schedulers.Schedulers; |
| | | |
| | | /** |
| | | * Created by Administrator on 2021/11/8 0008. |
| | | */ |
| | | public class AndroidScheduler implements Executor { |
| | | private static AndroidScheduler instance; |
| | | |
| | | private final Scheduler mMainScheduler; |
| | | private final Handler mHandler; |
| | | |
| | | private AndroidScheduler() { |
| | | mHandler = new Handler(Looper.myLooper()); |
| | | mMainScheduler = Schedulers.from(this); |
| | | } |
| | | |
| | | public static synchronized Scheduler mainThread() { |
| | | if (instance == null) { |
| | | instance = new AndroidScheduler(); |
| | | } |
| | | return instance.mMainScheduler; |
| | | } |
| | | |
| | | @Override |
| | | public void execute(@NonNull Runnable command) { |
| | | mHandler.post(command); |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.duqing.missions.retrofit.Interceptor; |
| | | |
| | | |
| | | import com.duqing.missions.retrofit.utils.RSAUtils; |
| | | |
| | | 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 加密拦截器 |
| | | * |
| | | * @purpose Created by Runt (qingingrunt2010@qq.com) on 2021-10-8. |
| | | */ |
| | | |
| | | public class EncryptInterceptor implements Interceptor { |
| | | |
| | | protected static final Charset UTF8 = Charset.forName("UTF-8"); |
| | | private final String ENCRYPT = "encrypt"; |
| | | |
| | | @Override |
| | | public Response intercept(Chain chain) throws IOException { |
| | | return chain.proceed(encryptRequest(chain.request())); |
| | | } |
| | | |
| | | |
| | | //加密 |
| | | protected Request encryptRequest(Request request) throws IOException { |
| | | Headers headers = request.headers(); |
| | | RequestBody requestBody = request.body(); |
| | | Request.Builder builder = request.newBuilder(); |
| | | 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 |
| | | */ |
| | | public static String encryptParam(Map<String, Object> params){ |
| | | return encryptJson(new JSONObject(params).toString()); |
| | | } |
| | | public static 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.duqing.missions.retrofit.Interceptor; |
| | | |
| | | import android.util.Log; |
| | | |
| | | import com.duqing.missions.retrofit.NetWorkCost; |
| | | import com.duqing.missions.retrofit.NetWorkListenear; |
| | | import com.duqing.missions.retrofit.utils.HttpPrintUtils; |
| | | import com.duqing.missions.util.GsonUtils; |
| | | |
| | | import org.json.JSONObject; |
| | | |
| | | import java.io.EOFException; |
| | | import java.io.IOException; |
| | | import java.net.URLDecoder; |
| | | import java.nio.charset.Charset; |
| | | import java.util.ArrayList; |
| | | import java.util.HashMap; |
| | | |
| | | import okhttp3.FormBody; |
| | | import okhttp3.Headers; |
| | | import okhttp3.MediaType; |
| | | import okhttp3.MultipartBody; |
| | | import okhttp3.Request; |
| | | import okhttp3.RequestBody; |
| | | import okhttp3.Response; |
| | | import okhttp3.ResponseBody; |
| | | import okhttp3.internal.http.HttpHeaders; |
| | | import okio.Buffer; |
| | | import okio.BufferedSource; |
| | | |
| | | /** |
| | | * My father is Object, ites purpose of log打印 |
| | | * |
| | | * @purpose Created by Runt (qingingrunt2010@qq.com) on 2020-10-21. |
| | | */ |
| | | |
| | | public class HttpLoggingInterceptor extends EncryptInterceptor { |
| | | |
| | | final String TAG = "HttpLogging"; |
| | | |
| | | public HttpLoggingInterceptor() { |
| | | } |
| | | |
| | | |
| | | @Override |
| | | public Response intercept(Chain chain) throws IOException { |
| | | |
| | | Request request = chain.request(); |
| | | int hashCode = request.hashCode(); |
| | | ArrayList<String> logArrays = getRequestLog(request); |
| | | int position = logArrays.size() +2; |
| | | Response response; |
| | | try { |
| | | request = encryptRequest(request);//加密 |
| | | response = chain.proceed(request); |
| | | logArrays.addAll(getResponseLog(response)); |
| | | Log.d(TAG,"hashcode:"+hashCode); |
| | | NetWorkCost netWorkCost = NetWorkListenear.workCostMap.get(hashCode); |
| | | String cost = String.format("dns:%s,secure:%s,connect:%s,requestH:%s,requestB:%s,responseH:%s,responseB:%s", convertTimes(netWorkCost.dns) ,convertTimes(netWorkCost.secure) , convertTimes(netWorkCost.connect),convertTimes(netWorkCost.requestHeader),convertTimes(netWorkCost.requestBody) ,convertTimes(netWorkCost.resposeHeader),convertTimes(netWorkCost.resposeBody) ); |
| | | logArrays.add(position,"<-- costtimes : "+convertTimes(netWorkCost.total)+" (" +cost + ')'); |
| | | NetWorkListenear.workCostMap.remove(hashCode); |
| | | new Thread(){ |
| | | @Override |
| | | public void run() { |
| | | HttpPrintUtils.getInstance().printLog(logArrays, true);//线程安全方法,需在新线程执行,避免阻塞当前线程,导致程序无响应 |
| | | } |
| | | }.start(); |
| | | } catch (Exception e) { |
| | | logArrays.add("<-- response url:" + URLDecoder.decode(request.url().toString(), "UTF-8")); |
| | | NetWorkCost netWorkCost = NetWorkListenear.workCostMap.get(hashCode); |
| | | String cost = String.format("dns:%s,secure:%s,connect:%s,requestH:%s,requestB:%s,responseH:%s,responseB:%s", convertTimes(netWorkCost.dns) ,convertTimes(netWorkCost.secure) , convertTimes(netWorkCost.connect),convertTimes(netWorkCost.requestHeader),convertTimes(netWorkCost.requestBody) ,convertTimes(netWorkCost.resposeHeader),convertTimes(netWorkCost.resposeBody) ); |
| | | logArrays.add("<-- costtimes : "+convertTimes(netWorkCost.total)+" (" +cost + ')'); |
| | | logArrays.add("<-- response failed " + e.getLocalizedMessage()); |
| | | logArrays.add("<-- " + e.toString()); |
| | | new Thread(){ |
| | | @Override |
| | | public void run() { |
| | | HttpPrintUtils.getInstance().printLog(logArrays, false);//线程安全方法,需在新线程执行,避免阻塞当前线程,导致程序无响应 |
| | | } |
| | | }.start(); |
| | | throw e;//抛出异常,用于请求接收信息 |
| | | } |
| | | return response; |
| | | } |
| | | |
| | | private ArrayList<String> getRequestLog(Request request) throws IOException { |
| | | RequestBody requestBody = request.body(); |
| | | ArrayList<String> logArrays = new ArrayList<>(); |
| | | String requestStartMessage = "--> " + request.method() + ' ' + URLDecoder.decode(request.url().toString() ,"UTF-8")+ ' ' ; |
| | | if ( requestBody != null) { |
| | | requestStartMessage += " (" + requestBody.contentLength() + "-byte body)"; |
| | | } |
| | | logArrays.add(requestStartMessage); |
| | | Headers headers = request.headers(); |
| | | logArrays.add("---------->REQUEST HEADER<----------"); |
| | | for (int i = 0, count = headers.size(); i < count; i++) { |
| | | logArrays.add(headers.name(i) + ": " + headers.value(i)); |
| | | } |
| | | if (requestBody == null) { |
| | | logArrays.add("--> END " + request.method()); |
| | | } else if (bodyEncoded(request.headers())) { |
| | | logArrays.add("--> END " + request.method() + " (encoded body omitted)"); |
| | | } else { |
| | | |
| | | Charset charset = UTF8; |
| | | MediaType contentType = requestBody.contentType(); |
| | | if (contentType != null) { |
| | | charset = contentType.charset(UTF8); |
| | | } |
| | | HashMap param = new HashMap(); |
| | | if(requestBody instanceof MultipartBody){ |
| | | logArrays.add("---------->REQUEST BODY[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")); |
| | | } |
| | | logArrays.add(GsonUtils.retractJson(new JSONObject(param).toString())); |
| | | }else if(requestBody instanceof FormBody){ |
| | | logArrays.add("---------->REQUEST BODY[FormBody]<----------"); |
| | | FormBody body = (FormBody) requestBody; |
| | | for(int i = 0 ; i < body.size() ; i ++ ){ |
| | | param.put(body.name(i),body.value(i)); |
| | | } |
| | | logArrays.add(GsonUtils.retractJson(new JSONObject(param).toString())); |
| | | }else{ |
| | | Buffer buffer = new Buffer(); |
| | | requestBody.writeTo(buffer); |
| | | logArrays.add("---------->REQUEST BODY<----------"); |
| | | String str = buffer.readString(charset); |
| | | try{ |
| | | logArrays.add(GsonUtils.retractJson(URLDecoder.decode(str, "UTF-8"))); |
| | | }catch (Exception e){ |
| | | logArrays.add(str); |
| | | } |
| | | } |
| | | logArrays.add("--> END " + request.method() + " " + contentType + " ( " |
| | | + requestBody.contentLength() + "-byte body )"); |
| | | } |
| | | return logArrays; |
| | | |
| | | } |
| | | |
| | | |
| | | private ArrayList<String> getResponseLog(Response response) throws IOException { |
| | | ArrayList<String> logArrays = new ArrayList<>(); |
| | | ResponseBody responseBody = response.body(); |
| | | long contentLength = responseBody.contentLength(); |
| | | String bodySize = contentLength != -1 ? contentLength + "-byte" : "unknown-length"; |
| | | logArrays.add("<-- response code:" + response.code() + " message:" + response.message()+" contentlength:"+bodySize ); |
| | | logArrays.add("<-- response url:"+URLDecoder.decode(response.request().url().toString(),"UTF-8") ); |
| | | |
| | | if ( !HttpHeaders.hasBody(response)) { |
| | | logArrays.add("<-- END HTTP"); |
| | | } else if (bodyEncoded(response.headers())) { |
| | | logArrays.add("<-- END HTTP (encoded body omitted)"); |
| | | } else { |
| | | BufferedSource source = responseBody.source(); |
| | | source.request(Long.MAX_VALUE); // Buffer the entire body. |
| | | Buffer buffer = source.buffer(); |
| | | |
| | | Charset charset = UTF8; |
| | | MediaType contentType = responseBody.contentType(); |
| | | if (contentType != null) { |
| | | charset = contentType.charset(UTF8); |
| | | } |
| | | |
| | | if (isPlaintext(buffer)) { |
| | | logArrays.add("---------->RESPONSE BODY<----------"); |
| | | if (contentLength != 0) { |
| | | logArrays.add(retractJson(buffer.clone().readString(charset))); |
| | | } |
| | | |
| | | logArrays.add("<-- END HTTP (" + buffer.size() + "-byte body)"); |
| | | } |
| | | |
| | | } |
| | | return logArrays; |
| | | } |
| | | |
| | | /** |
| | | * 字符串缩进 |
| | | * @param json |
| | | * @return |
| | | */ |
| | | private String retractJson(String json){ |
| | | int level = 0 ; |
| | | StringBuffer jsonForMatStr = new StringBuffer(); |
| | | for(int index=0;index<json.length();index++)//将字符串中的字符逐个按行输出 |
| | | { |
| | | //获取s中的每个字符 |
| | | char c = json.charAt(index); |
| | | // System.out.println(s.charAt(index)); |
| | | |
| | | //level大于0并且jsonForMatStr中的最后一个字符为\n,jsonForMatStr加入\t |
| | | if (level > 0 && '\n' == jsonForMatStr.charAt(jsonForMatStr.length() - 1)) { |
| | | jsonForMatStr.append(getLevelStr(level)); |
| | | // System.out.println("123"+jsonForMatStr); |
| | | } |
| | | //遇到"{"和"["要增加空格和换行,遇到"}"和"]"要减少空格,以对应,遇到","要换行 |
| | | switch (c) { |
| | | case '{': |
| | | case '[': |
| | | jsonForMatStr.append(c + "\n"); |
| | | level++; |
| | | break; |
| | | case ',': |
| | | jsonForMatStr.append(c + "\n"); |
| | | break; |
| | | case '}': |
| | | case ']': |
| | | jsonForMatStr.append("\n"); |
| | | level--; |
| | | jsonForMatStr.append(getLevelStr(level)); |
| | | jsonForMatStr.append(c); |
| | | break; |
| | | default: |
| | | jsonForMatStr.append(c); |
| | | break; |
| | | } |
| | | } |
| | | return jsonForMatStr.toString(); |
| | | } |
| | | |
| | | private String getLevelStr(int level) { |
| | | StringBuffer levelStr = new StringBuffer(); |
| | | for (int levelI = 0; levelI < level; levelI++) { |
| | | levelStr.append("\t");//\t或空格 |
| | | } |
| | | return levelStr.toString(); |
| | | } |
| | | |
| | | /** |
| | | * Returns true if the body in question probably contains human readable text. Uses a small sample |
| | | * of code points to detect unicode control characters commonly used in binary file signatures. |
| | | */ |
| | | static boolean isPlaintext(Buffer buffer) { |
| | | try { |
| | | Buffer prefix = new Buffer(); |
| | | long byteCount = buffer.size() < 64 ? buffer.size() : 64; |
| | | buffer.copyTo(prefix, 0, byteCount); |
| | | for (int i = 0; i < 16; i++) { |
| | | if (prefix.exhausted()) { |
| | | break; |
| | | } |
| | | int codePoint = prefix.readUtf8CodePoint(); |
| | | if (Character.isISOControl(codePoint) && !Character.isWhitespace(codePoint)) { |
| | | return false; |
| | | } |
| | | } |
| | | return true; |
| | | } catch (EOFException e) { |
| | | return false; // Truncated UTF-8 sequence. |
| | | } |
| | | } |
| | | |
| | | private boolean bodyEncoded(Headers headers) { |
| | | String contentEncoding = headers.get("Content-Encoding"); |
| | | return contentEncoding != null && !contentEncoding.equalsIgnoreCase("identity"); |
| | | } |
| | | |
| | | private String convertTimes(long ms){ |
| | | String m = null,s=null; |
| | | final int utilS = 1000; |
| | | final int utilM = utilS*60; |
| | | if(ms/utilM>0){ |
| | | m = ms/utilM+"m"; |
| | | } |
| | | if(ms%utilM/utilS>0){ |
| | | s = ms%utilM/utilS+"s"; |
| | | } |
| | | return (m!=null?m:"")+(s!=null?s:"")+ms%utilS+"ms"; |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.duqing.missions.retrofit; |
| | | |
| | | |
| | | /** |
| | | * My father is Object, ites purpose of 网络消耗 |
| | | * |
| | | * @purpose Created by Runt (qingingrunt2010@qq.com) on 2021-3-12. |
| | | */ |
| | | |
| | | public class NetWorkCost { |
| | | |
| | | //网络消耗时间 |
| | | public long dns,connect,total,secure,requestHeader,requestBody,resposeHeader,resposeBody; |
| | | } |
New file |
| | |
| | | package com.duqing.missions.retrofit; |
| | | |
| | | import androidx.annotation.Nullable; |
| | | |
| | | import org.jetbrains.annotations.NotNull; |
| | | |
| | | import java.io.IOException; |
| | | import java.net.InetAddress; |
| | | import java.net.InetSocketAddress; |
| | | import java.net.Proxy; |
| | | import java.nio.charset.Charset; |
| | | import java.util.Date; |
| | | import java.util.HashMap; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | |
| | | import okhttp3.Call; |
| | | import okhttp3.EventListener; |
| | | import okhttp3.Handshake; |
| | | import okhttp3.Protocol; |
| | | import okhttp3.Request; |
| | | import okhttp3.Response; |
| | | |
| | | /** |
| | | * My father is Object, ites purpose of 接口请求耗时监听 |
| | | * |
| | | * @purpose Created by Runt (qingingrunt2010@qq.com) on 2021-7-9. |
| | | */ |
| | | |
| | | public class NetWorkListenear extends EventListener { |
| | | |
| | | private static final String TAG = "NetworkEventListener"; |
| | | final Charset UTF8 = Charset.forName("UTF-8"); |
| | | public static Map<Integer, NetWorkCost> workCostMap = new HashMap<>(); |
| | | |
| | | public static Factory get(){ |
| | | Factory factory = new Factory() { |
| | | @NotNull |
| | | @Override |
| | | public EventListener create(@NotNull Call call) { |
| | | return new NetWorkListenear(); |
| | | } |
| | | }; |
| | | return factory; |
| | | } |
| | | |
| | | @Override |
| | | public void callStart(@NotNull Call call) { |
| | | super.callStart(call); |
| | | //mRequestId = mNextRequestId.getAndIncrement() + ""; |
| | | //getAndAdd,在多线程下使用cas保证原子性 |
| | | NetWorkCost netWorkCost = new NetWorkCost(); |
| | | netWorkCost.total = new Date().getTime(); |
| | | workCostMap.put(call.request().hashCode(),netWorkCost); |
| | | } |
| | | |
| | | @Override |
| | | public void dnsStart(@NotNull Call call, @NotNull String domainName) { |
| | | super.dnsStart(call, domainName); |
| | | //Log.d(TAG, "dnsStart"); |
| | | workCostMap.get(call.request().hashCode()).dns = new Date().getTime(); |
| | | } |
| | | |
| | | @Override |
| | | public void dnsEnd(@NotNull Call call, @NotNull String domainName, @NotNull List<InetAddress> inetAddressList) { |
| | | super.dnsEnd(call, domainName, inetAddressList); |
| | | //Log.d(TAG, "dnsEnd"); |
| | | workCostMap.get(call.request().hashCode()).dns = new Date().getTime() - workCostMap.get(call.request().hashCode()).dns; |
| | | } |
| | | |
| | | @Override |
| | | public void connectStart(@NotNull Call call, @NotNull InetSocketAddress inetSocketAddress, @NotNull Proxy proxy) { |
| | | super.connectStart(call, inetSocketAddress, proxy); |
| | | //Log.d(TAG, "connectStart"); |
| | | workCostMap.get(call.request().hashCode()).connect = new Date().getTime(); |
| | | } |
| | | |
| | | @Override |
| | | public void secureConnectStart(@NotNull Call call) { |
| | | super.secureConnectStart(call); |
| | | //Log.d(TAG, "secureConnectStart"); |
| | | workCostMap.get(call.request().hashCode()).secure = new Date().getTime(); |
| | | } |
| | | |
| | | @Override |
| | | public void secureConnectEnd(@NotNull Call call, @Nullable Handshake handshake) { |
| | | super.secureConnectEnd(call, handshake); |
| | | //Log.d(TAG, "secureConnectEnd"); |
| | | workCostMap.get(call.request().hashCode()).secure = new Date().getTime() - workCostMap.get(call.request().hashCode()).secure; |
| | | } |
| | | |
| | | @Override |
| | | public void connectEnd(@NotNull Call call, @NotNull InetSocketAddress inetSocketAddress, |
| | | @NotNull Proxy proxy, @Nullable Protocol protocol) { |
| | | super.connectEnd(call, inetSocketAddress, proxy, protocol); |
| | | //Log.d(TAG, "connectEnd"); |
| | | workCostMap.get(call.request().hashCode()).connect = new Date().getTime() - workCostMap.get(call.request().hashCode()).connect; |
| | | } |
| | | |
| | | @Override |
| | | public void connectFailed(@NotNull Call call, @NotNull InetSocketAddress inetSocketAddress, @NotNull Proxy proxy, @Nullable Protocol protocol, @NotNull IOException ioe) { |
| | | super.connectFailed(call, inetSocketAddress, proxy, protocol, ioe); |
| | | workCostMap.get(call.request().hashCode()).connect = new Date().getTime() - workCostMap.get(call.request().hashCode()).connect; |
| | | workCostMap.get(call.request().hashCode()).total = new Date().getTime() - workCostMap.get(call.request().hashCode()).total; |
| | | //Log.d(TAG, "connectFailed"); |
| | | } |
| | | |
| | | @Override |
| | | public void requestHeadersStart(@NotNull Call call) { |
| | | super.requestHeadersStart(call); |
| | | //Log.d(TAG, "requestHeadersStart"); |
| | | workCostMap.get(call.request().hashCode()).requestHeader = new Date().getTime(); |
| | | } |
| | | |
| | | @Override |
| | | public void requestHeadersEnd(@NotNull Call call, @NotNull Request request) { |
| | | super.requestHeadersEnd(call, request); |
| | | //Log.d(TAG, "requestHeadersEnd"); |
| | | workCostMap.get(call.request().hashCode()).requestHeader = new Date().getTime() - workCostMap.get(call.request().hashCode()).requestHeader; |
| | | } |
| | | |
| | | @Override |
| | | public void requestBodyStart(@NotNull Call call) { |
| | | super.requestBodyStart(call); |
| | | //Log.d(TAG, "requestBodyStart"); |
| | | workCostMap.get(call.request().hashCode()).requestBody = new Date().getTime(); |
| | | } |
| | | |
| | | @Override |
| | | public void requestBodyEnd(@NotNull Call call, long byteCount) { |
| | | super.requestBodyEnd(call, byteCount); |
| | | //Log.d(TAG, "requestBodyEnd"); |
| | | workCostMap.get(call.request().hashCode()).requestBody = new Date().getTime() - workCostMap.get(call.request().hashCode()).requestBody; |
| | | } |
| | | |
| | | @Override |
| | | public void responseHeadersStart(@NotNull Call call) { |
| | | super.responseHeadersStart(call); |
| | | //Log.d(TAG, "responseHeadersStart"); |
| | | workCostMap.get(call.request().hashCode()).resposeHeader = new Date().getTime(); |
| | | } |
| | | |
| | | @Override |
| | | public void responseHeadersEnd(@NotNull Call call, @NotNull Response response) { |
| | | super.responseHeadersEnd(call, response); |
| | | //Log.d(TAG, "responseHeadersEnd"); |
| | | workCostMap.get(call.request().hashCode()).resposeHeader = new Date().getTime() - workCostMap.get(call.request().hashCode()).resposeHeader; |
| | | } |
| | | |
| | | @Override |
| | | public void responseBodyStart(@NotNull Call call) { |
| | | super.responseBodyStart(call); |
| | | //Log.d(TAG, "responseBodyStart"); |
| | | workCostMap.get(call.request().hashCode()).resposeBody = new Date().getTime(); |
| | | } |
| | | |
| | | @Override |
| | | public void responseBodyEnd(@NotNull Call call, long byteCount) { |
| | | super.responseBodyEnd(call, byteCount); |
| | | //Log.d(TAG, "responseBodyEnd"); |
| | | workCostMap.get(call.request().hashCode()).resposeBody = new Date().getTime() - workCostMap.get(call.request().hashCode()).resposeBody; |
| | | workCostMap.get(call.request().hashCode()).total = new Date().getTime() - workCostMap.get(call.request().hashCode()).total; |
| | | } |
| | | |
| | | |
| | | @Override |
| | | public void callFailed(@NotNull Call call, @NotNull IOException ioe) { |
| | | super.callFailed(call, ioe); |
| | | workCostMap.get(call.request().hashCode()).total = new Date().getTime() - workCostMap.get(call.request().hashCode()).total; |
| | | //Log.d(TAG, "callFailed"); |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.duqing.missions.retrofit; |
| | | |
| | | |
| | | import com.duqing.missions.BuildConfig; |
| | | import com.duqing.missions.retrofit.Interceptor.EncryptInterceptor; |
| | | import com.duqing.missions.retrofit.Interceptor.HttpLoggingInterceptor; |
| | | import com.duqing.missions.retrofit.api.CommonApiCenter; |
| | | import com.duqing.missions.retrofit.converter.DecryptGsonConverterFactory; |
| | | |
| | | import java.util.Collections; |
| | | import java.util.concurrent.TimeUnit; |
| | | |
| | | import okhttp3.OkHttpClient; |
| | | import okhttp3.Protocol; |
| | | import retrofit2.Retrofit; |
| | | import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory; |
| | | |
| | | /** |
| | | * My father is Object, ites purpose of |
| | | * |
| | | * @purpose Created by Runt (qingingrunt2010@qq.com) on 2021-7-9. |
| | | */ |
| | | |
| | | public class RetrofitUtils { |
| | | public static String HOST_IP_ADDR; |
| | | static RetrofitUtils instance; |
| | | Retrofit retrofit/*log输出,驼峰转换*/,unHumpRetrofit/*log输出,不强制驼峰转换*/, |
| | | unLogRetrofit/*log不输出,驼峰转换*/,unLogHumpRetorfit/*log不输出,不强制驼峰转换*/; |
| | | CommonApiCenter commonApi;//常用接口 |
| | | |
| | | OkHttpClient.Builder builder = new OkHttpClient.Builder() |
| | | .addInterceptor(new EncryptInterceptor()); |
| | | OkHttpClient.Builder logBuilder = new OkHttpClient.Builder() |
| | | .addInterceptor(new HttpLoggingInterceptor());//log打印拦截器 |
| | | |
| | | public static RetrofitUtils getInstance() { |
| | | if(instance == null){ |
| | | instance = new RetrofitUtils(); |
| | | } |
| | | return instance; |
| | | } |
| | | |
| | | /** |
| | | * log输出,gson驼峰转换 |
| | | * @return |
| | | */ |
| | | public <T> T getRetrofit(Class<T> clas) { |
| | | if(retrofit == null){ |
| | | retrofit = getRetrofit(getOkHttpClient(logBuilder), |
| | | new Retrofit.Builder().addConverterFactory(DecryptGsonConverterFactory.create(true))) ; |
| | | } |
| | | if(!BuildConfig.DEBUG){//正式版 不打印log |
| | | return getUnLogRetrofit(clas); |
| | | } |
| | | return retrofit.create(clas); |
| | | } |
| | | |
| | | /** |
| | | * log输出,gson不转换驼峰 |
| | | * @return |
| | | */ |
| | | public <T> T getUnHumpRetrofit(Class<T> clas) { |
| | | if(unHumpRetrofit == null){ |
| | | unHumpRetrofit = getRetrofit(getOkHttpClient(logBuilder), |
| | | new Retrofit.Builder().addConverterFactory(DecryptGsonConverterFactory.create())) ; |
| | | } |
| | | if(!BuildConfig.DEBUG){//正式版 不打印log |
| | | return getUnLogHumpRetorfit(clas); |
| | | } |
| | | return unHumpRetrofit.create(clas); |
| | | } |
| | | |
| | | /** |
| | | * log不输出,gson驼峰转换 |
| | | * @return |
| | | */ |
| | | public <T> T getUnLogRetrofit(Class<T> clas) { |
| | | if(unLogRetrofit == null){ |
| | | unLogRetrofit = getRetrofit(getOkHttpClient(builder), |
| | | new Retrofit.Builder().addConverterFactory(DecryptGsonConverterFactory.create(true))) ; |
| | | } |
| | | return unLogRetrofit.create(clas); |
| | | } |
| | | |
| | | /** |
| | | * log不输出,gson不转换驼峰 |
| | | * @return |
| | | */ |
| | | public <T> T getUnLogHumpRetorfit(Class<T> clas) { |
| | | if(unLogHumpRetorfit == null){ |
| | | unLogHumpRetorfit = getRetrofit(getOkHttpClient(builder), |
| | | new Retrofit.Builder().addConverterFactory(DecryptGsonConverterFactory.create())) ; |
| | | } |
| | | return unLogHumpRetorfit.create(clas); |
| | | } |
| | | |
| | | private OkHttpClient getOkHttpClient(OkHttpClient.Builder builder){ |
| | | return builder.connectTimeout(10, TimeUnit.SECONDS)//设置连接超时时间 |
| | | .readTimeout(30, TimeUnit.SECONDS)//设置读取超时时间 |
| | | .protocols(Collections.singletonList(Protocol.HTTP_1_1)) |
| | | .eventListenerFactory(NetWorkListenear.get()) |
| | | .build(); |
| | | } |
| | | |
| | | private Retrofit getRetrofit(OkHttpClient client,Retrofit.Builder builder){ |
| | | return builder |
| | | //设置OKHttpClient |
| | | .client(client) |
| | | //设置baseUrl,注意,baseUrl必须后缀"/" |
| | | .baseUrl(BuildConfig.ENVIRONMENT.equals("develop")?HOST_IP_ADDR:BuildConfig.HOST_IP_ADDR) |
| | | .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) |
| | | .build(); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 常用接口 |
| | | * @return |
| | | */ |
| | | public CommonApiCenter getCommonApi(){ |
| | | if(commonApi == null){ |
| | | commonApi = getRetrofit(CommonApiCenter.class); |
| | | } |
| | | return commonApi; |
| | | } |
| | | } |
New file |
| | |
| | | package com.duqing.missions.retrofit.api; |
| | | |
| | | |
| | | import com.duqing.missions.data.ApkUpGradeResult; |
| | | |
| | | import java.util.Map; |
| | | |
| | | import io.reactivex.Observable; |
| | | import retrofit2.http.Field; |
| | | import retrofit2.http.FieldMap; |
| | | import retrofit2.http.FormUrlEncoded; |
| | | import retrofit2.http.GET; |
| | | import retrofit2.http.POST; |
| | | import retrofit2.http.Query; |
| | | import retrofit2.http.QueryMap; |
| | | import retrofit2.http.Url; |
| | | |
| | | /** |
| | | * My father is Object, ites purpose of 常用接口 |
| | | * |
| | | * @purpose Created by Runt (qingingrunt2010@qq.com) on 2021-7-21. |
| | | */ |
| | | |
| | | public interface CommonApiCenter { |
| | | |
| | | @GET |
| | | Observable<Object> getData(@Url String url, @QueryMap Map<String,String> param); |
| | | |
| | | @FormUrlEncoded |
| | | @POST |
| | | Observable<Object> postData(@Url String url, @FieldMap Map<String,String> param); |
| | | |
| | | |
| | | /** |
| | | * 分页数据 |
| | | * @param url 请求地址 |
| | | * @param pageNum 页数 |
| | | * @param pageSize 每页数量 |
| | | * @param param 其他参数 |
| | | * @return |
| | | */ |
| | | @GET |
| | | Observable<Object> getPageData(@Url String url, @Query("pageNum") int pageNum, @Query("pageSize") int pageSize, @QueryMap Map<String,String> param); |
| | | |
| | | /** |
| | | * 分页数据 |
| | | * @param url 请求地址 |
| | | * @param pageNum 页数 |
| | | * @param pageSize 每页数量 |
| | | * @param param 其他参数 |
| | | * @return |
| | | */ |
| | | @FormUrlEncoded |
| | | @POST |
| | | Observable<Object> postPageData(@Url String url, @Field("pageNum") int pageNum, @Field("pageSize") int pageSize, @FieldMap Map<String,String> param); |
| | | |
| | | /** |
| | | * app更新 |
| | | * @return |
| | | */ |
| | | @GET("system/appupgrade/tourist/get/2") |
| | | Observable<ApkUpGradeResult> getAppUpdate(); |
| | | |
| | | |
| | | } |
New file |
| | |
| | | package com.duqing.missions.retrofit.api; |
| | | |
| | | import io.reactivex.Observable; |
| | | import retrofit2.Call; |
| | | import retrofit2.http.Field; |
| | | import retrofit2.http.FormUrlEncoded; |
| | | import retrofit2.http.POST; |
| | | |
| | | /** |
| | | * Created by Administrator on 2021/11/8 0008. |
| | | */ |
| | | public interface LoginApiCenter { |
| | | |
| | | @FormUrlEncoded |
| | | @POST("api/v1/login") |
| | | Observable<Object> login(@Field("paramString") String str); |
| | | |
| | | @FormUrlEncoded |
| | | @POST("api/v1/login") |
| | | Call<Object> loginCall(@Field("paramString") String str); |
| | | } |
New file |
| | |
| | | package com.duqing.missions.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; |
| | | |
| | | /** |
| | | * My father is Object, ites purpose of 解密gson转换 |
| | | * |
| | | * @purpose Created by Runt (qingingrunt2010@qq.com) on 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 GsonRequestBodyConverter<>(gson, adapter); |
| | | } |
| | | } |
New file |
| | |
| | | package com.duqing.missions.retrofit.converter; |
| | | |
| | | import android.util.Log; |
| | | |
| | | import com.duqing.missions.data.BaseApiResult; |
| | | import com.duqing.missions.retrofit.utils.RSAUtils; |
| | | import com.duqing.missions.util.GsonUtils; |
| | | 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 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; |
| | | |
| | | /** |
| | | * My father is Object, ites purpose of 解密gson转换器 |
| | | * |
| | | * @purpose Created by Runt (qingingrunt2010@qq.com) on 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(); |
| | | BaseApiResult apiResult = new BaseApiResult<>(); |
| | | apiResult.code = 412; |
| | | apiResult.msg = "解密数据出错"+e.getMessage(); |
| | | response = new Gson().toJson(apiResult); |
| | | } catch (JSONException e) { |
| | | e.printStackTrace(); |
| | | BaseApiResult apiResult = new BaseApiResult<>(); |
| | | apiResult.code = 414; |
| | | apiResult.msg = "非标准json"; |
| | | response = new Gson().toJson(apiResult); |
| | | }catch (Exception e){ |
| | | JsonReader jsonReader = gson.newJsonReader(value.charStream()); |
| | | return adapter.read(jsonReader); |
| | | } finally { |
| | | 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 { |
| | | Log.e("Converter","decryptJsonStr body:"+body); |
| | | if(body.indexOf("{") == 0) { |
| | | JSONObject json = new JSONObject(body); |
| | | body = RSAUtils.decrypt(json.getString(ENCRYPT), RSAUtils.getPublicKey(RSAUtils.PUBLIC_KEY));// |
| | | } |
| | | return transHump? GsonUtils.toHumpJson(body):body; |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.duqing.missions.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; |
| | | |
| | | /** |
| | | * My father is Object, ites purpose of |
| | | * |
| | | * @purpose Created by Runt (qingingrunt2010@qq.com) on 2021-7-15. |
| | | */ |
| | | |
| | | final class GsonRequestBodyConverter<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; |
| | | |
| | | GsonRequestBodyConverter(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()); |
| | | } |
| | | } |
New file |
| | |
| | | package com.duqing.missions.retrofit.utils; |
| | | |
| | | import com.duqing.missions.BuildConfig; |
| | | import com.duqing.missions.util.GsonUtils; |
| | | import com.duqing.missions.util.MyLog; |
| | | |
| | | import java.io.EOFException; |
| | | import java.util.ArrayList; |
| | | |
| | | import okio.Buffer; |
| | | |
| | | /** |
| | | * My father is Object, ites purpose of 单例模式 保证synchronized方法的线程安全性 |
| | | * |
| | | * @purpose Created by Runt (qingingrunt2010@qq.com) on 2021-5-13. |
| | | */ |
| | | |
| | | public class HttpPrintUtils { |
| | | String TAG = "HttpPrintUtils"; |
| | | static HttpPrintUtils instance; |
| | | public static HttpPrintUtils getInstance(){ |
| | | if(instance == null){ |
| | | instance = new HttpPrintUtils(); |
| | | } |
| | | return instance; |
| | | } |
| | | |
| | | /** |
| | | * 打印log |
| | | * @param list |
| | | */ |
| | | public synchronized void printLog(ArrayList<String> list, boolean info){ |
| | | int length = 0 ;//计算每行最长的长度 |
| | | ArrayList<String> logArrays = new ArrayList<>(); |
| | | for(String str : list){ |
| | | if(str.indexOf("\n")>-1){//有换行的拆分处理 |
| | | String[] split = str.split("\n"); |
| | | for(String s : split){ |
| | | s = s.replace("\t"," ");//缩进替换空格 |
| | | if(length<s.length()){ |
| | | length = s.length(); |
| | | } |
| | | } |
| | | }else{ |
| | | if(length<str.length()){ |
| | | length = str.length(); |
| | | } |
| | | } |
| | | } |
| | | length+=14;//左右间距 |
| | | if(length>300){ |
| | | length = 300; |
| | | } |
| | | String head = "HTTP REQUEST START"; |
| | | logArrays.add(" \n\n\n"+"\n"); |
| | | //打印头部 |
| | | String logHead = "┏"+getEmptyStr((length-head.length())/2,"━")+head+getEmptyStr((length-head.length())/2,"━")+"┓"; |
| | | logArrays.add(logHead+"\n"); |
| | | //打印内容 |
| | | for(String str : list){ |
| | | String logStr = ""; |
| | | if(str.indexOf("\n")>-1){//内部换行替换 |
| | | splitStr(str,logHead.length(),logArrays); |
| | | }else{ |
| | | if(str.length()> logHead.length()){ |
| | | outOflength(str,logHead.length(),logArrays); |
| | | }else { |
| | | logStr = "┃ " + str + getEmptyStr((length - 14 - str.length()), " "); |
| | | //处理中文间距,保证打印无偏差 |
| | | logArrays.add(logStr + getEmptyStr((logHead.length() - logStr.length() - 1 - hasCNchar(logStr)), " ") + "┃ \n"); |
| | | } |
| | | } |
| | | } |
| | | String end = "HTTP REQUEST END"; |
| | | //打印结尾 |
| | | logArrays.add("┗"+getEmptyStr((length-end.length())/2,"━")+end+getEmptyStr((length-end.length())/2,"━")+"┛\n"); |
| | | logArrays.add(" \n\n\n"); |
| | | //Logger.DEFAULT.log(sb.toString());//打印log,避免多个log语句,导致log输出时其他线程的log输出切入此输出阵列内 |
| | | if(BuildConfig.DEBUG) { |
| | | for(int i = 0 ; i < logArrays.size() ; i ++ ){ |
| | | String str = logArrays.get(i); |
| | | if (info) { |
| | | MyLog.i(TAG , str.replace("\n","")+" "+logArrays.size()+" "+i); |
| | | } else { |
| | | MyLog.e(TAG , str.replace("\n","")+" "+logArrays.size()+" "+i); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 拆分 |
| | | * @param str |
| | | * @param totalLength |
| | | * @param list |
| | | */ |
| | | private void splitStr(String str,int totalLength,ArrayList<String> list){ |
| | | String logStr = ""; |
| | | String[] split = str.split("\n"); |
| | | for(String s : split){ |
| | | if(s.length()/totalLength>3){ |
| | | s = s.substring(0,totalLength*3)+"..."; |
| | | } |
| | | s = s.replace("\t"," ");//缩进替换空格 |
| | | if(s.indexOf("\":{\"")>-1 || s.indexOf("\":[{\"")>-1 || s.indexOf("\":[[")>-1){//内容非校正缩进,且为json字符规范 |
| | | splitStr(s.substring(0,s.indexOf("\":")+2)+ GsonUtils.retractJson(s.substring(s.indexOf("\":")+2)),totalLength,list); |
| | | }else { |
| | | if(s.length()> totalLength){ |
| | | outOflength(s,totalLength,list); |
| | | }else { |
| | | logStr = "┃ " + s + getEmptyStr((totalLength - 16 - s.length()), " "); |
| | | //处理中文间距,保证打印无偏差 |
| | | list.add(logStr + getEmptyStr((totalLength - logStr.length() - 1 - hasCNchar(logStr)), " ") + "┃ "/*+logStr.length()+" "+logStr.getBytes().length+" "+(" ").getBytes().length +" "+hasCNchar(s)*/ + "\n"); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 超长字符拆分 |
| | | * @param str |
| | | * @param total |
| | | * @param list |
| | | */ |
| | | private void outOflength(String str,int total,ArrayList<String> list){ |
| | | String logStr = ""; |
| | | //缩进空间 |
| | | String space = getEmptyStr(str.length() - str.trim().length()+4," "); |
| | | //要拆分的实际长度 |
| | | int length = (str.length()-space.length()); |
| | | //每行数量 |
| | | int count = total-16-space.length();//总长度-间距-缩进空间是每行的数量 |
| | | //最终拆分数量 |
| | | int lines = (length/count) + (length%(count)>0?1:0); |
| | | |
| | | for(int i = 0 ; i < lines ; i ++){ |
| | | int start = space.length() + (count * (i+1));//起始位 |
| | | int end = start+count;//结束位 |
| | | String s = ""; |
| | | if(start > str.length() && i > 0){ |
| | | break; |
| | | } else if(end > str.length() && i > 0 || i == lines-1){ |
| | | s = str.substring(start); |
| | | } else if(i == 0 ){ |
| | | s = str.substring(0, start); |
| | | } else { |
| | | s = str.substring(start, end); |
| | | } |
| | | if(i>0) { |
| | | s = space + s; |
| | | } |
| | | logStr = "┃ " + s + getEmptyStr((total - 16 - s.length()), " "); |
| | | list.add(logStr + getEmptyStr((total - logStr.length() - 1 - hasCNchar(logStr)), " ") + "┃ \n"); |
| | | } |
| | | } |
| | | |
| | | |
| | | //返回包含中文数量, |
| | | private int hasCNchar(String str){ |
| | | str = str.replace("┃",""); |
| | | int size = 0 ; |
| | | for(int i = 0 ; i < str.length() ; i ++){ |
| | | char c = str.charAt(i); |
| | | |
| | | if((c >= 0x0391 && c <= 0xFFE5)) { //中文字符 |
| | | size++; |
| | | } |
| | | } |
| | | return size>0?(int)(size/3.0*2):0;//+1为修正在log中与英文字符短一位 |
| | | } |
| | | |
| | | /** |
| | | * 占位符填充 |
| | | * @param length 占位数量 |
| | | * @param space 占位符 |
| | | * @return |
| | | */ |
| | | private String getEmptyStr(int length,String space){ |
| | | StringBuilder sb = new StringBuilder(); |
| | | for(int i = 0 ; i < length ; i ++){ |
| | | sb.append(space); |
| | | } |
| | | return sb.toString(); |
| | | } |
| | | /** |
| | | * Returns true if the body in question probably contains human readable text. Uses a small sample |
| | | * of code points to detect unicode control characters commonly used in binary file signatures. |
| | | */ |
| | | static boolean isPlaintext(Buffer buffer) { |
| | | try { |
| | | Buffer prefix = new Buffer(); |
| | | long byteCount = buffer.size() < 64 ? buffer.size() : 64; |
| | | buffer.copyTo(prefix, 0, byteCount); |
| | | for (int i = 0; i < 16; i++) { |
| | | if (prefix.exhausted()) { |
| | | break; |
| | | } |
| | | int codePoint = prefix.readUtf8CodePoint(); |
| | | if (Character.isISOControl(codePoint) && !Character.isWhitespace(codePoint)) { |
| | | return false; |
| | | } |
| | | } |
| | | return true; |
| | | } catch (EOFException e) { |
| | | return false; // Truncated UTF-8 sequence. |
| | | } |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.duqing.missions.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 = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCwRnotLHB6Do0yyJjx7wEmhqmDa3S4ntHJFqe-DZKr-xVXlzzr1hBvP40SQlYydYK6_EhnfbFWNrMZ-VyM-31BAX8e1ZvJtA2gjQViaRSxsPcYmlWdgFCqDckw-DYGaG28GW7emTQev34ID6xhdfKauhj8gp3V9SVvGYmSo991QQIDAQAB"; |
| | | |
| | | |
| | | /** |
| | | * 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.URL_SAFE); |
| | | 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/None/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/None/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.duqing.missions.R; |
| | | import com.duqing.missions.base.activities.BaseTitleBarActivity; |
| | | import com.duqing.missions.databinding.ActivityLoginBinding; |
| | | import com.duqing.missions.retrofit.RetrofitUtils; |
| | | import com.duqing.missions.retrofit.api.LoginApiCenter; |
| | | |
| | | import retrofit2.Call; |
| | | import retrofit2.Callback; |
| | | import retrofit2.Response; |
| | | |
| | | |
| | | public class LoginActivity extends BaseTitleBarActivity<ActivityLoginBinding,LoginViewModel> { |
| | |
| | | loginButton.setOnClickListener(new View.OnClickListener() { |
| | | @Override |
| | | public void onClick(View v) { |
| | | viewModel.login(phoneEdit.getText().toString(), |
| | | passwordEditText.getText().toString()); |
| | | /*RetrofitUtils.getInstance().getRetrofit(LoginApiCenter.class).login(";lajks;dkfjal;ksjdf") |
| | | |
| | | .subscribeOn(Schedulers.io())//指定网络请求在io后台线程中进行 |
| | | .observeOn(AndroidScheduler.mainThread())//指定observer回调在UI主线程中进行 |
| | | .subscribe(new io.reactivex.Observer<Object>() { |
| | | @Override |
| | | public void onSubscribe(Disposable d) { |
| | | v.setEnabled(false); |
| | | Log.d(TAG,"onSubscribe"); |
| | | } |
| | | |
| | | @Override |
| | | public void onNext(Object value) { |
| | | Log.d(TAG,"onNext value:"+value); |
| | | |
| | | } |
| | | |
| | | @Override |
| | | public void onError(Throwable e) { |
| | | v.setEnabled(true); |
| | | Log.d(TAG,"onError "+e.getMessage()); |
| | | |
| | | } |
| | | |
| | | @Override |
| | | public void onComplete() { |
| | | v.setEnabled(true); |
| | | Log.d(TAG,"onComplete"); |
| | | |
| | | } |
| | | });//发起请求,请求的结果会回调到订阅者observer中*/ |
| | | RetrofitUtils.getInstance().getRetrofit(LoginApiCenter.class).loginCall("asdfasdfasdfasdfasdf").enqueue(new Callback<Object>() { |
| | | @Override |
| | | public void onResponse(Call<Object> call, Response<Object> response) { |
| | | |
| | | } |
| | | |
| | | @Override |
| | | public void onFailure(Call<Object> call, Throwable t) { |
| | | |
| | | } |
| | | }); |
| | | } |
| | | }); |
| | | |
New file |
| | |
| | | /* |
| | | * Copyright (C) 2017 Baidu, Inc. All Rights Reserved. |
| | | */ |
| | | package com.duqing.missions.util; |
| | | |
| | | import com.google.gson.Gson; |
| | | import com.google.gson.GsonBuilder; |
| | | import com.google.gson.JsonParseException; |
| | | |
| | | import org.json.JSONArray; |
| | | import org.json.JSONException; |
| | | import org.json.JSONObject; |
| | | |
| | | import java.lang.reflect.Type; |
| | | import java.util.ArrayList; |
| | | import java.util.Collection; |
| | | import java.util.Iterator; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.TreeMap; |
| | | |
| | | /** |
| | | * Json工具类. |
| | | */ |
| | | public class GsonUtils { |
| | | private static Gson gson = new GsonBuilder().create(); |
| | | |
| | | public static String toJson(Object value) { |
| | | return gson.toJson(value); |
| | | } |
| | | |
| | | public static <T> T fromJson(String json, Class<T> classOfT) throws JsonParseException { |
| | | return gson.fromJson(json, classOfT); |
| | | } |
| | | |
| | | public static <T> T fromJson(String json, Type typeOfT) throws JsonParseException { |
| | | return (T) gson.fromJson(json, typeOfT); |
| | | } |
| | | |
| | | /** |
| | | * 将对象转换为驼峰命名的json |
| | | * @param value |
| | | * @return |
| | | */ |
| | | public static String toHumpJson(Object value) { |
| | | try { |
| | | if(value instanceof Collection){ |
| | | return convertToHumpJsonArray(new JSONArray(gson.toJson(value)) ).toString(); |
| | | }else { |
| | | return convertToHumpJsonObj(new JSONObject(gson.toJson(value)) ).toString(); |
| | | } |
| | | } catch (JSONException e) { |
| | | e.printStackTrace(); |
| | | return gson.toJson(value); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * |
| | | * 将json转换为驼峰命名的json |
| | | * @param json |
| | | * @return |
| | | */ |
| | | public static String toHumpJson(String json) throws JSONException { |
| | | if(json.indexOf("[") == 0){ |
| | | return convertToHumpJsonArray(new JSONArray(json) ).toString(); |
| | | }else { |
| | | return convertToHumpJsonObj(new JSONObject(json) ).toString(); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 驼峰命名转换 |
| | | * @param json |
| | | * @param classOfT |
| | | * @param <T> |
| | | * @return |
| | | * @throws JsonParseException |
| | | */ |
| | | public static <T> T fromJsonToHump(String json, Class<T> classOfT) throws JsonParseException, JSONException { |
| | | return gson.fromJson(toHumpJson(json), classOfT); |
| | | } |
| | | |
| | | /** |
| | | * 驼峰命名转换 |
| | | * @param json |
| | | * @param typeOfT |
| | | * @param <T> |
| | | * @return |
| | | * @throws JsonParseException |
| | | */ |
| | | public static <T> T fromJsonToHump(String json, Type typeOfT) throws JsonParseException, JSONException { |
| | | return (T) gson.fromJson(toHumpJson(json), typeOfT); |
| | | } |
| | | |
| | | /** |
| | | * 转换驼峰命名 |
| | | * @param jsonObject |
| | | * @return |
| | | */ |
| | | public static JSONObject convertToHumpJsonObj(JSONObject jsonObject){ |
| | | JSONObject temp = new JSONObject(); |
| | | Iterator<String> it = jsonObject.keys(); |
| | | while ( it.hasNext()){ |
| | | String key = it.next(); |
| | | String humpKey = humpName(key); |
| | | try { |
| | | if(jsonObject.get(key) instanceof JSONObject){ |
| | | temp.put(humpKey,convertToHumpJsonObj(jsonObject.getJSONObject(key))); |
| | | }else if(jsonObject.get(key) instanceof JSONArray){ |
| | | temp.put(humpKey,convertToHumpJsonArray(jsonObject.getJSONArray(key))); |
| | | }else { |
| | | temp.put(humpKey,jsonObject.get(key)); |
| | | } |
| | | } catch (JSONException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | } |
| | | return temp; |
| | | |
| | | } |
| | | |
| | | public static JSONArray convertToHumpJsonArray(JSONArray array){ |
| | | JSONArray jsons = new JSONArray(); |
| | | for(int i = 0 ; i < array.length() ; i ++){ |
| | | try { |
| | | if(array.get(i) instanceof JSONObject){ |
| | | jsons.put(convertToHumpJsonObj(array.getJSONObject(i))); |
| | | }else if(array.get(i) instanceof JSONArray){ |
| | | jsons.put(convertToHumpJsonArray(array.getJSONArray(i))); |
| | | }else { |
| | | jsons.put(array.get(i)); |
| | | } |
| | | } catch (JSONException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | } |
| | | return jsons; |
| | | |
| | | } |
| | | /** |
| | | * 将key转换为驼峰 |
| | | * @param param |
| | | * @return |
| | | */ |
| | | public static Map convertToHumpMap(Map<String, Object> param){ |
| | | Map temp = new TreeMap(); |
| | | for(String key: param.keySet()){ |
| | | String humpKey = humpName(key); |
| | | if(param.get(key) instanceof Map){ |
| | | temp.put(humpKey,convertToHumpMap((Map<String, Object>) param.get(key))); |
| | | }else if(param.get(key) instanceof List){ |
| | | temp.put(humpKey,convertToHumpList((List)param.get(key))); |
| | | }else { |
| | | temp.put(humpKey,param.get(key)); |
| | | } |
| | | } |
| | | return temp; |
| | | } |
| | | |
| | | |
| | | public static List convertToHumpList(List list){ |
| | | List ars = new ArrayList(); |
| | | for(Object object : list){ |
| | | if(object instanceof Map){ |
| | | ars.add(convertToHumpMap((Map)object)); |
| | | }else if(object instanceof List){ |
| | | ars.add(convertToHumpList((List)object)); |
| | | }else { |
| | | ars.add(object); |
| | | } |
| | | } |
| | | return ars; |
| | | } |
| | | /** |
| | | * 驼峰命名 |
| | | * @param name |
| | | * @return |
| | | */ |
| | | public static String humpName(String name){ |
| | | String[] strings = name.split("_"); |
| | | StringBuilder sb = new StringBuilder(); |
| | | sb.append(strings[0]); |
| | | for(int i = 1 ; i < strings.length ; i ++){ |
| | | sb.append(toUperFirst(strings[i])); |
| | | } |
| | | if(sb.toString().equals("new")){//关键字 转成大写 |
| | | return "NEW"; |
| | | } |
| | | return sb.toString(); |
| | | } |
| | | |
| | | /** |
| | | * 首字母大写 |
| | | * @param name |
| | | * @return |
| | | */ |
| | | public static String toUperFirst(String name){ |
| | | return name.substring(0,1).toUpperCase()+name.substring(1); |
| | | } |
| | | |
| | | /** |
| | | * json字符串缩进 |
| | | * @param json |
| | | * @return |
| | | */ |
| | | public static String retractJson(String json){ |
| | | int level = 0 ; |
| | | StringBuffer jsonForMatStr = new StringBuffer(); |
| | | for(int index=0;index<json.length();index++)//将字符串中的字符逐个按行输出 |
| | | { |
| | | //获取s中的每个字符 |
| | | char c = json.charAt(index); |
| | | // System.out.println(s.charAt(index)); |
| | | |
| | | //level大于0并且jsonForMatStr中的最后一个字符为\n,jsonForMatStr加入\t |
| | | if (level > 0 && '\n' == jsonForMatStr.charAt(jsonForMatStr.length() - 1)) { |
| | | jsonForMatStr.append(getLevelStr(level)); |
| | | // System.out.println("123"+jsonForMatStr); |
| | | } |
| | | //遇到"{"和"["要增加空格和换行,遇到"}"和"]"要减少空格,以对应,遇到","要换行 |
| | | switch (c) { |
| | | case '{': |
| | | case '[': |
| | | jsonForMatStr.append(c + "\n"); |
| | | level++; |
| | | break; |
| | | case ',': |
| | | if(index>0 && index < json.length()-2 && (json.charAt(index-1) != '\n') && json.charAt(index+1) == '"'){ |
| | | jsonForMatStr.append(c + "\n"); |
| | | }else{ |
| | | jsonForMatStr.append(c); |
| | | } |
| | | break; |
| | | case '}': |
| | | case ']': |
| | | jsonForMatStr.append("\n"); |
| | | level--; |
| | | jsonForMatStr.append(getLevelStr(level)); |
| | | jsonForMatStr.append(c); |
| | | break; |
| | | default: |
| | | jsonForMatStr.append(c); |
| | | break; |
| | | } |
| | | } |
| | | return jsonForMatStr.toString(); |
| | | } |
| | | private static String getLevelStr(int level) { |
| | | StringBuffer levelStr = new StringBuffer(); |
| | | for (int levelI = 0; levelI < level; levelI++) { |
| | | levelStr.append("\t");//\t或空格 |
| | | } |
| | | return levelStr.toString(); |
| | | } |
| | | } |
New file |
| | |
| | | package com.duqing.missions.util; |
| | | |
| | | import android.annotation.SuppressLint; |
| | | import android.content.Context; |
| | | import android.net.ConnectivityManager; |
| | | import android.net.NetworkInfo; |
| | | import android.net.wifi.WifiInfo; |
| | | import android.net.wifi.WifiManager; |
| | | import android.util.Log; |
| | | |
| | | import org.json.JSONException; |
| | | import org.json.JSONObject; |
| | | |
| | | import java.io.BufferedReader; |
| | | import java.io.IOException; |
| | | import java.io.InputStream; |
| | | import java.io.InputStreamReader; |
| | | import java.net.HttpURLConnection; |
| | | import java.net.Inet6Address; |
| | | import java.net.InetAddress; |
| | | import java.net.MalformedURLException; |
| | | import java.net.NetworkInterface; |
| | | import java.net.SocketException; |
| | | import java.net.URL; |
| | | import java.net.URLConnection; |
| | | import java.util.Enumeration; |
| | | import java.util.HashMap; |
| | | import java.util.Map; |
| | | |
| | | /** |
| | | * My father is Object, ites purpose of |
| | | * |
| | | * @purpose Created by Runt (qingingrunt2010@qq.com) on 2019-3-19. |
| | | */ |
| | | |
| | | public class NetWorkUtils { |
| | | |
| | | |
| | | /** |
| | | * 获取外网IP地址 |
| | | * @return |
| | | */ |
| | | public static String getNetIp() { |
| | | final Map<String,String> param = new HashMap<>(); |
| | | Thread thread = new Thread(new Runnable() { |
| | | @Override |
| | | public void run() { |
| | | String line = ""; |
| | | URL infoUrl = null; |
| | | InputStream inStream = null; |
| | | try { |
| | | infoUrl = new URL("http://pv.sohu.com/cityjson?ie=utf-8"); |
| | | URLConnection connection = infoUrl.openConnection(); |
| | | HttpURLConnection httpConnection = (HttpURLConnection) connection; |
| | | int responseCode = httpConnection.getResponseCode(); |
| | | if (responseCode == HttpURLConnection.HTTP_OK) { |
| | | inStream = httpConnection.getInputStream(); |
| | | BufferedReader reader = new BufferedReader(new InputStreamReader(inStream, "utf-8")); |
| | | StringBuilder strber = new StringBuilder(); |
| | | while ((line = reader.readLine()) != null) |
| | | strber.append(line + "\n"); |
| | | inStream.close(); |
| | | // 从反馈的结果中提取出IP地址 |
| | | int start = strber.indexOf("{"); |
| | | int end = strber.indexOf("}"); |
| | | String json = strber.substring(start, end + 1); |
| | | if (json != null) { |
| | | try { |
| | | JSONObject jsonObject = new JSONObject(json); |
| | | line = jsonObject.optString("cip"); |
| | | } catch (JSONException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | } |
| | | param.put("ip",line); |
| | | } |
| | | } catch (MalformedURLException e) { |
| | | e.printStackTrace(); |
| | | } catch (IOException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | } |
| | | }); |
| | | try { |
| | | thread.start(); |
| | | thread.join(); |
| | | } catch (InterruptedException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | return param.get("ip"); |
| | | } |
| | | |
| | | /*** |
| | | * 获取局域网ip |
| | | * @param context |
| | | * @return |
| | | */ |
| | | @SuppressLint("MissingPermission") |
| | | public static String getLocalIpAddress(Context context) { |
| | | |
| | | ConnectivityManager connect = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); |
| | | //检查网络连接 |
| | | NetworkInfo info = connect.getActiveNetworkInfo(); |
| | | |
| | | if (info == null) { |
| | | return ""; |
| | | } |
| | | int netType = info.getType(); |
| | | int netSubtype = info.getSubtype(); |
| | | |
| | | if (netType == ConnectivityManager.TYPE_WIFI) { //WIFI |
| | | return getWifiIpAddress(context); |
| | | } else /*if (netType == ConnectivityManager.TYPE_MOBILE) { //MOBILE |
| | | return getGPRSIpAddress(); |
| | | } else */if (netType == ConnectivityManager.TYPE_ETHERNET) { //MOBILE |
| | | return getEthernetIp(); |
| | | } else { |
| | | return ""; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 使用wifi |
| | | * @param context |
| | | * @return |
| | | */ |
| | | @SuppressLint("MissingPermission") |
| | | public static String getWifiIpAddress(Context context) { |
| | | |
| | | //获取wifi服务 |
| | | WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); |
| | | //判断wifi是否开启 |
| | | // if (!wifiManager.isWifiEnabled()) { |
| | | // <span style="white-space:pre"> </span> wifiManager.setWifiEnabled(true); |
| | | // } |
| | | WifiInfo wifiInfo = wifiManager.getConnectionInfo(); |
| | | int ipAddress = wifiInfo.getIpAddress(); |
| | | String ip = intToIp(ipAddress); |
| | | return ip; |
| | | } |
| | | |
| | | private static String intToIp(int i) { |
| | | return (i & 0xFF) + "." + |
| | | ((i >> 8) & 0xFF) + "." + |
| | | ((i >> 16) & 0xFF) + "." + |
| | | (i >> 24 & 0xFF); |
| | | } |
| | | /** |
| | | * 使用GPRS |
| | | * @return |
| | | */ |
| | | public static String getGPRSIpAddress() { |
| | | try { |
| | | for (Enumeration<NetworkInterface> en = NetworkInterface |
| | | .getNetworkInterfaces(); en.hasMoreElements(); ) { |
| | | NetworkInterface intf = en.nextElement(); |
| | | for (Enumeration<InetAddress> enumIpAddr = intf |
| | | .getInetAddresses(); enumIpAddr.hasMoreElements(); ) { |
| | | InetAddress inetAddress = enumIpAddr.nextElement(); |
| | | if (!inetAddress.isLoopbackAddress()) { |
| | | return inetAddress.getHostAddress().toString(); |
| | | } |
| | | } |
| | | } |
| | | } catch (SocketException ex) { |
| | | MyLog.e("Exception", ex.toString()); |
| | | } |
| | | return "127.0.0.1"; |
| | | } |
| | | |
| | | public static String getEthernetIp() { |
| | | String hostIp = null; |
| | | try { |
| | | Enumeration nis = NetworkInterface.getNetworkInterfaces(); |
| | | InetAddress ia = null; |
| | | while (nis.hasMoreElements()) { |
| | | NetworkInterface ni = (NetworkInterface) nis.nextElement(); |
| | | Enumeration<InetAddress> ias = ni.getInetAddresses(); |
| | | while (ias.hasMoreElements()) { |
| | | ia = ias.nextElement(); |
| | | if (ia instanceof Inet6Address) { |
| | | continue;// skip ipv6 |
| | | } |
| | | String ip = ia.getHostAddress(); |
| | | if (!"127.0.0.1".equals(ip)) { |
| | | hostIp = ia.getHostAddress(); |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | } catch (SocketException e) { |
| | | Log.i("yao", "SocketException"); |
| | | e.printStackTrace(); |
| | | } |
| | | return hostIp; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 将得到的int类型的IP转换为String类型 |
| | | * |
| | | * @param ip |
| | | * @return |
| | | */ |
| | | public static String intIP2StringIP(int ip) { |
| | | return (ip & 0xFF) + "." + |
| | | ((ip >> 8) & 0xFF) + "." + |
| | | ((ip >> 16) & 0xFF) + "." + |
| | | (ip >> 24 & 0xFF); |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | <?xml version="1.0" encoding="utf-8"?> |
| | | <set xmlns:android="http://schemas.android.com/apk/res/android"> |
| | | <translate android:fromXDelta="-50%p" android:toXDelta="0" |
| | | android:duration="@android:integer/config_mediumAnimTime"/> |
| | | <alpha android:fromAlpha="0.0" android:toAlpha="1.0" |
| | | android:duration="@android:integer/config_mediumAnimTime" /> |
| | | </set> |
New file |
| | |
| | | <?xml version="1.0" encoding="utf-8"?> |
| | | <navigation xmlns:android="http://schemas.android.com/apk/res/android" |
| | | xmlns:app="http://schemas.android.com/apk/res-auto" |
| | | xmlns:tools="http://schemas.android.com/tools" |
| | | android:id="@+id/mobile_navigation" |
| | | app:startDestination="@+id/navigation_home"> |
| | | |
| | | <fragment |
| | | android:id="@+id/navigation_home" |
| | | android:name="com.duqing.missions.ui.main.home.HomeFragment" |
| | | android:label="@string/title_home" |
| | | tools:layout="@layout/fragment_home" /> |
| | | |
| | | <fragment |
| | | android:id="@+id/navigation_hall" |
| | | android:name="com.duqing.missions.ui.main.hall.HallFragment" |
| | | android:label="@string/title_hall" |
| | | tools:layout="@layout/layout_tab_viewpager" /> |
| | | |
| | | <fragment |
| | | android:id="@+id/navigation_dynamic" |
| | | android:name="com.duqing.missions.ui.main.dynamic.DynamicFragment" |
| | | android:label="@string/title_dynamic" |
| | | tools:layout="@layout/layout_tab_viewpager" /> |
| | | <fragment |
| | | android:id="@+id/navigation_mine" |
| | | android:name="com.duqing.missions.ui.main.mine.MineFragment" |
| | | android:label="@string/title_mine" |
| | | tools:layout="@layout/fragment_mine" /> |
| | | </navigation> |
| | |
| | | <resources> |
| | | <string name="app_name">Missions</string> |
| | | <string name="title_home">Home</string> |
| | | <string name="title_hall">Hall</string> |
| | | <string name="title_dynamic">Dynamic</string> |
New file |
| | |
| | | <?xml version="1.0" encoding="utf-8"?> |
| | | <network-security-config> |
| | | <base-config cleartextTrafficPermitted="true" /> |
| | | </network-security-config> |