feat: 初始化项目结构和基本功能

- 创建项目根目录和主要子模块
- 添加基本的 Activity 和布局文件
- 实现简单的导航和电话拨打功能
- 添加相机和图像处理相关代码
- 创建网络请求和数据加密工具类
- 设置 AndroidManifest 文件和权限
This commit is contained in:
songzhiling
2025-04-11 11:52:07 +08:00
parent 74ce8fc526
commit 91305ab9d1
386 changed files with 36517 additions and 34 deletions

View File

@ -0,0 +1,123 @@
package com.za.net;
import android.util.Base64;
import java.nio.charset.StandardCharsets;
import java.util.Random;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
public class AESUtils {
private static final String cipherMode = "AES/ECB/PKCS5Padding";//算法/模式/补码方式
/* AES秘钥支持128bit/192bit/256bit三种长度的秘钥一个字节等于8bit
* 因此支持生成的字符串的长度应该是 16/24/32
* */
private static final int keyLength = 16;
// public static void main(String[] args) {
//
// /*构建一个随机密码*/
// String key = getRandomKey(keyLength);
// System.out.println("随机生成的key" + key);
//
// String data = "{'fig':1,'message':'登录成功'}";
//
// try {
// String encriptData = AESUtils.encrypt(data, key);
// System.out.println("加密后的数据:" + encriptData);
//
// String decryptData = decrypt(encriptData, key);
//
// System.out.println("解密后的数据:" + decryptData);
//
// } catch (Exception e) {
// e.printStackTrace();
// }
//
// }
/**
* @param length 需要生成的字符串长度
* @return 随机生成的字符串
*/
public static String getRandomKey(int length) {
if (length != 16 && length != 24 && length != 32) {
System.out.println("长度必须为16/24/32");
return null;
}
String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
Random random = new Random();
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < length; i++) {
int number = random.nextInt(62);
stringBuilder.append(str.charAt(number));
}
return stringBuilder.toString();
}
/**
* @param data 需要加密的数据
* @param key 加密使用的key
* @return 加密后的数据(Base64编码)
* @throws Exception
*/
public static String encrypt(String data, String key) throws Exception {
int length = key.length();
if (length != 16 && length != 24 && length != 32) {
System.out.println("长度必须为16/24/32");
return null;
}
byte[] raw = key.getBytes(StandardCharsets.UTF_8);
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance(cipherMode);
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
byte[] encrypted = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
return Base64.encodeToString(encrypted, Base64.URL_SAFE | Base64.NO_WRAP);
}
/**
* @param data 需要解密的数据
* @param key 解密用的key
* @return 解密后的数据
* @throws Exception
*/
public static String decrypt(String data, String key) throws Exception {
try {
int length = key.length();
if (length != 16 && length != 24 && length != 32) {
System.out.println("长度必须为16/24/32");
return null;
}
byte[] raw = key.getBytes(StandardCharsets.UTF_8);
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance(cipherMode);
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
byte[] encrypted = Base64.decode(data,Base64.URL_SAFE | Base64.NO_WRAP);//先用base64解密
try {
byte[] original = cipher.doFinal(encrypted);
return new String(original, StandardCharsets.UTF_8);
} catch (Exception e) {
System.out.println(e.toString());
return null;
}
} catch (Exception ex) {
System.out.println(ex.toString());
return null;
}
}
}

View File

@ -0,0 +1,265 @@
package com.za.net
import com.za.bean.BaseResponse
import com.za.bean.BatteryCostQueryBean
import com.za.bean.BatteryCostQueryRequest
import com.za.bean.ChangeBatteryResponse
import com.za.bean.DriverIdentityAuthWebBean
import com.za.bean.DriverIdentityAuthWebRequest
import com.za.bean.DriverInfo
import com.za.bean.FetchChangeBatteryPhotoRequest
import com.za.bean.GeneralInfo
import com.za.bean.HistoryPhotoTemplates
import com.za.bean.HistoryTaskBean
import com.za.bean.ImageBean
import com.za.bean.JpushBean
import com.za.bean.LoginWithTaskBean
import com.za.bean.LoginWithTaskRequest
import com.za.bean.NewOrderRequestBean
import com.za.bean.PaymentInfoBean
import com.za.bean.ReportHistoryBean
import com.za.bean.ReportHistoryRequest
import com.za.bean.ReportInfoRequest
import com.za.bean.ReportItem
import com.za.bean.SettleInfoRequest
import com.za.bean.TaskSettlementAndTraceBean
import com.za.bean.UpdateVersionBean
import com.za.bean.UpdateVersionRequest
import com.za.bean.UploadChangeBatteryRequest
import com.za.bean.VehicleInfo
import com.za.bean.db.order.OrderInfo
import com.za.bean.db.order.PhotoTemplateInfo
import com.za.bean.request.AcceptOrderRequest
import com.za.bean.request.CustomerPaymentCreateBean
import com.za.bean.request.CustomerPaymentCreateRequest
import com.za.bean.request.DriverFaceCompareBean
import com.za.bean.request.DriverFaceCompareRequest
import com.za.bean.request.ElectronOrderResponse
import com.za.bean.request.FetchVehicleMaintenanceSubmitHistoryRequestBean
import com.za.bean.request.GeneralInfoRequest
import com.za.bean.request.GiveUpTaskRequest
import com.za.bean.request.HistoryDetailRequest
import com.za.bean.request.HistoryPhotoTemplateRequest
import com.za.bean.request.HistoryTasksRequest
import com.za.bean.request.LoginRequest
import com.za.bean.request.OrderListRequest
import com.za.bean.request.OrderPhotoOcrRecognizeRequest
import com.za.bean.request.PaymentInfoRequest
import com.za.bean.request.PaymentUpdateRequest
import com.za.bean.request.PhotoTemplateRequest
import com.za.bean.request.QueryEleOrderRequest
import com.za.bean.request.RecognizeRefuelOcrRequestBean
import com.za.bean.request.RecognizeRefuelTicketBean
import com.za.bean.request.RecognizeRefuelTicketRequestBean
import com.za.bean.request.RefuseOrderRequest
import com.za.bean.request.SaveEleOrderRequest
import com.za.bean.request.SwitchTaskRequest
import com.za.bean.request.TaskFinishRequest
import com.za.bean.request.TaskFinishResponse
import com.za.bean.request.TodayMaintainRequest
import com.za.bean.request.TodayMaintainUploadRequest
import com.za.bean.request.TodayMaintainbean
import com.za.bean.request.UpdateOrderConfirmTaskRequest
import com.za.bean.request.UpdatePhotoRequest
import com.za.bean.request.UpdateTaskBean
import com.za.bean.request.UpdateTaskRequest
import com.za.bean.request.UpdateVehicleStateRequest
import com.za.bean.request.UploadGpsRequest
import com.za.bean.request.UploadPhotoBean
import com.za.bean.request.VehicleListRequest
import com.za.bean.request.VehicleLogoutRequest
import com.za.bean.request.VehicleMaintenanceHistoryBean
import com.za.bean.request.VehicleMaintenanceSubmitRequest
import com.za.bean.request.VehicleRepairBean
import com.za.bean.request.VehicleRepairPointMatcherItem
import com.za.bean.request.VehicleRepairPointMatcherListRequest
import com.za.bean.request.VerifyCodeRequest
import com.za.bean.request.VerifyCodeResponse
import com.za.call.ContactRecordRequest
import com.za.water_marker.bean.MyWaterMarkerTemplateBean
import com.za.water_marker.bean.WaterMarkerRequestBean
import io.reactivex.rxjava3.core.Observable
import okhttp3.MultipartBody
import retrofit2.http.Body
import retrofit2.http.Multipart
import retrofit2.http.POST
import retrofit2.http.Part
interface ApiService {
//获取车辆列表
@POST("/driverApp/supplier/listVehicleNew")
fun getVehicleList(@Body info : VehicleListRequest) : Observable<BaseResponse<List<VehicleInfo>>>
//更改车辆状态
@POST("/driverApp/task/switchVehicleStatus")
fun newUpdateVehicleState(@Body info : UpdateVehicleStateRequest) : Observable<BaseResponse<String>>
@POST("/driverApp/v2/user/generalInfo")
fun generalInfo(@Body info : GeneralInfoRequest) : Observable<BaseResponse<GeneralInfo>>
@POST("/driverApp/base/appVersion")
fun getUpdate(@Body versionRequest : UpdateVersionRequest) : Observable<BaseResponse<UpdateVersionBean>>
@POST("/driverApp/base/getVerifyCode")
fun getVerifyCode(@Body verifyCodeRequest : VerifyCodeRequest) : Observable<BaseResponse<VerifyCodeResponse>>
@Multipart
@POST("/order/uploadImage")
fun uploadImage(@Part part : MultipartBody.Part) : Observable<ImageBean>
@POST("/driverApp/task/uploadContactRecord")
fun uploadContactRecord(@Body contactRecordRequest : ContactRecordRequest?) : Observable<BaseResponse<String>>
@POST("/driverApp/task/login")
fun login(@Body info : LoginRequest) : Observable<BaseResponse<DriverInfo?>>
@POST("/driverApp/task/loginWithTask")
fun loginWithTask(@Body loginWithTaskRequest : LoginWithTaskRequest) : Observable<BaseResponse<LoginWithTaskBean>>
@POST("/driverApp/supplier/vehicleLogout")
fun vehicleLogout(@Body info : VehicleLogoutRequest) : Observable<BaseResponse<String>>
//当前订单列表
@POST("/driverApp/v2/task/listCurrentTask")
fun queryOrderList(@Body info : OrderListRequest) : Observable<BaseResponse<List<OrderInfo>?>>
@POST("/driverApp/task/getNewOrder")
fun getNewOrder(@Body newOrderRequestBean : NewOrderRequestBean) : Observable<BaseResponse<JpushBean>>
@POST("/driverApp/supplier/uploadGps")
fun uploadGps(@Body info : UploadGpsRequest) : Observable<BaseResponse<String>>
//获取报备内容列表
@POST("/driverApp/base/getReportTemplates")
fun getReportTemplates() : Observable<BaseResponse<List<ReportItem>>>
//提交报备
@POST("/driverApp/task/submitReport")
fun submitReport(@Body reportInfoRequest : ReportInfoRequest) : Observable<BaseResponse<String>>
//历史报备内容
@POST("/driverApp/task/reportHistory")
fun getReportHistory(@Body reportHistoryRequest : ReportHistoryRequest) : Observable<BaseResponse<List<ReportHistoryBean>>>
//拒绝任务
@POST("/driverApp/task/refuseTask")
fun refuseOrder(@Body request : RefuseOrderRequest) : Observable<BaseResponse<String>>
//接受任务
@POST("/driverApp/task/acceptTask")
fun acceptOrder(@Body request : AcceptOrderRequest) : Observable<BaseResponse<String>>
//更新任务
@POST("/driverApp/v4/task/updateTask")
fun updateTask(@Body request : UpdateTaskRequest) : Observable<BaseResponse<UpdateTaskBean>>
//更新任务
@POST("/driverApp/v4/task/updateTask")
fun submitOrderConfirmTask(@Body request : UpdateOrderConfirmTaskRequest) : Observable<BaseResponse<UpdateTaskBean>>
@POST("/driverApp/v2/supplier/photoTemplate")
fun fetchPhotoTemplate(@Body request : PhotoTemplateRequest) : Observable<BaseResponse<List<PhotoTemplateInfo>>>
@POST("/driverApp/supplier/getWatermarkTemplateConfig")
fun getWatermarkTemplateConfig(@Body request : WaterMarkerRequestBean) : Observable<BaseResponse<MyWaterMarkerTemplateBean>>
@POST("/driverApp/supplier/orderPhotoOcrRecognize")
fun orderPhotoOcrRecognize(@Body info : OrderPhotoOcrRecognizeRequest) : Observable<BaseResponse<String>>
@POST("/driverApp/v4/supplier/saveElectronOrder")
fun saveElectronOrder(@Body info : SaveEleOrderRequest?) : Observable<BaseResponse<String>>
@POST("/driverApp/supplier/queryElectronOrder")
fun queryElectronOrder(@Body info : QueryEleOrderRequest?) : Observable<BaseResponse<ElectronOrderResponse>>
//查询支付信息
@POST("/driverApp/payment/paymentInfoQuery")
fun paymentInfoQuery(@Body info : PaymentInfoRequest?) : Observable<BaseResponse<PaymentInfoBean>>
@POST("/driverApp/payment/customerPaymentCreate")
fun customerPaymentCreate(@Body customerPaymentCreateRequest : CustomerPaymentCreateRequest) : Observable<BaseResponse<CustomerPaymentCreateBean>>
@POST("/driverApp/payment/paymentAmountUpdate")
fun paymentAmountUpdate(@Body paymentUpdateRequest : PaymentUpdateRequest) : Observable<BaseResponse<String>>
@POST("/driverApp/battery/saveReplaceBatteryPhoto")
fun saveReplaceBatteryPhoto(@Body info : UploadChangeBatteryRequest) : Observable<BaseResponse<String>>
@POST("/driverApp/supplier/getReplaceBatteryPhoto")
fun getReplaceBatteryPhoto(@Body info : FetchChangeBatteryPhotoRequest) : Observable<BaseResponse<List<ChangeBatteryResponse>>>
//电瓶费用查询
@POST("/driverApp/battery/batteryCostQuery")
fun batteryCostQuery(@Body info : BatteryCostQueryRequest) : Observable<BaseResponse<BatteryCostQueryBean>>
@POST("/driverApp/v4/task/taskFinish")
fun taskFinish(@Body info : TaskFinishRequest) : Observable<BaseResponse<TaskFinishResponse>>
@POST("/driverApp/task/giveUpTask")
fun giveUpTask(@Body info : GiveUpTaskRequest) : Observable<BaseResponse<String>>
//历史订单补传照片
@POST("/driverApp/task/updatePhoto")
fun addPhoto(@Body params : UpdatePhotoRequest) : Observable<BaseResponse<UploadPhotoBean>>
@POST("/driverApp/v2/task/switchTask")
fun switchTask(@Body info : SwitchTaskRequest) : Observable<BaseResponse<String>>
@POST("/driverApp/task/listHistoryTaskNew")
fun getHistory(@Body info : HistoryTasksRequest) : Observable<BaseResponse<List<HistoryTaskBean>>>
@POST("/driverApp/task/getHistoryTaskPhotos")
fun getHistoryTaskPhotos(@Body info : HistoryPhotoTemplateRequest) : Observable<BaseResponse<List<HistoryPhotoTemplates>>>
//历史结算单和轨迹
@POST("/driverApp/task/getTaskSettlementAndTrace")
fun getTaskSettlementAndTrace(@Body info : HistoryDetailRequest) : Observable<BaseResponse<TaskSettlementAndTraceBean>>
@POST("driverApp/task/updateSettleInfo")
fun updateSettleInfo(@Body settleInfoRequest : SettleInfoRequest) : Observable<BaseResponse<String>>
//人脸比对
@POST("driverApp/supplier/driverFaceCompare")
fun driverFaceCompare(@Body driverFaceCompareRequest : DriverFaceCompareRequest) : Observable<BaseResponse<DriverFaceCompareBean>>
@POST("driverApp/supplier/driverIdentityAuthWeb")
fun driverIdentityAuthWeb(@Body request : DriverIdentityAuthWebRequest) : Observable<BaseResponse<DriverIdentityAuthWebBean>>
//今日保养
@POST("driverApp/supplier/getTodayMaintain")
fun getTodayMaintain(@Body info : TodayMaintainRequest) : Observable<BaseResponse<List<TodayMaintainbean>>>
//今日保养
@POST("driverApp/supplier/uploadTodayMaintain")
fun uploadTodayMaintain(@Body params : TodayMaintainUploadRequest) : Observable<BaseResponse<String>>
//加油小票识别
@POST("driverApp/supplier/recognizeRefuelTicket")
fun recognizeRefuelTicket(@Body bean : RecognizeRefuelOcrRequestBean?) : Observable<BaseResponse<RecognizeRefuelTicketBean>>
//提交加油记录
@POST("driverApp/supplier/vehicleRefuelSubmit")
fun vehicleRefuelSubmit(@Body info : RecognizeRefuelTicketRequestBean?) : Observable<BaseResponse<String>>
//获取车辆维保记录
@POST("driverApp/supplier/v2/getVehicleMaintenanceSubmit")
fun getVehicleMaintenanceSubmit(@Body info : FetchVehicleMaintenanceSubmitHistoryRequestBean) : Observable<BaseResponse<VehicleRepairBean>>
//获取车辆维保详细信息
@POST("driverApp/supplier/v2/getVehicleMaintenanceDetail")
fun getVehicleRepairDetail(@Body info : FetchVehicleMaintenanceSubmitHistoryRequestBean) : Observable<BaseResponse<VehicleRepairBean>>
//维修地点匹配
@POST("driverApp/supplier/v2/vehicleRepairPointMatcherList")
fun vehicleRepairPointMatcherList(@Body info : VehicleRepairPointMatcherListRequest) : Observable<BaseResponse<List<VehicleRepairPointMatcherItem>>>
//提交维保记录
@POST("driverApp/supplier/v2/vehicleMaintenanceSubmit")
fun vehicleMaintenanceSubmit(@Body info : VehicleMaintenanceSubmitRequest) : Observable<BaseResponse<String>>
//获取车辆维修历史
@POST("/driverApp/supplier/v2/vehicleMaintenanceList")
fun vehicleMaintenanceList(@Body info : FetchVehicleMaintenanceSubmitHistoryRequestBean) : Observable<BaseResponse<List<VehicleMaintenanceHistoryBean>>>
}

View File

@ -0,0 +1,127 @@
package com.za.net
import android.net.ParseException
import com.blankj.utilcode.util.ActivityUtils
import com.blankj.utilcode.util.NetworkUtils
import com.blankj.utilcode.util.ToastUtils
import com.google.gson.JsonParseException
import com.za.base.Const
import com.za.bean.BaseResponse
import com.za.common.GlobalData
import com.za.common.log.LogUtil
import com.za.service.location.ZdLocationManager
import io.reactivex.rxjava3.core.Observer
import io.reactivex.rxjava3.disposables.Disposable
import org.json.JSONException
import java.net.ConnectException
import java.net.SocketTimeoutException
import java.net.UnknownHostException
import java.util.concurrent.TimeoutException
import javax.net.ssl.SSLHandshakeException
/**
* Created by DoggieX on 2017/7/26.
*/
abstract class BaseObserver<T> : Observer<BaseResponse<T>> {
override fun onSubscribe(d: Disposable) {
// if (!NetworkUtils.isAvailable()) {
// doFailure(999, "网络无法使用")
// d.dispose()
// }
}
override fun onNext(tBaseResponse: BaseResponse<T>) {
if (tBaseResponse.isOk) {
doSuccess(tBaseResponse.result)
} else {
when (tBaseResponse.code) {
3, 401 -> handlerTokenExpired()
// 4 -> RsaRouter.navigate(context, "/page/Standby")
}
if (null != tBaseResponse.msg) {
doFailure(tBaseResponse.code, tBaseResponse.msg)
} else if (null != tBaseResponse.message) {
doFailure(tBaseResponse.code, tBaseResponse.message)
} else {
doFailure(tBaseResponse.code, "error")
}
}
}
override fun onError(e: Throwable) {
LogUtil.print("net error", e)
when (e) {
is JsonParseException -> {
doFailure(1, "数据解析错误")
}
is JSONException -> {
doFailure(1, "数据解析错误")
}
is ParseException -> {
doFailure(1, "数据解析错误")
}
is ConnectException -> {
doFailure(Const.NetWorkException, "与服务器断开连接")
}
is UnknownHostException -> {
doFailure(Const.NetWorkException, "与服务器断开连接")
}
is SSLHandshakeException -> {
doFailure(1, "证书验证失败")
LogUtil.print("SSLHandshakeException", e)
}
is TimeoutException -> {
doFailure(Const.NetWorkException, "网络连接超时1")
LogUtil.print("TimeoutException", e)
}
is SocketTimeoutException -> {
doFailure(Const.NetWorkException, "网络连接超时2")
LogUtil.print("SocketTimeoutException2", e)
}
else -> {
doFailure(1, "error:" + e.message)
LogUtil.print("other error", e)
}
}
}
override fun onComplete() {
}
abstract fun doSuccess(it: T?)
abstract fun doFailure(code: Int, msg: String?)
private fun handlerTokenExpired() {
ToastUtils.showShort("登陆信息已过期,请重新登录")
try {
GlobalData.clearUserCache()
ZdLocationManager.stopContinuousLocation()
ActivityUtils.finishAllActivities()
// val oldLoginInfo: LoginInfo = DbManager.getInstance(context).queryLoginInfo()
// val loginInfo: LoginInfo = LoginInfo()
// loginInfo.setSupplierId(oldLoginInfo.getSupplierId())
// loginInfo.setSupplierCode(oldLoginInfo.getSupplierCode())
// loginInfo.setJobNumber(oldLoginInfo.getJobNumber())
// loginInfo.setPassword(oldLoginInfo.getPassword())
// DbManager.getInstance(context).deleteLoginInfo()
// DbManager.getInstance(context).saveLoginInfo(loginInfo)
// SPKit.saveString(context, "userId", "-1")
// SPKit.saveString(context, "vehicleId", "-1")
//
// LBSManager.getInstance().cancel()
// DaemonService.stopService()
// //跳转
// RsaRouter.navigateNoFlag(context, "/page/login")
} catch (e: Exception) {
LogUtil.print("handlerTokenExpired", e)
}
}
}

View File

@ -0,0 +1,405 @@
package com.za.net
import android.content.Context
import android.graphics.BitmapFactory
import com.blankj.utilcode.util.ActivityUtils
import com.blankj.utilcode.util.ImageUtils
import com.za.base.Const
import com.za.bean.DriverInfo
import com.za.bean.GeneralInfo
import com.za.bean.ImageBean
import com.za.bean.JpushBean
import com.za.bean.NewOrderRequestBean
import com.za.bean.VehicleInfo
import com.za.bean.db.ele.EleCarDamagePhotoBean
import com.za.bean.db.ele.EleWorkOrderBean
import com.za.bean.db.order.OrderInfo
import com.za.bean.db.order.PhotoTemplateInfo
import com.za.bean.request.ElectronOrderResponse
import com.za.bean.request.GeneralInfoRequest
import com.za.bean.request.OrderListRequest
import com.za.bean.request.PhotoTemplateRequest
import com.za.bean.request.QueryEleOrderRequest
import com.za.bean.request.UpdateTaskBean
import com.za.bean.request.UpdateTaskRequest
import com.za.bean.request.UploadGpsRequest
import com.za.common.GlobalData
import com.za.common.log.LogUtil
import com.za.common.util.DeviceUtil
import com.za.ext.toJson
import com.za.offline.OfflineManager
import com.za.room.RoomHelper
import com.za.ui.new_order.NewOrderActivity
import com.za.ui.order_report.ReportFloatingManager
import com.za.water_marker.WaterMarkerTemplateManager
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.core.Observer
import io.reactivex.rxjava3.disposables.Disposable
import io.reactivex.rxjava3.schedulers.Schedulers
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.MultipartBody
import okhttp3.RequestBody.Companion.asRequestBody
import java.io.File
object CommonMethod {
fun uploadGps(uploadGpsRequest : UploadGpsRequest,
success : () -> Unit = {},
failed : (String?) -> Unit = {}) {
RetrofitHelper.getDefaultService().uploadGps(uploadGpsRequest).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()).subscribe(object : BaseObserver<String>() {
override fun doSuccess(it : String?) {
success()
LogUtil.print("uploadGps", uploadGpsRequest.toString())
}
override fun doFailure(code : Int, msg : String?) {
failed(msg)
LogUtil.print("uploadGps", "failed==$msg")
}
})
}
fun uploadImage(file : File,
preview : () -> Unit = {},
success : (String?) -> Unit = {},
failed : (String?) -> Unit = {}) {
file.writeBytes(ImageUtils.compressByQuality(BitmapFactory.decodeStream(file.inputStream()),
Const.Image_Max_length,
true))
val requestFile = file.asRequestBody("image/*".toMediaTypeOrNull())
val body = MultipartBody.Part.createFormData("file", file.name, requestFile)
preview()
RetrofitHelper.getDefaultService().uploadImage(body).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()).subscribe(object : Observer<ImageBean> {
override fun onSubscribe(d : Disposable) {
}
override fun onError(e : Throwable) {
failed(e.message)
LogUtil.print("uploadImage", e)
}
override fun onComplete() {
}
override fun onNext(t : ImageBean) {
if (t.isOk()) {
success(t.data)
return
}
failed(t.msg)
LogUtil.print("uploadImage failed", t.toJson() ?: "")
}
})
}
//更新订单状态
fun updateTask(taskRequest : UpdateTaskRequest,
success : (UpdateTaskBean?) -> Unit,
failed : (String?, Int) -> Unit) {
RetrofitHelper.getDefaultService().updateTask(taskRequest).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : BaseObserver<UpdateTaskBean>() {
override fun doSuccess(it : UpdateTaskBean?) {
success(it)
LogUtil.print("updateTask", "success=$it request=${taskRequest.toJson()}")
}
override fun doFailure(code : Int, msg : String?) {
failed(msg, code)
LogUtil.print("updateTask", "doFailure=$msg request=${taskRequest.toJson()}")
}
})
}
fun getGenerateInfo(vehicleId : Int? = null,
userId : Int? = null,
success : (GeneralInfo) -> Unit = {},
failed : (String?) -> Unit = {}) {
val generalInfoRequest =
GeneralInfoRequest(vehicleId = vehicleId ?: GlobalData.vehicleInfo?.vehicleId,
driverId = userId ?: GlobalData.driverInfo?.userId,
deviceId = DeviceUtil.getAndroidId(ActivityUtils.getTopActivity()))
RetrofitHelper.getDefaultService().generalInfo(generalInfoRequest)
.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
.subscribe(object : BaseObserver<GeneralInfo>() {
override fun doSuccess(it : GeneralInfo?) {
if (it == null) {
failed("获取车辆信息失败")
return
}
if (GlobalData.vehicleInfo == null) {
GlobalData.vehicleInfo = VehicleInfo(vehicleId = it.vehicleId,
vehicleName = it.vehicleName,
userName = it.userName,
userPhone = it.userPhone,
status = it.vehicleState,
plateNumber = it.plateNumber,
vehicleState = it.vehicleState,
supplierType = it.supplierType)
} else {
GlobalData.vehicleInfo =
GlobalData.vehicleInfo?.copy(vehicleId = it.vehicleId,
vehicleName = it.vehicleName,
userName = it.userName,
userPhone = it.userPhone,
status = it.vehicleState,
plateNumber = it.plateNumber,
vehicleState = it.vehicleState,
supplierType = it.supplierType)
}
if (GlobalData.driverInfo == null) {
GlobalData.driverInfo = DriverInfo(userPortrait = it.userPortrait,
userName = it.userName,
userId = it.userId,
userPhone = it.userPhone,
supplierId = it.supplierId.toString(),
supplierName = it.supplierName,
authStatus = it.authStatus,
supplierType = it.supplierType,
serviceList = it.serviceList)
} else {
GlobalData.driverInfo =
GlobalData.driverInfo?.copy(userPortrait = it.userPortrait,
userName = it.userName,
userId = it.userId,
userPhone = it.userPhone,
supplierId = it.supplierId.toString(),
supplierName = it.supplierName,
authStatus = it.authStatus,
supplierType = it.supplierType,
serviceList = it.serviceList)
}
success(it)
}
override fun doFailure(code : Int, msg : String?) {
failed(msg)
LogUtil.print("getGenerateInfo",
"doFailure=$msg request=${generalInfoRequest.toJson()}")
}
})
}
fun getNewOrder(context : Context) {
val newOrderRequestBean = NewOrderRequestBean(GlobalData.vehicleInfo?.vehicleId)
RetrofitHelper.getDefaultService().getNewOrder(newOrderRequestBean)
.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
.subscribe(object : BaseObserver<JpushBean>() {
override fun doSuccess(order : JpushBean?) {
NewOrderActivity.goNewOrderActivity(context,
jpushBean = JpushBean(taskId = order?.taskId,
taskCode = order?.taskCode,
customerName = order?.customerName,
customerPhone = order?.customerPhone,
carBrand = order?.carBrand,
carModel = order?.carModel,
carNo = order?.carNo,
taskState = order?.taskState,
address = order?.address,
addressProperty = order?.addressProperty,
hotline = order?.hotline,
expectArriveTime = order?.expectArriveTime,
serviceTypeName = order?.serviceTypeName,
dispatchTime = order?.dispatchTime,
lat = order?.lat,
lng = order?.lng,
distLat = order?.distLat,
distLng = order?.distLng,
importantTip = order?.importantTip,
hasReplaceBatteryCapable = order?.hasReplaceBatteryCapable,
distAddress = order?.distAddress,
distAddressRemark = order?.distAddressRemark,
addressRemark = order?.addressRemark,
voiceType = order?.voiceType))
}
override fun doFailure(code : Int, msg : String?) {
}
})
}
fun queryOrderList(context : Context? = null,
success : (OrderInfo?, List<OrderInfo>?) -> Unit,
failed : (String?) -> Unit) {
RetrofitHelper.getDefaultService()
.queryOrderList(OrderListRequest(vehicleId = GlobalData.vehicleInfo?.vehicleId,
deviceId = DeviceUtil.getAndroidId(ActivityUtils.getTopActivity())))
.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
.subscribe(object : BaseObserver<List<OrderInfo>?>() {
override fun doSuccess(it : List<OrderInfo>?) {
LogUtil.print("queryOrderList", "${it.toJson()}")
if (it.isNullOrEmpty()) {
GlobalData.clearAllOrderCache()
ReportFloatingManager.stopService()
success(null, null)
return
}
val inServicingOrder = it.find { it.isCurrent == true }
val waitServiceOrders = it.filter { it.isCurrent == false }
if (inServicingOrder == null) {
context?.let { context ->
val order = it[0]
NewOrderActivity.goNewOrderActivity(context,
jpushBean = JpushBean(taskId = order.taskId,
taskCode = order.taskCode,
customerName = order.customerName,
customerPhone = order.customerPhone,
carBrand = order.carBrand,
carModel = order.carModel,
carNo = order.carNo,
taskState = order.taskState,
address = order.address,
addressProperty = order.addressProperty,
hotline = order.hotline,
expectArriveTime = order.expectArriveTime,
serviceTypeName = order.serviceTypeName,
dispatchTime = order.dispatchTime,
lat = order.lat,
lng = order.lng,
distLat = order.distLat,
distLng = order.distLng,
importantTip = order.importantTip,
hasReplaceBatteryCapable = order.hasReplaceBatteryCapable,
distAddress = order.distAddress,
distAddressRemark = order.distAddressRemark,
addressRemark = order.addressRemark))
}
success(null, waitServiceOrders)
return
}
GlobalData.currentOrder = inServicingOrder
it.forEach {
if (RoomHelper.db?.orderDao()
?.getOrderInfoFromTaskId(it.taskId ?: 0) != null
) {
RoomHelper.db?.orderDao()?.update(orderInfo = it)
} else {
RoomHelper.db?.orderDao()?.insertOrder(orderInfo = it)
}
}
fetchPhotoTemplate(inServicingOrder)
queryElectronOrder(orderInfo = inServicingOrder)
WaterMarkerTemplateManager.fetchWaterTemplate(inServicingOrder.taskCode ?: "",
taskId = inServicingOrder.taskId ?: 0,
inServicingOrder.userOrderId ?: 0)
OfflineManager.start(GlobalData.currentOrder?.taskId)
context?.let {
ReportFloatingManager.startService(it)
}
success(inServicingOrder, waitServiceOrders)
}
override fun doFailure(code : Int, msg : String?) {
val list = RoomHelper.db?.orderDao()?.getAllOrder()
val inServicingOrder = list?.find { it.isCurrent == true }
val waitServiceOrders = list?.filter { it.isCurrent == false }
GlobalData.currentOrder = inServicingOrder
success(inServicingOrder, waitServiceOrders)
OfflineManager.start(GlobalData.currentOrder?.taskId)
LogUtil.print("queryOrderList", "queryOrderList failed 是用离线数据==$msg")
}
})
}
fun fetchPhotoTemplate(orderInfo : OrderInfo?,
success : () -> Unit = {},
failed : (String?) -> Unit = {}) {
val photoTemplateRequest = PhotoTemplateRequest(orderInfo?.userOrderId)
RetrofitHelper.getDefaultService().fetchPhotoTemplate(photoTemplateRequest)
.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
.subscribe(object : BaseObserver<List<PhotoTemplateInfo>>() {
override fun doSuccess(it : List<PhotoTemplateInfo>?) {
if (it.isNullOrEmpty()) {
LogUtil.print("fetchPhotoTemplate",
"模板为null ${photoTemplateRequest.toJson()}")
failed("未找到模版")
return
}
val listData = RoomHelper.db?.photoTemplateDao()
?.queryCurrentOrderHasTaskNode(orderInfo?.userOrderId ?: 0)
if (! listData.isNullOrEmpty()) {
LogUtil.print("queryPhotoTemplate", "模板已经存在==${listData.toJson()}")
success()
return
}
it.forEachIndexed { _, item ->
val photoTemplateInfo = item.copy(userOrderId = orderInfo?.userOrderId,
taskCode = orderInfo?.taskCode,
myCustomPhotoType = Const.PhotoType.InServicing,
advanceTime = orderInfo?.advanceTime,
taskId = orderInfo?.taskId,
needWaterMarker = orderInfo?.needWaterMarker,
needShowPhoneBrand = orderInfo?.needShowPhoneBrand,
photoSource = 0)
RoomHelper.db?.photoTemplateDao()?.insert(photoTemplateInfo)
}
LogUtil.print("fetchPhotoTemplate", " ${it.toJson()}")
success()
}
override fun doFailure(code : Int, msg : String?) {
LogUtil.print("fetchPhotoTemplate", "err==$msg")
failed(msg)
}
})
}
fun queryElectronOrder(orderInfo : OrderInfo?,
success : (EleWorkOrderBean) -> Unit = {},
failed : (String?) -> Unit = {}) {
val ele = RoomHelper.db?.eleWorkOrderDao()?.getEleWorkOrder(taskId = orderInfo?.taskId ?: 0)
if (ele != null) {
success(ele)
return
}
val queryEleOrderRequest = QueryEleOrderRequest(taskOrderId = orderInfo?.taskId,
userOrderId = orderInfo?.userOrderId)
RetrofitHelper.getDefaultService().queryElectronOrder(queryEleOrderRequest)
.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
.subscribe(object : BaseObserver<ElectronOrderResponse>() {
override fun doSuccess(it : ElectronOrderResponse?) {
val temp = EleWorkOrderBean(orderId = orderInfo?.taskId ?: 0,
userOrderId = it?.userOrderId,
date = it?.createTime,
orderWorkStatus = it?.state,
hasBad = it?.hasDamage == 1,
serverCustomSignPath = it?.customerSignPath,
carNO = it?.plateNumberBean?.value,
carVin = it?.vinNo,
serviceContent = it?.serviceTerm,
serverAcceptCarSignPath = it?.recipientSignPath,
serverServicePeopleSignPath = it?.waitstaffSignPath,
orderType = it?.serviceName)
it?.damageFileList?.forEach { item ->
val damagePhotoBean = EleCarDamagePhotoBean(userOrderId = it.userOrderId,
orderId = orderInfo?.taskId,
isPhoto = true,
uploadStatus = 1,
serverPath = item)
RoomHelper.db?.eleCarDamagePhotoDao()?.insert(damagePhotoBean)
}
RoomHelper.db?.eleWorkOrderDao()?.insertEleWorkOrder(temp)
success(temp)
}
override fun doFailure(code : Int, msg : String?) {
failed(msg)
}
})
}
}

View File

@ -0,0 +1,347 @@
package com.za.net;
import android.util.Base64;
import android.util.Log;
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.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;
import javax.crypto.Cipher;
public class RSAUtils {
/**
* 加密算法RSA
*/
private static final String KEY_ALGORITHM = "RSA";
/**
* 签名算法
*/
// public static final String SIGNATURE_ALGORITHM = "MD5withRSA";
private static final String SIGNATURE_ALGORITHM = "SHA256withRSA";
/**
* 获取公钥的key
*/
private static final String PUBLIC_KEY = "RSAPublicKey";
/**
* 获取私钥的key
*/
private static final String PRIVATE_KEY = "RSAPrivateKey";
/**
* RSA最大加密明文大小
*/
private static final int MAX_ENCRYPT_BLOCK = 117;
/**
* RSA最大解密密文大小
*/
private static final int MAX_DECRYPT_BLOCK = 256;
public static void main(String[] args) {
// try {
// genKeyPair(2048);
// } catch (Exception e) {
// e.printStackTrace();
// }
/*RSA 2048*/
// String publicKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAichGTEP0QFswnvn+ZAQrgGHM8VeDZLJuezGhgxh4d9SyRUfnIW/zefT71rwS4bZUs1MPxJwavOyxABJOHLuckdHXknCsGEWz78gsA6D0+O+9dl1gCZR29nnN/NlzmNbSjFnzvsTJYBlS88qSr35RXFE+6DM7uPsS8Fm2I+65FteJ8p2yMvpSg72QkIX8xvI1F1uwXrciIB+4u7uTozxIplMOo4a6uhAm3W+Kjpz3ni2btjGqHRbqb3ebSZyl+nFfnjQaBe3XyVxAWDSanjgFj/wbqbeug9FBs+nQFVPIZR9z0aE5Ndi5o3eSkV7HFmWpkxaiPZ0BLRK3XHMaBtuSpwIDAQAB";
// String privateKey = "MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCJyEZMQ/RAWzCe+f5kBCuAYczxV4Nksm57MaGDGHh31LJFR+chb/N59PvWvBLhtlSzUw/EnBq87LEAEk4cu5yR0deScKwYRbPvyCwDoPT47712XWAJlHb2ec382XOY1tKMWfO+xMlgGVLzypKvflFcUT7oMzu4+xLwWbYj7rkW14nynbIy+lKDvZCQhfzG8jUXW7BetyIgH7i7u5OjPEimUw6jhrq6ECbdb4qOnPeeLZu2MaodFupvd5tJnKX6cV+eNBoF7dfJXEBYNJqeOAWP/Bupt66D0UGz6dAVU8hlH3PRoTk12Lmjd5KRXscWZamTFqI9nQEtErdccxoG25KnAgMBAAECggEBAIPz1b88ZTMtIgdejA7lH3Q4Nbn8gc1yRPSet3uBd/3rKT/IeMZBHQBzaqxgOgUIRV3n8nXsun6sf2b+IOjLlErimH2agnZMauL85YokH/g4QU6WZl9GXBf41xmMd3SsZ8AadaEBfYoXNqZcHtcLNogfFwvx5QRnD+A3SoRnH8OLBeVvOEe4AqHLT2xEZ9TeCf3fJe0Rf0fUIbw7I5ioiRZV/ir0L1VM7+1k2JODUkdC2Luj5Tl3nl1Eg6EmkYCmGE1bip1NAatsfjPBLMF7XdPNjLboiffjgKVBOjb7Y9vL18BCoLtWeTT2GkMpi5Sr94T1te1Ox77dF4BP33Xn7eECgYEA1TNUrAQsh14NbbkwFtUHXS8/YXt81p9wbSpFBymIawF2Lkk0913TB4CHSun45LhYXjdZZxK/TgqC5EIq5v2RA0jY3cSxoqVe6RZKB04E8wszeJHiEJPdu2vFnpZh9iAyhswiM5FmuKZKoWsVc2SZrBXAI02smSn3lXYok1VBS3sCgYEApXEZS6gjUu4o7ZL53Ur1HDfi/nxpkxqrPh+D1HVYjzjT+4vTeZwtLXt2VCInPWNXH+f11mzhxIrLkI0jMcSCah81DuU8aFXnqvPuyFvt9uaQBYlVWBtkcGZyeaxHFrbfCyeu0jm7SfwmiIg12hKlIHtPTjEZQUX+kkWr8cdaZ8UCgYEAh0Pl+K09QzVc97yC0jmeTnTnlYWvksvdnKUw3nZvYtSukndH75nLhfr524HOs+5xwnUDd+3hCjaJDSEd7yf5lUfmr+1XdoXNTb0igrfxU/JLWbfU4geuqnaaDyACTxHmfLePC4C413ZJ61fxaCDvjsrN+JgTZanGt0EcRT3WC3kCgYEAgf5/GMJxlw0JXbs515a5R8Xl9358Whj/at3KcRsPTeIiNqnkrc54dR9ol60KViMDZ0+VDDobn5pLXzZ26/jzXD1PLHgU4gp18Q6glhAdx/3cNm11gLhtUCA/XLlwVjm0wggZRpgUQIr/IBKe9c3mr8IUS2Uq6e38nKRf+adhst0CgYAM4tvl+U1MPbbz3YzDv8QPepZ7Pglgdfxqfr5OkXA7jNhqTZjSq10B6oClGvirBo1m6f26F02iUKk1n67AuiLlTP/RRZHi1cfq6P9IaXl23PcxJfUMvIxQDS0U+UTFpNXryTw/qNAkSfufN48YzKdGvc8vHrYJyaeemaVlbdJOCw==";
//
//
// try {
//
// String data = "测试提交数据";
//
// byte[] publicEncryptBytes = RSAUtils.encryptByPublicKey(data.getBytes(), publicKey);
// System.out.println("公钥加密后的数据:" + Base64.encodeToString(publicEncryptBytes, Base64.URL_SAFE | Base64.NO_WRAP));
// byte[] privatDecryptBytes = RSAUtils.decryptByPrivateKey(publicEncryptBytes, privateKey);
// System.out.println("私钥解密后的数据:" + new String(privatDecryptBytes));
//
//
// System.out.println("--------------------");
//
// byte[] privateKeyEncryptBytes = RSAUtils.encryptByPrivateKey(data.getBytes(), privateKey);
// System.out.println("私钥加密后的数据:" + Base64.encodeToString(privateKeyEncryptBytes, Base64.URL_SAFE | Base64.NO_WRAP));
//
// String singnData = RSAUtils.sign(data.getBytes(), privateKey);
// System.out.println("私钥签名后的数据:" + singnData);
//
//
// byte[] publicDecryptBytes = RSAUtils.decryptByPublicKey(privateKeyEncryptBytes, publicKey);
// System.out.println("公钥解密后的数据:" + new String(publicDecryptBytes));
//
// boolean isSign = RSAUtils.verify(data.getBytes(), publicKey, singnData);
// System.out.println("签名是否正确:" + isSign);
//
//
// } catch (Exception e) {
// e.printStackTrace();
// }
}
/**
* @param keySize 生成的秘钥长度 一般为1024或2048
* @return
* @throws Exception
*/
public static Map<String, Object> genKeyPair(int keySize) throws Exception {
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
keyPairGen.initialize(keySize);
KeyPair keyPair = keyPairGen.generateKeyPair();
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
Map<String, Object> keyMap = new HashMap<String, Object>(2);
keyMap.put(PUBLIC_KEY, publicKey);
keyMap.put(PRIVATE_KEY, privateKey);
// Log.d("DoggieX","publicKey" + Base64.encodeToString(publicKey.getEncoded(), Base64.URL_SAFE | Base64.NO_WRAP));
// Log.d("DoggieX","privateKey" + Base64.encodeToString(privateKey.getEncoded(), Base64.URL_SAFE | Base64.NO_WRAP));
Log.d("DoggieX","publicKey" + Base64.encodeToString(publicKey.getEncoded(), Base64.NO_WRAP));
Log.d("DoggieX","privateKey" + Base64.encodeToString(privateKey.getEncoded(), Base64.NO_WRAP));
return keyMap;
}
/**
* 对已加密数据进行签名
*
* @param data 已加密的数据
* @param privateKey 私钥
* @return 对已加密数据生成的签名
* @throws Exception
*/
public static String sign(byte[] data, String privateKey) throws Exception {
byte[] keyBytes = Base64.decode(privateKey, Base64.URL_SAFE | Base64.NO_WRAP);
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
PrivateKey privateK = keyFactory.generatePrivate(pkcs8KeySpec);
Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
signature.initSign(privateK);
signature.update(data);
return Base64.encodeToString(signature.sign(), Base64.URL_SAFE);
}
/**
* 验签
*
* @param data 签名之前的数据
* @param publicKey 公钥
* @param sign 签名之后的数据
* @return 验签是否成功
* @throws Exception
*/
public static boolean verify(byte[] data, String publicKey, String sign) throws Exception {
byte[] keyBytes = Base64.decode(publicKey, Base64.URL_SAFE | Base64.NO_WRAP);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
PublicKey publicK = keyFactory.generatePublic(keySpec);
Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
signature.initVerify(publicK);
signature.update(data);
return signature.verify(Base64.decode(sign, Base64.URL_SAFE));
}
/**
* 用私钥对数据进行解密
*
* @param encryptedData 使用公钥加密过的数据
* @param privateKey 私钥
* @return 解密后的数据
* @throws Exception
*/
public static byte[] decryptByPrivateKey(byte[] encryptedData, String privateKey) throws Exception {
byte[] keyBytes = Base64.decode(privateKey, Base64.NO_WRAP);
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
//Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding","BC");
cipher.init(Cipher.DECRYPT_MODE, privateK);
Log.d("DoggieX","provider:"+cipher.getProvider().getClass().getName());
int inputLen = encryptedData.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(encryptedData, offSet, MAX_DECRYPT_BLOCK);
} else {
cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
}
out.write(cache, 0, cache.length);
i++;
offSet = i * MAX_DECRYPT_BLOCK;
}
byte[] decryptedData = out.toByteArray();
out.close();
return decryptedData;
}
/**
* 公钥解密
*
* @param encryptedData 使用私钥加密过的数据
* @param publicKey 公钥
* @return 解密后的数据
* @throws Exception
*/
public static byte[] decryptByPublicKey(byte[] encryptedData, String publicKey) throws Exception {
byte[] keyBytes = Base64.decode(publicKey, Base64.URL_SAFE | Base64.NO_WRAP);
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
Key publicK = keyFactory.generatePublic(x509KeySpec);
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.DECRYPT_MODE, publicK);
int inputLen = encryptedData.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(encryptedData, offSet, MAX_DECRYPT_BLOCK);
} else {
cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
}
out.write(cache, 0, cache.length);
i++;
offSet = i * MAX_DECRYPT_BLOCK;
}
byte[] decryptedData = out.toByteArray();
out.close();
return decryptedData;
}
/**
* 公钥加密
*
* @param data 需要加密的数据
* @param publicKey 公钥
* @return 使用公钥加密后的数据
* @throws Exception
*/
public static byte[] encryptByPublicKey(byte[] data, String publicKey) throws Exception {
byte[] keyBytes = Base64.decode(publicKey, Base64.NO_WRAP);
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
Key publicK = keyFactory.generatePublic(x509KeySpec);
// 对数据加密
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding","BC");
cipher.init(Cipher.ENCRYPT_MODE, publicK);
Log.d("DoggieX",cipher.getProvider().getClass().toString());
int inputLen = data.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, offSet, MAX_ENCRYPT_BLOCK);
} else {
cache = cipher.doFinal(data, offSet, inputLen - offSet);
}
out.write(cache, 0, cache.length);
i++;
offSet = i * MAX_ENCRYPT_BLOCK;
}
byte[] encryptedData = out.toByteArray();
out.close();
return encryptedData;
}
/**
* 私钥加密
*
* @param data 待加密的数据
* @param privateKey 私钥
* @return 使用私钥加密后的数据
* @throws Exception
*/
public static byte[] encryptByPrivateKey(byte[] data, String privateKey) throws Exception {
byte[] keyBytes = Base64.decode(privateKey, Base64.URL_SAFE | Base64.NO_WRAP);
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE, privateK);
int inputLen = data.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, offSet, MAX_ENCRYPT_BLOCK);
} else {
cache = cipher.doFinal(data, offSet, inputLen - offSet);
}
out.write(cache, 0, cache.length);
i++;
offSet = i * MAX_ENCRYPT_BLOCK;
}
byte[] encryptedData = out.toByteArray();
out.close();
return encryptedData;
}
/**
* 获取私钥
*
* @param keyMap 生成的秘钥对
* @return
* @throws Exception
*/
public static String getPrivateKey(Map<String, Object> keyMap) throws Exception {
Key key = (Key) keyMap.get(PRIVATE_KEY);
return Base64.encodeToString(key.getEncoded(), Base64.URL_SAFE | Base64.NO_WRAP);
}
/**
* 获取公钥
*
* @param keyMap 生成的秘钥对
* @return
* @throws Exception
*/
public static String getPublicKey(Map<String, Object> keyMap) throws Exception {
Key key = (Key) keyMap.get(PUBLIC_KEY);
return Base64.encodeToString(key.getEncoded(), Base64.URL_SAFE | Base64.NO_WRAP);
}
}

View File

@ -0,0 +1,109 @@
package com.za.net;
import android.util.Base64;
import androidx.annotation.NonNull;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.za.common.GlobalData;
import java.io.IOException;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import okhttp3.HttpUrl;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okio.Buffer;
/**
* @author DoggieX
* @create 2021/8/23 15:00
* @mail coldpuppy@163.com
*/
public class RequestEncryptInterceptor implements Interceptor {
static final String PUBLIC_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA7UM6zdWdBuO0DZZVkxVfJioawUe6qH1p5Uz/qR9zbawl2oWyxxcBfxQyPS+HxOej/ZnyS4bu7qhh99alDqkJzk6g9oGZWs+jEF5GRWt9nChlfUsjvHQwuF2TSQMTdPtDPCByF/QgMFCAfbCqTrNmOETrZ/2GFy1Re0BTlhh6X/XzpzqtK+enikEMlQ5fIM5ljdXgyCnvDou9ptWqzw8Zmsat6LeA0UKz+bgpJAbw6KfK+8lPMqUpNFfkmJuEd5+JQOG9McH7j9pBagohkC6k3Cn92dAf9iD6NSDKSNgt1vxXhaNnfAbYJ5pqeSGy6QMSVO0TXYj4asln5OutD/284QIDAQAB";
@NonNull
@Override
public Response intercept(@NonNull Chain chain) throws IOException {
Request request = chain.request();
String method = request.method().toLowerCase().trim();
HttpUrl url = request.url();
boolean skipEncrypt = url.encodedPath().endsWith("appVersion")
|| url.encodedPath().endsWith("getVerifyCode")
|| url.encodedPath().endsWith("listVehicleNew")
|| url.encodedPath().endsWith("getExitMileage")
|| url.encodedPath().endsWith("uploadImage")
|| url.encodedPath().endsWith("upload")
|| url.encodedPath().endsWith("matchAppUploadTime");
if (method.equals("post") && !skipEncrypt) {
RequestBody body = request.body();
if (null != body) {
Buffer buffer = new Buffer();
body.writeTo(buffer);
String data = URLDecoder.decode(buffer.readString(StandardCharsets.UTF_8), "utf-8");
JSONObject jsonObject = JSON.parseObject(data);
if (null == jsonObject) {
jsonObject = new JSONObject();
}
jsonObject.put("requestTime", System.currentTimeMillis());
data = jsonObject.toJSONString();
String aesKey;
try {
if (url.encodedPath().endsWith("login")
|| url.encodedPath().endsWith("fastLogin")) {
// 登录接口生成新key
aesKey = AESUtils.getRandomKey(16);
GlobalData.INSTANCE.setAesKey(aesKey);
} else {
aesKey = GlobalData.INSTANCE.getAesKey();
if (null == aesKey && url.encodedPath().endsWith("loginWithTask")) {
aesKey = AESUtils.getRandomKey(16);
GlobalData.INSTANCE.setAesKey(aesKey);
} else if (null == aesKey) {
throw new IOException("缺失加密密钥");
} else {
aesKey = GlobalData.INSTANCE.getAesKey();
}
}
if (!url.encodedPath().endsWith("login")
&& !url.encodedPath().endsWith("fastLogin")
&& !url.encodedPath().endsWith("loginWithTask")) {
data = AESUtils.encrypt(data, aesKey);
}
RequestBody requestBody = RequestBody.create(body.contentType(), data);
Request.Builder requestBuilder = request.newBuilder().post(requestBody);
if (url.encodedPath().endsWith("login")
|| url.encodedPath().endsWith("fastLogin")
|| url.encodedPath().endsWith("loginWithTask")) {
byte[] bytes = RSAUtils.encryptByPublicKey(aesKey.getBytes(StandardCharsets.UTF_8), PUBLIC_KEY);
String tokenSecret = Base64.encodeToString(bytes, Base64.NO_WRAP);
requestBuilder.addHeader("secret", tokenSecret);
} else {
String token = GlobalData.INSTANCE.getToken();
if (null == token) {
throw new IOException("缺失token");
} else {
requestBuilder.addHeader("token", token);
}
}
request = requestBuilder.build();
} catch (Exception e) {
e.printStackTrace();
}
}
}
return chain.proceed(request);
}
}

View File

@ -0,0 +1,83 @@
package com.za.net
import android.util.Log
import com.za.base.AppConfig
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.adapter.rxjava3.RxJava3CallAdapterFactory
import retrofit2.converter.gson.GsonConverterFactory
import java.io.UnsupportedEncodingException
import java.net.URLDecoder
import java.util.concurrent.TimeUnit
object RetrofitHelper {
private var retrofit: Retrofit? = null
private var apiService: ApiService? = null
private val loggerInterceptor = HttpLoggingInterceptor {
try {
if (it.contains("image/*") || it.contains("form-data; name=\"file\"")
|| it.startsWith("Content-Type")
|| it.startsWith("Content-Length")
|| it.startsWith("Server")
|| it.startsWith("Date")
|| it.startsWith("Transfer-Encoding")
|| it.startsWith("Connection")
|| it.startsWith("X-")
|| it.startsWith("token")
|| it.startsWith("Cache-Control")
|| it.startsWith("Expires")
|| it.startsWith("Accept")
|| it.startsWith("Vary")
|| it.isEmpty()
|| it.startsWith("Pragma")
) {
return@HttpLoggingInterceptor
}
if (it.contains("name=\"file\"; filename")) {
return@HttpLoggingInterceptor
}
Log.e(
"--network--",
URLDecoder.decode(it.replace(Regex("%(?![0-9a-fA-F]{2})"), ""), "utf-8")
)
} catch (e: UnsupportedEncodingException) {
e.printStackTrace()
}
}.setLevel(HttpLoggingInterceptor.Level.BODY)
fun getDefaultService(): ApiService {
return if (apiService == null) {
apiService = getDefaultRetrofit().create(ApiService::class.java)
apiService!!
} else {
apiService!!
}
}
private fun getDefaultRetrofit(): Retrofit {
return if (retrofit == null) {
retrofit = Retrofit.Builder().baseUrl(AppConfig.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava3CallAdapterFactory.create())
.client(getOkHttpClient())
.build()
retrofit!!
} else {
retrofit!!
}
}
private fun getOkHttpClient(): OkHttpClient {
return OkHttpClient.Builder()
.connectTimeout(30, TimeUnit.SECONDS)
.writeTimeout(60, TimeUnit.SECONDS)
.readTimeout(60, TimeUnit.SECONDS)
.addInterceptor(RequestEncryptInterceptor())
.addInterceptor(loggerInterceptor)
.build()
}
}