Commit a14cefe5 authored by fengruiyu's avatar fengruiyu

网络请求测试已完成

parent c60209a8
......@@ -16,7 +16,6 @@ android {
versionName rootProject.ext.android.versionName
//flavorDimensions "default"
buildConfigField ("boolean","IS_DEV","false")
//多个dex
multiDexEnabled true
......@@ -36,36 +35,25 @@ android {
// buildTypes {
// debug {
//
//
// //混淆
// minifyEnabled false
// //signingConfig signingConfigs.release
// zipAlignEnabled true
// versionNameSuffix "-dev"
// zipAlignEnabled false
// shrinkResources false//打开
//
// proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
// }
// release {
// minifyEnabled false
//
// //混淆
// minifyEnabled true
// zipAlignEnabled true
// shrinkResources false
// shrinkResources true
// //signingConfig signingConfigs.release
// proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
// }
// }
// productFlavors {
// // 开发版本
// auto {
// buildConfigField ('boolean','IS_DEV',"true")
// manifestPlaceholders = [
// app_logo_name: "Auto"
// ]
// }
// // 线上产品版本
// product {
// buildConfigField ('boolean','IS_DEV',"false")
// manifestPlaceholders = [
// app_logo_name: "线上"
// ]
// }
// }
}
dependencies {
......
......@@ -2,6 +2,11 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.mints.goodnews">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:name=".AppApplication"
android:allowBackup="true"
......@@ -9,8 +14,15 @@
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
android:theme="@style/AppTheme"
android:usesCleartextTraffic="true"
>
<activity android:name=".main.MainActivity">
</activity>
<activity android:name=".login.LoginActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
......
package com.mints.goodnews.api
import com.fry.base.netwrok.HttpManager
import com.mints.goodnews.bean.AwardBean
import com.mints.goodnews.bean.UserBean
import io.reactivex.Observable
import me.goldze.mvvmhabit.http.BaseResponse
import retrofit2.Response
import retrofit2.http.Body
import retrofit2.http.POST
/**
* Created by 冯瑞雨 on 2021/7/2.
*/
interface MainApi {
companion object{
fun newInstance(): MainApi {
return HttpManager.getInstance().defaultClient.create(MainApi::class.java)
}
}
/**
* 登录
*/
@POST("api/mobilelogin")
fun mobileLogin(@Body vo: @JvmSuppressWildcards Map<String, Any>): Observable<Response<BaseResponse<UserBean>>>
/**
* 获取用户配置信息
*
*/
@POST("api/getCoinMsg")
fun getCoinMsg(): Observable<Response<BaseResponse<AwardBean>>>
}
\ No newline at end of file
package com.mints.goodnews.bean
import android.annotation.SuppressLint
import android.os.Parcelable
import kotlinx.android.parcel.Parcelize
/**
*
* @author jyx
* @date 2021/4/7
* @des
*/
@SuppressLint("ParcelCreator")
@Parcelize
data class AwardBean(
var highCoin: Int = 0,
var showHigh: Boolean = false,
var coin: Int = 0,
var riskinfoRate: Boolean = false
) : Parcelable
\ No newline at end of file
package com.mints.goodnews.bean
import java.io.Serializable
/**
* 描述:用户信息
* 作者:孟崔广
* 时间:2019/10/29 18:42
* 邮箱:mengcga@163.com
*/
class UserBean : Serializable {
val token: String? = null
val toKeepAnAccount: String? = null
val consumer: ConsumerBean? = null
inner class ConsumerBean : Serializable {
val head: String? = null
val openid: String? = null
val nickname: String? = null
val mobile: String? = null
val real_name: String? = null
val alipay_account: String? = null
val idcode: String? = null
val gameInfo: String? = null
var sumCoin: String? = null
val surplus //余额
= 0.0
val coin // 积分
= 0
val pk_id // 用户id
: Long = 0
val isFirstSignInApp // 首次登录app true:首次
= false
}
}
package com.mints.goodnews.login
import android.os.Bundle
import com.fry.base.base.BaseActivity
import com.mints.goodnews.BR
import com.mints.goodnews.R
import com.mints.goodnews.databinding.ActivityLoginBinding
/**
* Created by 冯瑞雨 on 2021/7/2.
*/
class LoginActivity:BaseActivity<ActivityLoginBinding,LoginViewModel>() {
override fun initContentView(savedInstanceState: Bundle?) = R.layout.activity_login
override fun initVariableId() = BR.viewModel
override fun initData() {
super.initData()
binding.button.setOnClickListener {
viewModel.login()
}
}
}
\ No newline at end of file
package com.mints.goodnews.login
import android.app.Application
import com.fry.base.basenetwork.HttpSubscribeImpl
import com.mints.goodnews.bean.AwardBean
import com.mints.goodnews.bean.UserBean
import com.mints.goodnews.model.ApiModel
import me.goldze.mvvmhabit.base.BaseViewModel
import me.goldze.mvvmhabit.http.BaseResponse
import me.goldze.mvvmhabit.utils.KLog
import retrofit2.Response
/**
* Created by 冯瑞雨 on 2021/7/2.
*/
class LoginViewModel(application:Application):BaseViewModel(application) {
fun login(){
// val vo = hashMapOf<String, Any>()
// vo["shumeiId"] = ""
// vo["mobile"] = ""
// vo["smsCode"] = ""
// vo["device"] = ""
ApiModel.coinMsg(lifecycleProvider).safeSubscribe(
object : HttpSubscribeImpl<BaseResponse<AwardBean>>(
this@LoginViewModel,true){
override fun onBusinessSuccess(response: BaseResponse<AwardBean>) {
KLog.e("sfdsdf",response.result.toString())
}
})
}
}
\ No newline at end of file
package com.mints.goodnews.main.home
import android.app.Activity
import android.os.Bundle
import android.view.LayoutInflater
import android.view.ViewGroup
import com.fry.base.base.BaseFragment
import com.mints.goodnews.BR
import com.mints.goodnews.R
import com.mints.goodnews.databinding.ActivityMainBinding
import com.mints.goodnews.databinding.FragmentHomeBinding
/**
......
package com.mints.goodnews.model
import com.fry.base.netwrok.HttpManager
import com.mints.goodnews.api.MainApi
import com.mints.goodnews.bean.AwardBean
import com.mints.goodnews.bean.UserBean
import com.trello.rxlifecycle2.LifecycleProvider
import io.reactivex.Observable
import me.goldze.mvvmhabit.http.BaseResponse
import retrofit2.Response
/**
* Created by 冯瑞雨 on 2021/7/2.
*/
object ApiModel {
/**
* 登录
*/
fun login(lifecycleProvider: LifecycleProvider<Any>?
,map: Map<String, Any>): Observable<Response<BaseResponse<UserBean>>> {
return HttpManager.getInstance()
.execute(lifecycleProvider,MainApi.newInstance().mobileLogin(map))
}
/**
* 获取用户配置信息
*
*/
fun coinMsg(lifecycleProvider: LifecycleProvider<Any>?): Observable<Response<BaseResponse<AwardBean>>> {
return HttpManager.getInstance()
.execute(lifecycleProvider,MainApi.newInstance().getCoinMsg())
}
}
\ No newline at end of file
package com.mints.goodnews.widget;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnFocusChangeListener;
import android.view.animation.Animation;
import android.view.animation.CycleInterpolator;
import android.view.animation.TranslateAnimation;
import com.mints.goodnews.R;
import androidx.appcompat.widget.AppCompatEditText;
import androidx.core.content.ContextCompat;
public class ClearEditText extends AppCompatEditText implements
OnFocusChangeListener, TextWatcher {
/**
* 删除按钮的引用
*/
private Drawable mClearDrawable;
public Drawable getmClearDrawable() {
return mClearDrawable;
}
public ClearEditText(Context context) {
this(context, null);
}
public ClearEditText(Context context, AttributeSet attrs) {
//这里构造方法也很重要,不加这个很多属性不能再XML里面定义
this(context, attrs, android.R.attr.editTextStyle);
}
public ClearEditText(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init() {
//获取EditText的DrawableRight,假如没有设置我们就使用默认的图片
mClearDrawable = getCompoundDrawables()[2];
if (mClearDrawable == null) {
mClearDrawable = ContextCompat.getDrawable(getContext(), R.mipmap.ic_text_clear);
}
mClearDrawable.setBounds(0, 0, mClearDrawable.getIntrinsicWidth(), mClearDrawable.getIntrinsicHeight());
setClearIconVisible(false);
setOnFocusChangeListener(this);
addTextChangedListener(this);
}
/**
* 因为我们不能直接给EditText设置点击事件,所以我们用记住我们按下的位置来模拟点击事件
* 当我们按下的位置 在 EditText的宽度 - 图标到控件右边的间距 - 图标的宽度 和
* EditText的宽度 - 图标到控件右边的间距之间我们就算点击了图标,竖直方向没有考虑
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
if (getCompoundDrawables()[2] != null) {
if (event.getAction() == MotionEvent.ACTION_UP) {
boolean touchable = event.getX() > (getWidth()
- getPaddingRight() - mClearDrawable.getIntrinsicWidth())
&& (event.getX() < ((getWidth() - getPaddingRight())));
if (touchable) {
this.setText("");
}
}
}
return super.onTouchEvent(event);
}
/**
* 当ClearEditText焦点发生变化的时候,判断里面字符串长度设置清除图标的显示与隐藏
*/
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus) {
setClearIconVisible(getText().length() > 0);
} else {
setClearIconVisible(false);
}
}
/**
* 设置清除图标的显示与隐藏,调用setCompoundDrawables为EditText绘制上去
*
* @param visible
*/
protected void setClearIconVisible(boolean visible) {
Drawable right = visible ? mClearDrawable : null;
setCompoundDrawables(getCompoundDrawables()[0],
getCompoundDrawables()[1], right, getCompoundDrawables()[3]);
}
/**
* 当输入框里面内容发生变化的时候回调的方法
*/
@Override
public void onTextChanged(CharSequence s, int start, int count,
int after) {
setClearIconVisible(s.length() > 0);
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
}
@Override
public void afterTextChanged(Editable s) {
}
/**
* 设置晃动动画
*/
public void setShakeAnimation() {
this.setAnimation(shakeAnimation(5));
}
/**
* 晃动动画
*
* @param counts 1秒钟晃动多少下
* @return
*/
public static Animation shakeAnimation(int counts) {
Animation translateAnimation = new TranslateAnimation(0, 10, 0, 0);
translateAnimation.setInterpolator(new CycleInterpolator(counts));
translateAnimation.setDuration(1000);
return translateAnimation;
}
}
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<!-- 填充的颜色 -->
<solid android:color="@color/color_FF9837" />
<!-- 设置按钮的四个角为弧形 -->
<!-- android:radius 弧形的半径 -->
<corners android:radius="30dip" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="ViewModel"
type="com.mints.goodnews.login.LoginViewModel" />
</data>
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include layout="@layout/include_header" />
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="30dp"
android:layout_marginTop="30dp"
android:layout_marginRight="30dp"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/str_phone_num_1" />
<com.mints.goodnews.widget.ClearEditText
android:id="@+id/et_phone"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_marginStart="20dp"
android:background="@null"
android:gravity="center_vertical"
android:hint="@string/str_input_phone"
android:inputType="number"
android:maxLength="13"
android:maxLines="1"
android:textColor="@color/color_172B54"
android:textColorHint="@color/color_BEC2CC"
android:textSize="14sp" />
</androidx.appcompat.widget.LinearLayoutCompat>
<View
style="@style/line_3"
android:layout_marginStart="30dp"
android:layout_marginEnd="30dp" />
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="30dp"
android:layout_marginTop="10dp"
android:layout_marginEnd="30dp"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/str_sms_code_1" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_marginStart="20dp">
<com.mints.goodnews.widget.ClearEditText
android:id="@+id/et_sms"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerVertical="true"
android:layout_marginEnd="120dp"
android:background="@null"
android:hint="@string/str_input_sms"
android:inputType="number"
android:maxLength="4"
android:textColor="@color/color_172B54"
android:textColorHint="@color/color_BEC2CC"
android:textSize="14sp" />
<TextView
android:id="@+id/tv_send_sms"
android:layout_width="100dp"
android:layout_height="30dp"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:gravity="center"
android:text="@string/str_send_sms"
android:textColor="@color/color_FF9837"
android:textSize="14sp" />
</RelativeLayout>
</androidx.appcompat.widget.LinearLayoutCompat>
<View
style="@style/line_3"
android:layout_marginStart="30dp"
android:layout_marginEnd="30dp" />
<Button
android:id="@+id/button"
android:layout_width="match_parent"
android:layout_height="46dp"
android:layout_marginStart="40dp"
android:layout_marginTop="30dp"
android:layout_marginEnd="40dp"
android:background="@drawable/shape_main"
android:text="@string/str_immediately_login"
android:textColor="@color/white"
android:textSize="16sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="30dp"
android:layout_marginTop="20dp"
android:layout_marginRight="30dp"
android:text="@string/str_login_tint" />
</androidx.appcompat.widget.LinearLayoutCompat>
</layout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/include_header"
android:layout_width="match_parent"
android:layout_height="70dp"
android:paddingTop="25dp">
<ImageView
android:id="@+id/iv_left_icon"
android:layout_width="50dp"
android:layout_height="50dp"
android:padding="10dp"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_left_subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:lines="1"
android:maxLength="12"
android:padding="8dp"
android:textColor="@color/black"
android:textSize="18sp"
android:textStyle="bold"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:lines="1"
android:maxLength="12"
android:textColor="@color/color_121B32"
android:textSize="18sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/iv_right_icon2"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_marginEnd="10dp"
android:scaleType="center"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/iv_right_icon"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/iv_right_icon"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_marginEnd="10dp"
android:scaleType="center"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_right_subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="10dp"
android:textColor="@color/color_121B32"
android:textSize="16sp"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<View
style="@style/view_line_E6E6E6"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="@+id/iv_right_icon" />
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
......@@ -25,4 +25,15 @@
<item name="android:windowExitAnimation">@anim/slide_out_to_right</item>-->
</style>
<!--浅灰色line-->
<style name="view_line_E6E6E6">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">1dp</item>
<item name="android:background">@color/color_E6E6E6</item>
</style>
<style name="line_3">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">1px</item>
<item name="android:background">#E8E8F0</item>
</style>
</resources>
\ No newline at end of file
......@@ -51,9 +51,15 @@ android {
}
buildTypes {
release {
buildConfigField ("boolean","IS_DEV","true")
buildConfigField ("String","DEBUG_URL",DEBUG_URL)
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
debug{
buildConfigField ("boolean","IS_DEV","true")
buildConfigField ("String","DEBUG_URL",DEBUG_URL)
}
}
// productFlavors {
// //包含所有环境
......
......@@ -21,15 +21,15 @@ public class BaseApp extends BaseApplication {
@Override
public void onCreate() {
super.onCreate();
// boolean isMainProcess = AppUtils.isMainProcess(this);
// //初始化组件(靠前)
// ModuleLifecycleConfig.getInstance().initModuleAhead(this,isMainProcess);
// //线程管理类
// WorkTaskManager.getInstance().addWorkEventTask(() ->
// ModuleLifecycleConfig.getInstance().initModuleAsWork(BaseApp.this,isMainProcess));
// //....
// //初始化组件(靠后)
// ModuleLifecycleConfig.getInstance().initModuleLow(this,isMainProcess);
boolean isMainProcess = AppUtils.isMainProcess(this);
//初始化组件(靠前)
ModuleLifecycleConfig.getInstance().initModuleAhead(this,isMainProcess);
//线程管理类
WorkTaskManager.getInstance().addWorkEventTask(() ->
ModuleLifecycleConfig.getInstance().initModuleAsWork(BaseApp.this,isMainProcess));
//....
//初始化组件(靠后)
ModuleLifecycleConfig.getInstance().initModuleLow(this,isMainProcess);
}
......
......@@ -10,6 +10,8 @@ import com.tencent.bugly.crashreport.CrashReport;
import me.goldze.mvvmhabit.utils.KLog;
import me.goldze.mvvmhabit.utils.SPUtils2;
import me.goldze.mvvmhabit.utils.ToastUtils;
import com.fry.base.BuildConfig;
/**
* Created by goldze on 2018/6/21 0021.
......@@ -21,14 +23,14 @@ public class BaseModuleInit implements IModuleInit<Void> {
public boolean onInitAhead(Application application,boolean isMainProcess) {
//开启打印日志
// KLog.init(BuildConfig.DEBUG);
// //初始化阿里路由框架
// if (BuildConfig.DEBUG) {
// ARouter.openLog(); // 打印日志
// ARouter.openDebug(); // 开启调试模式(如果在InstantRun模式下运行,必须开启调试模式!线上版本需要关闭,否则有安全风险)
// }
KLog.init(BuildConfig.DEBUG);
//初始化阿里路由框架
if (BuildConfig.DEBUG) {
ARouter.openLog(); // 打印日志
ARouter.openDebug(); // 开启调试模式(如果在InstantRun模式下运行,必须开启调试模式!线上版本需要关闭,否则有安全风险)
}
// 尽可能早,推荐在Application中初始化
ARouter.init(application);
// ARouter.init(application);
ToastUtils.setGravity(Gravity.CENTER,0,0);
return false;
......
......@@ -51,9 +51,9 @@ public class RetrofitClient {
OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder()
.cookieJar(new CookieJarImpl(new PersistentCookieStore(mContext)))
// .cache(cache)
.addInterceptor(new OkHttpInterceptor(AESUtils.getDefaultKey()))
// .addInterceptor()
// .addInterceptor(new CacheInterceptor(mContext))
.sslSocketFactory(sslParams.sSLSocketFactory, sslParams.trustManager)
// .sslSocketFactory(sslParams.sSLSocketFactory, sslParams.trustManager)
.connectTimeout(mHttpConfig.getTimeOut(), TimeUnit.SECONDS)
.writeTimeout(mHttpConfig.getTimeOut(), TimeUnit.SECONDS)
.readTimeout(mHttpConfig.getTimeOut(), TimeUnit.SECONDS)
......
package com.fry.base.global;
import com.fry.base.BuildConfig;
/**
* Created by jeme on 2019/9/17
*/
......@@ -54,8 +56,7 @@ public class Constants {
}
public static String getBaseUrl() {
//fry
// return PropertyUtils.getApiBaseUrl();
return "";
return BuildConfig.DEBUG_URL;
}
}
\ No newline at end of file
......@@ -39,11 +39,11 @@ public class HttpErrorProcess {
if (response.body() == null) {
return response;
}
if (response.body().getCode() == 401 || response.body().getCode() == 403) {//未登录 token 过期
if (response.body().getstatus() == 401 || response.body().getstatus() == 403) {//未登录 token 过期
// IUserService.getInstance().loginInvalid();
// IUserService.getInstance().navToLogin(AppManager.getAppManager().getCurrentActivity(), null);
return null;
} else if (response.body().getCode() == 550) {
} else if (response.body().getstatus() == 550) {
//签名错误
// ToastUtils.showShort(R.string.app_update_toast_tip);
/*ToastUtils.showShort("请从正规渠道下载App");
......@@ -65,8 +65,8 @@ public class HttpErrorProcess {
@Override
public BaseResponse<T> apply(BaseResponse<T> response) {
*//* if(response.body().getCode() == 412506){//门店未注册
}else if(response.body().getCode() == 412539) {//用户未注册
*//* if(response.body().getstatus() == 412506){//门店未注册
}else if(response.body().getstatus() == 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.fry.base.utils.encry.AESUtils;
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;
......@@ -47,7 +42,7 @@ public class HttpManager {
private HttpManager() {
mDefaultClient = new RetrofitClient(
HttpConfiguation.create(Constants.getBaseUrl())
.addInterceptor(new PublicHeaderInterceptor())
.addInterceptor(new OkHttpInterceptor(AESUtils.getDefaultKey()))
);
}
......@@ -69,11 +64,11 @@ public class HttpManager {
}
public <B extends BaseResponse, T extends Response<B>>
Observable<T> execute(LifecycleProvider life,final Observable<T> observable) {
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();
// ServerTimeHelper.requestServerTime();
return observable;
})
.observeOn(AndroidSchedulers.mainThread());
......@@ -88,14 +83,14 @@ public class HttpManager {
@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())
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();
// ServerTimeHelper.requestServerTime();
return observable;
})
.observeOn(AndroidSchedulers.mainThread());
.observeOn(AndroidSchedulers.mainThread());
if (life != null) {
newObservable = newObservable.compose(RxUtils.bindToLifecycle(life));
}
......
......@@ -31,7 +31,7 @@ class OkHttpInterceptor(aesKey: String) : Interceptor {
@Throws(IOException::class)
override fun intercept(chain: Interceptor.Chain): Response {
// val tokenID: String = UserManager.INSTANCE.getTokenID()
val tokenID: String = ""
val tokenID: String = "647ECC8C40A7238E012703044D60D0D95599F1AD1833C4D29670487710D12D315F433703067DF5142735505C42F58997"
val time = System.currentTimeMillis()
val channel = createChannel()
var request = chain.request()
......
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
}
#Thu Jul 01 19:22:36 CST 2021
VERSION_BUILD=2459
#Mon Jul 05 10:39:48 CST 2021
VERSION_BUILD=2517
......@@ -20,8 +20,8 @@ public class BaseApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
// setApplication(this);
// SPUtils2.init(this);
setApplication(this);
SPUtils2.init(this);
}
/**
......
......@@ -47,7 +47,7 @@ public abstract class ApiDisposableObserver<T> extends DisposableObserver<T> {
@Override
public void onNext(Object o) {
BaseResponse baseResponse = (BaseResponse) o;
switch (baseResponse.getCode()) {
switch (baseResponse.getstatus()) {
case CodeRule.CODE_200:
//请求成功, 正确的操作方式
onResult((T) baseResponse.getResult());
......@@ -59,7 +59,7 @@ public abstract class ApiDisposableObserver<T> extends DisposableObserver<T> {
case CodeRule.CODE_300:
//请求失败,不打印Message
KLog.e("请求失败");
ToastUtils.showShort("错误代码:", baseResponse.getCode());
ToastUtils.showShort("错误代码:", baseResponse.getstatus());
break;
case CodeRule.CODE_330:
//请求失败,打印Message
......@@ -67,7 +67,7 @@ public abstract class ApiDisposableObserver<T> extends DisposableObserver<T> {
break;
case CodeRule.CODE_500:
//服务器内部异常
ToastUtils.showShort("错误代码:", baseResponse.getCode());
ToastUtils.showShort("错误代码:", baseResponse.getstatus());
break;
case CodeRule.CODE_503:
//参数为空
......@@ -89,10 +89,10 @@ public abstract class ApiDisposableObserver<T> extends DisposableObserver<T> {
ToastUtils.showShort("请先登录");
break;
case CodeRule.CODE_551:
ToastUtils.showShort("错误代码:", baseResponse.getCode());
ToastUtils.showShort("错误代码:", baseResponse.getstatus());
break;
default:
ToastUtils.showShort("错误代码:", baseResponse.getCode());
ToastUtils.showShort("错误代码:", baseResponse.getstatus());
break;
}
}
......
......@@ -10,8 +10,7 @@ import com.google.gson.annotations.SerializedName;
* 该类仅供参考,实际业务返回的固定字段, 根据需求来定义,
*/
public class BaseResponse<T> {
private int code;
@SerializedName("msg")
private int status;
private String message;
// @JsonAdapter(value = JsonAdapterGsonDeserializer.class)
......@@ -21,18 +20,18 @@ public class BaseResponse<T> {
public BaseResponse() {
}
public BaseResponse(int code, String message, T result) {
this.code = code;
public BaseResponse(int status, String message, T result) {
this.status = status;
this.message = message;
this.result = result;
}
public int getCode() {
return code;
public int getstatus() {
return status;
}
public void setCode(int code) {
this.code = code;
public void setstatus(int status) {
this.status = status;
}
public T getResult() {
......@@ -44,7 +43,7 @@ public class BaseResponse<T> {
}
public boolean isOk() {
return code >= 200 && code < 300;
return status >= 200 && status < 300;
}
public String getMessage() {
......@@ -58,7 +57,7 @@ public class BaseResponse<T> {
@Override
public String toString() {
return "BaseResponse{" +
"code=" + code +
"status=" + status +
", message='" + message + '\'' +
", result=" + result +
'}';
......
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