Commit df5b0ceb authored by mengcuiguang's avatar mengcuiguang
parents b81b4162 3d12fe52
package com.fry.base.network; package com.fry.base.basenetwork;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
......
package com.fry.base.network; package com.fry.base.basenetwork;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
......
package com.fry.base.network package com.fry.base.basenetwork
import me.goldze.mvvmhabit._enum.ViewStatus import me.goldze.mvvmhabit._enum.ViewStatus
import me.goldze.mvvmhabit.base.BaseViewModel import me.goldze.mvvmhabit.base.BaseViewModel
......
package com.fry.base.network; package com.fry.base.basenetwork;
import java.security.SecureRandom; import java.security.SecureRandom;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
......
package com.fry.base.network; package com.fry.base.basenetwork;
import io.reactivex.disposables.Disposable; import io.reactivex.disposables.Disposable;
import me.goldze.mvvmhabit.http.BaseResponse; import me.goldze.mvvmhabit.http.BaseResponse;
......
package com.fry.base.network package com.fry.base.basenetwork
import io.reactivex.Observer import io.reactivex.Observer
import io.reactivex.disposables.Disposable import io.reactivex.disposables.Disposable
......
package com.fry.base.network; package com.fry.base.basenetwork;
import android.content.Context; import android.content.Context;
import android.text.TextUtils; import android.text.TextUtils;
......
package com.fry.base.network; package com.fry.base.basenetwork;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
......
package com.fry.base.netwrok;
import android.os.Process;
import com.fry.base.R;
import io.reactivex.Observable;
import io.reactivex.ObservableSource;
import io.reactivex.ObservableTransformer;
import io.reactivex.functions.Function;
import me.goldze.mvvmhabit.base.AppManager;
import me.goldze.mvvmhabit.http.BaseResponse;
import me.goldze.mvvmhabit.utils.ToastUtils;
import me.goldze.mvvmhabit.utils.Utils;
import retrofit2.Response;
/**
* Created by jeme on 2019/2/25
*/
public class HttpErrorProcess {
public static <T> ObservableTransformer<T, T> businessExceptionTransformer() {
return new ObservableTransformer<T, T>() {
@Override
public ObservableSource<T> apply(Observable observable) {
return observable
.map(new HandleFuc<T>()); //这里可以取出BaseResponse中的Result
}
};
}
private static class HandleFuc<T> implements Function<Response<BaseResponse<T>>, Response<BaseResponse<T>>> {
@Override
public Response<BaseResponse<T>> apply(Response<BaseResponse<T>> response) {
if (response.body() == null) {
return response;
}
if (response.body().getCode() == 401 || response.body().getCode() == 403) {//未登录 token 过期
// IUserService.getInstance().loginInvalid();
// IUserService.getInstance().navToLogin(AppManager.getAppManager().getCurrentActivity(), null);
return null;
} else if (response.body().getCode() == 550) {
//签名错误
// ToastUtils.showShort(R.string.app_update_toast_tip);
/*ToastUtils.showShort("请从正规渠道下载App");
AppManager.getAppManager().finishAllActivity();
Utils.getHandler().postDelayed(new Runnable() {
@Override
public void run() {
Process.killProcess(Process.myPid());
System.exit(0);
}
}, 3000);*/
return null;
}
return response;
}
}
/*private static class HandleFuc<T> implements Function<BaseResponse<T>, BaseResponse<T>> {
@Override
public BaseResponse<T> apply(BaseResponse<T> response) {
*//* if(response.body().getCode() == 412506){//门店未注册
}else if(response.body().getCode() == 412539) {//用户未注册
}*//*
return response;
}
}*/
}
package com.fry.base.netwrok;
import android.annotation.SuppressLint;
import android.text.TextUtils;
import com.fry.base.basenetwork.HttpConfiguation;
import com.fry.base.basenetwork.IHttpResponseListener;
import com.fry.base.basenetwork.RetrofitClient;
import com.fry.base.global.Constants;
import com.qjzn.ddg.common.network.ServerTimeHelper;
import com.trello.rxlifecycle2.LifecycleProvider;
import java.util.HashMap;
import java.util.concurrent.TimeUnit;
import io.reactivex.Observable;
import io.reactivex.ObservableSource;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Action;
import io.reactivex.functions.Consumer;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;
import me.goldze.mvvmhabit.http.BaseResponse;
import me.goldze.mvvmhabit.http.ResponseThrowable;
import me.goldze.mvvmhabit.utils.RxUtils;
import retrofit2.Response;
/**
* Created by jeme on 2019/1/31
*/
public class HttpManager {
private RetrofitClient mDefaultClient;
private RetrofitClient mTimeClient;
private static class SingletonHolder {
private static HttpManager INSTANCE = new HttpManager();
}
public static HttpManager getInstance() {
return SingletonHolder.INSTANCE;
}
private HttpManager() {
mDefaultClient = new RetrofitClient(
HttpConfiguation.create(Constants.getBaseUrl())
.addInterceptor(new PublicHeaderInterceptor())
);
}
public RetrofitClient getDefaultClient() {
return mDefaultClient;
}
public RetrofitClient getTimeClient() {
if (mTimeClient == null) {
mTimeClient = new RetrofitClient(
HttpConfiguation.create(Constants.getBaseUrl())
.setTimeOut(5000));
}
return mTimeClient;
}
public <T> T getDefaultServices(Class<T> clz) {
return getDefaultClient().create(clz);
}
public <B extends BaseResponse, T extends Response<B>>
Observable<T> execute(LifecycleProvider life,final Observable<T> observable) {
Observable<T> newObservable = Observable.just(observable)
.observeOn(Schedulers.io())
.flatMap((Function<Observable<T>, ObservableSource<T>>) tObservable -> {
ServerTimeHelper.requestServerTime();
return observable;
})
.observeOn(AndroidSchedulers.mainThread());
if (life != null) {
newObservable = newObservable.compose(RxUtils.bindToLifecycle(life));
}
return newObservable
.compose(RxUtils.schedulersTransformer())
.compose(RxUtils.exceptionTransformer())
.compose(HttpErrorProcess.businessExceptionTransformer());
}
@SuppressLint("CheckResult")
public <B extends BaseResponse, T extends Response<B>>
void execute(LifecycleProvider life,final Observable<T> observable, IHttpResponseListener<B> listener) {
Observable<T> newObservable = Observable.just(observable)
.observeOn(Schedulers.io())
.flatMap((Function<Observable<T>, ObservableSource<T>>) tObservable -> {
ServerTimeHelper.requestServerTime();
return observable;
})
.observeOn(AndroidSchedulers.mainThread());
if (life != null) {
newObservable = newObservable.compose(RxUtils.bindToLifecycle(life));
}
newObservable
.compose(RxUtils.schedulersTransformer())
.compose(RxUtils.exceptionTransformer())
.compose(HttpErrorProcess.businessExceptionTransformer())
.doOnSubscribe(new Consumer<Disposable>() {
@Override
public void accept(Disposable disposable) throws Exception {
if (listener != null) {
listener.onStart(disposable);
}
}
})
.doFinally(new Action() {
@Override
public void run() throws Exception {
if (listener != null) {
listener.onCompleted();
}
}
})
.subscribe(t -> {
if (listener != null) {
// listener.onCompleted();
if (!listener.onParseResponse(t)) {
if (t.body() != null && t.body().isOk()) {
listener.onBusinessSuccess(t.body());
} else {
listener.onBusinessFail(t.body());
}
}
}
}, throwable -> {
if (listener != null && throwable instanceof ResponseThrowable) {
listener.onFailed((ResponseThrowable) throwable);
}
throwable.printStackTrace();
}, () -> {
});
}
}
package com.fry.base.netwrok;
import android.os.Build;
import android.text.TextUtils;
import com.fry.base.utils.ConfigManager;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.reflect.TypeToken;
import com.qjzn.ddg.common.network.ServerTimeHelper;
import java.io.IOException;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import me.goldze.mvvmhabit.BuildConfig;
import me.goldze.mvvmhabit.utils.AppUtils;
import me.goldze.mvvmhabit.utils.KLog;
import me.goldze.mvvmhabit.utils.MD5Util;
import me.goldze.mvvmhabit.utils.StringUtils;
import me.goldze.mvvmhabit.utils.Utils;
import okhttp3.HttpUrl;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
import okio.Buffer;
public class PublicHeaderInterceptor implements Interceptor {
private static final String TIMES_TAMP = "timestamp";
private static final String TOUCH_ID = "touchid";
private static final String DEVICE = "device";
private static final String VERSION = "version";
private static final String TOKEN = "token";
private static final String SIGN = "sign";
private static final String KEY = "key_secret";
private static final String KEY_VALUE = "base64:qC93ZPHeTNxh2SwB/DeOSb0zUwiU61ZDAPvdnOjROYE=";
private Gson gson;
private String imeiMd5;
private String androidId;
public PublicHeaderInterceptor() {
gson = createGsonObj();
}
/**
* Gson 自动将 int 转为 double 问题解决
*/
private Gson createGsonObj() {
return new GsonBuilder()
.registerTypeAdapter(
new TypeToken<TreeMap<String, String>>() {
}.getType(),
new JsonDeserializer<TreeMap<String, String>>() {
@Override
public TreeMap<String, String> deserialize(
JsonElement json, Type typeOfT,
JsonDeserializationContext context) throws JsonParseException {
TreeMap<String, String> treeMap = new TreeMap<>();
JsonObject jsonObject = json.getAsJsonObject();
Set<Map.Entry<String, JsonElement>> entrySet = jsonObject.entrySet();
for (Map.Entry<String, JsonElement> entry : entrySet) {
if (entry.getValue().isJsonArray()) {
treeMap.put(entry.getKey(), Utils.getGson().toJson(entry.getValue()));
} else {
treeMap.put(entry.getKey(), entry.getValue().getAsString());
}
}
return treeMap;
}
}).create();
}
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
String method = request.method();
// 单位秒 10位
long time = ServerTimeHelper.getTimestamp() / 1000;
String device = "android";
//String touchId = DeviceId.INSTANCE.getDeviceId();
String touchId ="";
// String token = StringUtils.null2Length0(IUserService.getInstance().getUserToken());
String token = "";
HttpUrl url = request.url();
String sign = "";
Request.Builder builder = request.newBuilder();
// 获取参数
Map<String, String> params = new HashMap<>(10);
// 获取 url 参数
List<String> urlKeys = new ArrayList<>(url.queryParameterNames());
String urlKey = "";
for (int i = 0; i < urlKeys.size(); i++) {
urlKey = urlKeys.get(i);
params.put(urlKey, StringUtils.null2Length0(url.queryParameter(urlKey)));
}
// 获取 Body 参数
String bodyString = "";
if (request.body() != null) {
final Buffer buffer = new Buffer();
request.body().writeTo(buffer);
bodyString = buffer.readUtf8();
}
if (isJsonObject(bodyString) || isJsonArray(bodyString)) {
TreeMap<String, String> map = gson.fromJson(bodyString, new TypeToken<TreeMap<String, String>>() {
}.getType());
if (map != null) {
for (String key : map.keySet()) {
params.put(key, map.get(key));
}
}
}
// 传入指定参数
params.put(PublicHeaderInterceptor.TIMES_TAMP, String.valueOf(time));
if (!TextUtils.isEmpty(touchId)) {
params.put(PublicHeaderInterceptor.TOUCH_ID, touchId);
}
params.put(PublicHeaderInterceptor.DEVICE, device);
if (!TextUtils.isEmpty(token)) {
params.put(PublicHeaderInterceptor.TOKEN, token);
}
params.put(PublicHeaderInterceptor.KEY, KEY_VALUE);
StringBuilder signStringBuilder = new StringBuilder();
List<String> keys = new ArrayList<>(params.keySet());
// 移除SIGN key
keys.remove(SIGN);
// 排序
Collections.sort(keys);
// 排序后 拼接
for (int i = 0; i < keys.size(); i++) {
String key = keys.get(i);
if (i != 0) {
signStringBuilder.append("&");
}
String valueObj = params.get(key);
String value = "";
if (valueObj != null) {
value = valueObj;
}
signStringBuilder.append(String.format("%s=%s", key, value));
}
String signBefore = signStringBuilder.toString().toLowerCase();
// MD5加密
sign = MD5Util.md5(signBefore.getBytes());
// 在URL末尾追加签名与时间
String newUrl = url.toString();
if (!newUrl.contains("?")) {
newUrl = String.format("%s?sign=%s&timestamp=%s", newUrl, sign, time);
} else {
newUrl = String.format("%s&sign=%s&timestamp=%s", newUrl, sign, time);
}
builder.url(newUrl);
KLog.d("request", String.format("newUrl={%s} \n md5_str={%s} \n time=%s", newUrl, signBefore, time));
// --start 将验签参数加入header
if (!TextUtils.isEmpty(token)) {
builder.addHeader(TOKEN, token);
}
if (!TextUtils.isEmpty(touchId)) {
builder.addHeader(PublicHeaderInterceptor.TOUCH_ID, touchId);
}
builder.addHeader(PublicHeaderInterceptor.DEVICE, device);
builder.addHeader(PublicHeaderInterceptor.VERSION, BuildConfig.VERSION_NAME);
// --end
builder.addHeader("vcode", BuildConfig.VERSION_CODE + "");
builder.addHeader("channel", ConfigManager.getDefault().getAppChannel());
// samsung SM-G6200 8.1.0
builder.addHeader("systemVersion", String.format("%s|%s|%s", Build.BRAND, Build.MODEL, Build.VERSION.RELEASE));
if (TextUtils.isEmpty(imeiMd5)) {
String imei = AppUtils.getImei(Utils.getContext());
if (!TextUtils.isEmpty(imei)) {
imeiMd5 = MD5Util.md5(imei.getBytes());
}
}
if (!TextUtils.isEmpty(imeiMd5)) {
builder.addHeader("imei", imeiMd5);
}
if (TextUtils.isEmpty(androidId)) {
androidId = AppUtils.getAndroidId(Utils.getContext());
}
builder.addHeader("androidId", androidId);
//请求信息
return chain.proceed(builder.build());
}
private boolean isJsonObject(String content) {
return !StringUtils.isEmpty(content) && (content.trim().startsWith("{") && content.trim().endsWith("}"));
}
private boolean isJsonArray(String content) {
return !StringUtils.isEmpty(content) && (content.trim().startsWith("[") && content.trim().endsWith("]"));
}
}
\ No newline at end of file
@file:JvmName("ServerTimeHelper")
package com.qjzn.ddg.common.network
import com.fry.base.netwrok.HttpManager
import com.google.gson.Gson
import me.goldze.mvvmhabit.utils.KLog
import okhttp3.ResponseBody
import retrofit2.Call
import retrofit2.Response
import retrofit2.http.GET
import kotlin.math.abs
interface ServerTimeApi {
/***
* 获取服务器时间戳
*/
@GET("api/v1/init/time")
fun getServerTime(): Call<ResponseBody>
}
data class ServerTimeData(var microtime: String?)
data class ServerTimeDataJson(var code: Int = 400, var msg: String?, var data: ServerTimeData?)
/**
* 本地时间与服务器时间的差值
*/
private var timeDiffForLocalAndService: Long = -1
/**
* 是否需要重新计算差值
*/
private fun isNeedRecalculateTimeDiff() = timeDiffForLocalAndService == -1L
/**
* 重置差值
*/
fun restTimeDiffForLocalAndService() {
timeDiffForLocalAndService = -1L
}
private val lock = Object()
fun requestServerTime() {
if(!isNeedRecalculateTimeDiff()){
return
}
synchronized(lock) {
if (isNeedRecalculateTimeDiff()) {
val currentTime = System.currentTimeMillis()
try {
val response: Response<ResponseBody> = HttpManager.getInstance().timeClient
.create(ServerTimeApi::class.java).getServerTime().execute()
if (response.isSuccessful) {
val responseBody = response.body()
if (responseBody != null) {
val bytes = responseBody.bytes()
val json = String(bytes)
val serverTimeDataJson: ServerTimeDataJson = Gson().fromJson(json, ServerTimeDataJson::class.java)
if (serverTimeDataJson.code in 200..299) {
var diff: Long = try {
(serverTimeDataJson.data?.microtime?.toLong() ?: currentTime) - currentTime
} catch (e: Exception) {
0L
}
val remainder = abs(diff) % 1000
if (diff < 0 && remainder > 0) {
// 正值时 防止 差值为-60 服务器毫米为 1990 客户端为 2060
// 计算秒时 服务端为1990/1000=1s,而客户端为(2060-60)/1000=2s的情况
diff = -(abs(diff) / 1000 + 1) * 1000
}
if (diff > 0 && remainder > 0) {
// 正值时 防止 差值为60时 服务器毫米为 2990 客户端为 2940
// 计算秒时 服务端为2990/1000=2s,而客户端为(2940+60)/1000=3s的情况
diff = (abs(diff) / 1000 - 1) * 1000
}
timeDiffForLocalAndService = diff
KLog.d("request","----------timeDiffForLocalAndService=${timeDiffForLocalAndService}")
}
}
}
} catch (e: Exception) {
e.printStackTrace()
}
}
}
}
fun getTimestamp(): Long {
if (isNeedRecalculateTimeDiff()) {
return System.currentTimeMillis()
}
return System.currentTimeMillis() + timeDiffForLocalAndService
}
package com.fry.base.viewmodel;
import android.app.Application;
import androidx.annotation.NonNull;
import me.goldze.mvvmhabit.base.BaseViewModel;
/**
* Created by jeme on 2019/2/19
*/
public class BaseWebViewModel extends BaseViewModel {
public BaseWebViewModel(@NonNull Application application) {
super(application);
}
}
package com.fry.base.viewmodel;
import android.app.Application;
import com.fry.base.bean.PageBean;
import androidx.annotation.NonNull;
import androidx.lifecycle.MutableLiveData;
import me.goldze.mvvmhabit.binding.command.BindingCommand;
/**
* @author jeme
* @date 2019/10/14
*/
public class LoadMoreViewModel extends RefreshViewModel {
protected int page = 1;
public MutableLiveData<Boolean> hasMore = new MutableLiveData<>();
public LoadMoreViewModel(@NonNull Application application) {
super(application);
hasMore.setValue(true);
}
public boolean isRefresh(){
return page == 1;
}
public BindingCommand onLoadMoreCommand = new BindingCommand(()->{
if(hasMore.getValue()) {
page++;
requestData(false);
}else{
// ToastUtils.showShort("仓主,没有更多了");
dismissDialog();
}
});
@Override
public void requestData() {
page = 1;
requestData(true);
}
protected void requestData(boolean isRefresh){}
protected void hasMoreData(PageBean pageInfo){
if (pageInfo == null){
hasMore.setValue(true);
}else{
hasMore.setValue(pageInfo.getPageNum() * pageInfo.getPageSize() < pageInfo.getTotal());
page = pageInfo.getPageNum();
}
/* if(page == 1){
hasMore.setValue(true);
}else{
if(data == null || data.size() == 0){
hasMore.setValue(false);
}else{
hasMore.setValue(true);
}
}*/
}
public int getPage(){
return page;
}
}
package com.fry.base.viewmodel;
import android.app.Application;
import androidx.annotation.NonNull;
import me.goldze.mvvmhabit.base.BaseViewModel;
import me.goldze.mvvmhabit.binding.command.BindingCommand;
/**
* @author jeme
* @date 2019/10/14
*/
public class RefreshViewModel extends BaseViewModel {
public RefreshViewModel(@NonNull Application application) {
super(application);
}
public BindingCommand onRefreshCommand = new BindingCommand(()->{
requestData();
});
public void requestData(){
}
}
#Wed Jun 30 13:02:29 CST 2021 #Wed Jun 30 14:54:57 CST 2021
VERSION_BUILD=2203 VERSION_BUILD=2207
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment