From 082545a516a88f7f6846cfee2713b77a37cc321d Mon Sep 17 00:00:00 2001 From: jtsky <704167880@qq.com> Date: Tue, 6 Jul 2021 17:22:42 +0800 Subject: [PATCH] =?UTF-8?q?modify:=20[Android]:=20=E4=B8=80=E6=9C=BA?= =?UTF-8?q?=E5=A4=9A=E6=8E=A7=E5=B9=B3=E5=8F=B0=E7=AB=AF=E8=81=94=E8=B0=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/didichuxing/doraemondemo/App.kt | 3 +- .../doraemondemo/MainDebugActivityOkhttpV3.kt | 9 +- .../kit/mc/ability/DokitMcInterceptor.kt | 60 ++++++-- .../kit/mc/ability/McHttpManager.kt | 133 ++++++++++-------- .../kit/mc/ability/McUseCaseInfo.kt | 19 --- .../kit/mc/all/ui/DoKitMcDatasFragment.kt | 37 ++++- .../kit/mc/all/ui/DoKitMcMainFragment.kt | 122 +++++++++++----- .../kit/mc/all/ui/McCaseListAdapter.kt | 7 +- .../kit/mc/{ability => data}/AppInfo.kt | 2 +- .../kit/mc/data/HttpMatchedInfo.kt | 15 ++ .../HttpInfo.kt => data/HttpUploadInfo.kt} | 6 +- .../kit/mc/{all/ui => }/data/McCaseInfo.kt | 2 +- .../doraemonkit/kit/mc/data/McConfigInfo.kt | 13 ++ .../kit/mc/{all/ui => }/data/McResInfo.kt | 8 +- .../main/res/layout/dk_fragment_mc_datas.xml | 18 ++- .../doraemonkit/ExampleUnitTest.kt | 4 +- .../doraemonkit/plugin/DoKitExtUtil.kt | 5 + .../classtransformer/CommTransformer.kt | 10 +- .../processor/DoKitPluginConfigProcessor.kt | 8 ++ .../doraemonkit/aop/OkHttpHook.java | 31 ++-- .../kit/core/SimpleDokitStarter.kt | 8 ++ Android/java/settings.gradle | 3 +- 22 files changed, 362 insertions(+), 161 deletions(-) delete mode 100644 Android/java/doraemonkit-mc/src/main/java/com/didichuxing/doraemonkit/kit/mc/ability/McUseCaseInfo.kt rename Android/java/doraemonkit-mc/src/main/java/com/didichuxing/doraemonkit/kit/mc/{ability => data}/AppInfo.kt (94%) create mode 100644 Android/java/doraemonkit-mc/src/main/java/com/didichuxing/doraemonkit/kit/mc/data/HttpMatchedInfo.kt rename Android/java/doraemonkit-mc/src/main/java/com/didichuxing/doraemonkit/kit/mc/{ability/HttpInfo.kt => data/HttpUploadInfo.kt} (82%) rename Android/java/doraemonkit-mc/src/main/java/com/didichuxing/doraemonkit/kit/mc/{all/ui => }/data/McCaseInfo.kt (87%) create mode 100644 Android/java/doraemonkit-mc/src/main/java/com/didichuxing/doraemonkit/kit/mc/data/McConfigInfo.kt rename Android/java/doraemonkit-mc/src/main/java/com/didichuxing/doraemonkit/kit/mc/{all/ui => }/data/McResInfo.kt (61%) diff --git a/Android/java/app/src/debug/java/com/didichuxing/doraemondemo/App.kt b/Android/java/app/src/debug/java/com/didichuxing/doraemondemo/App.kt index 8ec82436..1a0b1faf 100644 --- a/Android/java/app/src/debug/java/com/didichuxing/doraemondemo/App.kt +++ b/Android/java/app/src/debug/java/com/didichuxing/doraemondemo/App.kt @@ -89,7 +89,8 @@ class App : Application() { DoKit.Builder(this) - .productId("749a0600b5e48dd77cf8ee680be7b1b7") + //.productId("749a0600b5e48dd77cf8ee680be7b1b7") + .productId("277016abcc33bff1e6a4f1afdf14b8e1") .disableUpload() .customKits(mapKits) .fileManagerHttpPort(9001) diff --git a/Android/java/app/src/debug/java/com/didichuxing/doraemondemo/MainDebugActivityOkhttpV3.kt b/Android/java/app/src/debug/java/com/didichuxing/doraemondemo/MainDebugActivityOkhttpV3.kt index a8b6d6d2..dcd6f175 100644 --- a/Android/java/app/src/debug/java/com/didichuxing/doraemondemo/MainDebugActivityOkhttpV3.kt +++ b/Android/java/app/src/debug/java/com/didichuxing/doraemondemo/MainDebugActivityOkhttpV3.kt @@ -218,7 +218,14 @@ class MainDebugActivityOkhttpV3 : BaseActivity(), View.OnClickListener, jsonObject.put("d", "dd") OkGo.post("https://wanandroid.com/user_article/list/0/json?b=bb&a=aa") .upJson(jsonObject) - .execute() + .execute(object : StringCallback() { + override fun onSuccess(response: Response?) { + response?.let { + Log.i(TAG, "okhttp====onSuccess===>" + it.body()) + } + } + + }) // OkGo.post("https://wanandroid.com/user_article/list/0/json?b=bb&a=aa") diff --git a/Android/java/doraemonkit-mc/src/main/java/com/didichuxing/doraemonkit/kit/mc/ability/DokitMcInterceptor.kt b/Android/java/doraemonkit-mc/src/main/java/com/didichuxing/doraemonkit/kit/mc/ability/DokitMcInterceptor.kt index 18157483..fa08d897 100644 --- a/Android/java/doraemonkit-mc/src/main/java/com/didichuxing/doraemonkit/kit/mc/ability/DokitMcInterceptor.kt +++ b/Android/java/doraemonkit-mc/src/main/java/com/didichuxing/doraemonkit/kit/mc/ability/DokitMcInterceptor.kt @@ -6,13 +6,15 @@ import com.didichuxing.doraemonkit.extension.doKitGlobalScope import com.didichuxing.doraemonkit.extension.sortedByKey import com.didichuxing.doraemonkit.extension.toMap import com.didichuxing.doraemonkit.kit.mc.all.McConstant +import com.didichuxing.doraemonkit.kit.mc.data.HttpMatchedInfo +import com.didichuxing.doraemonkit.kit.mc.data.HttpUploadInfo import com.didichuxing.doraemonkit.kit.network.NetworkManager import com.didichuxing.doraemonkit.kit.network.okhttp.InterceptorUtil import com.didichuxing.doraemonkit.kit.network.okhttp.interceptor.AbsDoKitInterceptor -import com.didichuxing.doraemonkit.util.EncodeUtils import com.didichuxing.doraemonkit.util.GsonUtils import com.didichuxing.doraemonkit.util.LogHelper import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking import okhttp3.* import okio.ByteString import java.net.URLDecoder @@ -34,6 +36,7 @@ class DokitMcInterceptor : AbsDoKitInterceptor() { val response = chain.proceed(request) val url = request.url() val host: String = url.host() + val scheme = url.scheme() val contentType = response.header("Content-Type") ?: response.header("content-type") //如果是图片则不进行拦截 if (InterceptorUtil.isImg(contentType)) { @@ -43,6 +46,15 @@ class DokitMcInterceptor : AbsDoKitInterceptor() { if (host.equals(NetworkManager.MOCK_HOST, ignoreCase = true)) { return response } + + if ("$scheme://$host".equals(McHttpManager.host, ignoreCase = true)) { + val strResponseBody = response.peekBody(Long.MAX_VALUE).string() + LogHelper.i(TAG, "========DoKit SDK 接口数据 Start url:$url ========") + LogHelper.json(TAG, strResponseBody) + LogHelper.i(TAG, "========DoKit SDK 接口数据 End url:$url ========") + return response + } + //不包含query字段 val method = request.method() val path = URLDecoder.decode(url.encodedPath(), "utf-8") @@ -59,6 +71,9 @@ class DokitMcInterceptor : AbsDoKitInterceptor() { val requestBodyMap = createRequestBodyMap(request) val strRequestBody = GsonUtils.toJson(requestBodyMap) val strResponseBody = response.peekBody(Long.MAX_VALUE).string() + LogHelper.i(TAG, "========业务接口 Start url:$url ========") + LogHelper.json(TAG, strResponseBody) + LogHelper.i(TAG, "========业务接口 End url:$url ========") val k = "method=$method&path=$path&fragment=$fragment&query=$strQuery&contentType=$requestContentType&requestBody=$strRequestBody" val key = ByteString.encodeUtf8(k).md5().hex() @@ -68,7 +83,7 @@ class DokitMcInterceptor : AbsDoKitInterceptor() { // val responseBody4Base64 = String(EncodeUtils.base64Encode(strResponseBody)) //todo: 实时发送网络请求 doKitGlobalScope.launch { - val httInfo = HttpInfo( + val httInfo = HttpUploadInfo( DoKitConstant.PRODUCT_ID, McConstant.MC_CASE_ID, key, @@ -92,19 +107,34 @@ class DokitMcInterceptor : AbsDoKitInterceptor() { } WSMode.HOST, WSMode.CLIENT -> { - if (McHttpManager.mHttpInfoMap[key] != null) { - val responseBodyBytes = - EncodeUtils.base64Decode(McHttpManager.mHttpInfoMap[key]?.responseBody4base64) - val responseBody = - ResponseBody.create(response.body()?.contentType(), responseBodyBytes) - return response.newBuilder() - .code(response.code()) - .request(request) - .message(response.message()) - .protocol(response.protocol()) - .headers(response.headers()) - .body(responseBody) - .build() + if (McConstant.MC_CASE_ID.isNotBlank() && DoKitConstant.PRODUCT_ID.isNotBlank()) { + //将挂起函数转为阻塞调用 等待协程返回值 + return runBlocking { + try { + val result = McHttpManager.httpMatch(key) + if (result.code == McHttpManager.RESPONSE_OK && result.data != null) { + val responseBody = + ResponseBody.create( + response.body()?.contentType(), + result.data!!.responseBody + ) + return@runBlocking response.newBuilder() + .code(response.code()) + .request(request) + .message(response.message()) + .protocol(response.protocol()) + .headers(response.headers()) + .body(responseBody) + .build() + } else { + return@runBlocking response + } + } catch (e: Exception) { + LogHelper.e(TAG, "e===>${e.message}") + return@runBlocking response + } + + } } } else -> { diff --git a/Android/java/doraemonkit-mc/src/main/java/com/didichuxing/doraemonkit/kit/mc/ability/McHttpManager.kt b/Android/java/doraemonkit-mc/src/main/java/com/didichuxing/doraemonkit/kit/mc/ability/McHttpManager.kt index d1b59e2f..f58697e3 100644 --- a/Android/java/doraemonkit-mc/src/main/java/com/didichuxing/doraemonkit/kit/mc/ability/McHttpManager.kt +++ b/Android/java/doraemonkit-mc/src/main/java/com/didichuxing/doraemonkit/kit/mc/ability/McHttpManager.kt @@ -4,13 +4,13 @@ import com.android.volley.Request import com.android.volley.toolbox.JsonObjectRequest import com.android.volley.toolbox.StringRequest import com.didichuxing.doraemonkit.constant.DoKitConstant +import com.didichuxing.doraemonkit.kit.mc.all.McConstant import com.didichuxing.doraemonkit.kit.mc.all.ui.McCaseInfoDialogProvider -import com.didichuxing.doraemonkit.kit.mc.all.ui.data.McCaseInfo -import com.didichuxing.doraemonkit.kit.mc.all.ui.data.McResInfo +import com.didichuxing.doraemonkit.kit.mc.data.AppInfo +import com.didichuxing.doraemonkit.kit.mc.data.HttpUploadInfo +import com.didichuxing.doraemonkit.kit.mc.data.McResInfo import com.didichuxing.doraemonkit.util.GsonUtils import com.didichuxing.doraemonkit.volley.VolleyManager -import com.google.gson.Gson -import com.google.gson.reflect.TypeToken import org.json.JSONObject import kotlin.coroutines.resume import kotlin.coroutines.resumeWithException @@ -29,14 +29,9 @@ object McHttpManager { const val RESPONSE_OK = 200 const val host = "http://dokit-test.intra.xiaojukeji.com" +// const val host = "http://172.23.166.48" - val mHttpInfoMap: MutableMap by lazy { - mutableMapOf() - } - - val mExcludeKey: List by lazy { - mutableListOf() - } + var mExcludeKey: List = mutableListOf() // /** @@ -52,29 +47,28 @@ object McHttpManager { // } - @Throws(Exception::class) - suspend inline fun getMcConfig(): McResInfo = suspendCoroutine { - val jsonObject = JSONObject() - jsonObject.put("pId", DoKitConstant.PRODUCT_ID) - val request = JsonObjectRequest( - "$host/app/multiControl/getConfig", - jsonObject, - { response -> - it.resume(convert2McResInfo(response)) - }, { error -> - it.resumeWithException(error) - }) - VolleyManager.add(request) - } + suspend inline fun getMcConfig(): McResInfo = + suspendCoroutine { + val jsonObject = JSONObject() + jsonObject.put("pId", DoKitConstant.PRODUCT_ID) + val request = JsonObjectRequest( + "$host/app/multiControl/getConfig", + jsonObject, + { response -> + it.resume(convert2McResInfoWithObj(response)) + }, { error -> + it.resumeWithException(error) + }) + VolleyManager.add(request) + } - @Throws(Exception::class) suspend inline fun mockStart(): McResInfo = suspendCoroutine { val request = JsonObjectRequest( "$host/app/multiControl/startRecord", JSONObject(GsonUtils.toJson(AppInfo())), { response -> - it.resume(convert2McResInfo(response)) + it.resume(convert2McResInfoWithObj(response)) }, { error -> it.resumeWithException(error) }) @@ -82,28 +76,26 @@ object McHttpManager { } - @Throws(Exception::class) - suspend inline fun uploadHttpInfo(httpInfo: HttpInfo): McResInfo = + suspend inline fun uploadHttpInfo(httpInfo: HttpUploadInfo): McResInfo = suspendCoroutine { val request = JsonObjectRequest( "$host/app/multiControl/uploadApiInfo", JSONObject(GsonUtils.toJson(httpInfo)), { response -> - it.resume(convert2McResInfo(response)) + it.resume(convert2McResInfoWithObj(response)) }, { error -> it.resumeWithException(error) }) VolleyManager.add(request) } - @Throws(Exception::class) suspend inline fun mockStop(caseInfo: McCaseInfoDialogProvider.CaseInfo): McResInfo = suspendCoroutine { val request = JsonObjectRequest( "$host/app/multiControl/endRecord", JSONObject(GsonUtils.toJson(caseInfo)), { response -> - it.resume(convert2McResInfo(response)) + it.resume(convert2McResInfoWithObj(response)) }, { error -> it.resumeWithException(error) }) @@ -111,13 +103,12 @@ object McHttpManager { } - @Throws(Exception::class) - suspend inline fun caseList(): McResInfo = suspendCoroutine { + suspend inline fun caseList(): McResInfo> = suspendCoroutine { val request = StringRequest( Request.Method.GET, "$host/app/multiControl/caseList?pId=${DoKitConstant.PRODUCT_ID}", { response -> - it.resume(convert2McResInfo(JSONObject(response))) + it.resume(convert2McResInfoWithList(JSONObject(response))) }, { error -> it.resumeWithException(error) }) @@ -125,35 +116,57 @@ object McHttpManager { } - @Throws(Exception::class) - suspend inline fun httpMatch(requestKey: String): McResInfo = suspendCoroutine { - val jsonObject = JSONObject() - jsonObject.put("key", requestKey) - jsonObject.put("caseId", "caseId") - val request = JsonObjectRequest( - "$host/app/multiControl/getCaseApiInfo", - jsonObject, - { response -> - it.resume(convert2McResInfo(response)) - }, { error -> - it.resumeWithException(error) - }) - VolleyManager.add(request) + suspend inline fun httpMatch(requestKey: String): McResInfo = + suspendCoroutine { + val request = StringRequest( + "$host/app/multiControl/getCaseApiInfo?key=${requestKey}&pId=${DoKitConstant.PRODUCT_ID}&caseId=${McConstant.MC_CASE_ID}", + { response -> + it.resume(convert2McResInfoWithObj(JSONObject(response))) + }, { error -> + it.resumeWithException(error) + }) + VolleyManager.add(request) + } + + + inline fun convert2McResInfoWithObj(json: JSONObject): McResInfo { + return try { + val mcInfo = McResInfo( + json.optInt("code", 0), + json.optString("msg", "has no msg value") + ) + + val dataJson = json.optJSONObject("data") + val type = GsonUtils.getType(T::class.java) + mcInfo.data = GsonUtils.fromJson(dataJson.toString(), type) + mcInfo + } catch (e: Exception) { + McResInfo( + 0, + "Gson format error", + null + ) + } } - inline fun convert2McResInfo(json: JSONObject): McResInfo { - val mcInfo = McResInfo( - json.getInt("code"), - json.getString("msg") - ) - val dataInfo: T? = try { - val dataJson = json.getJSONObject("data").toString() - GsonUtils.fromJson(dataJson, T::class.java) + inline fun convert2McResInfoWithList(json: JSONObject): McResInfo> { + return try { + val mcInfo = McResInfo>( + json.optInt("code", 0), + json.optString("msg", "has no msg value") + ) + + val dataJson = json.optJSONArray("data") + val type = GsonUtils.getListType(T::class.java) + mcInfo.data = GsonUtils.fromJson(dataJson.toString(), type) + mcInfo } catch (e: Exception) { - null + McResInfo( + 0, + "Gson format error", + null + ) } - mcInfo.data = dataInfo - return mcInfo } } \ No newline at end of file diff --git a/Android/java/doraemonkit-mc/src/main/java/com/didichuxing/doraemonkit/kit/mc/ability/McUseCaseInfo.kt b/Android/java/doraemonkit-mc/src/main/java/com/didichuxing/doraemonkit/kit/mc/ability/McUseCaseInfo.kt deleted file mode 100644 index 499e0073..00000000 --- a/Android/java/doraemonkit-mc/src/main/java/com/didichuxing/doraemonkit/kit/mc/ability/McUseCaseInfo.kt +++ /dev/null @@ -1,19 +0,0 @@ -package com.didichuxing.doraemonkit.kit.mc.ability - -import android.app.Person - -/** - * ================================================ - * 作 者:jint(金台) - * 版 本:1.0 - * 创建日期:2021/6/22-20:02 - * 描 述: - * 修订历史: - * ================================================ - */ -data class McUseCaseInfo( - val casePerson: String = "DoKit", - val caseName: String = "DoKit Default Case", - val appInfo: AppInfo = AppInfo(), - val httpInfos: MutableList = mutableListOf() -) diff --git a/Android/java/doraemonkit-mc/src/main/java/com/didichuxing/doraemonkit/kit/mc/all/ui/DoKitMcDatasFragment.kt b/Android/java/doraemonkit-mc/src/main/java/com/didichuxing/doraemonkit/kit/mc/all/ui/DoKitMcDatasFragment.kt index dfa65571..b36c6726 100644 --- a/Android/java/doraemonkit-mc/src/main/java/com/didichuxing/doraemonkit/kit/mc/all/ui/DoKitMcDatasFragment.kt +++ b/Android/java/doraemonkit-mc/src/main/java/com/didichuxing/doraemonkit/kit/mc/all/ui/DoKitMcDatasFragment.kt @@ -2,12 +2,15 @@ package com.didichuxing.doraemonkit.kit.mc.all.ui import android.os.Bundle import android.view.View +import android.widget.TextView import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.didichuxing.doraemonkit.kit.core.BaseFragment import com.didichuxing.doraemonkit.kit.mc.ability.McHttpManager +import com.didichuxing.doraemonkit.kit.mc.all.McConstant import com.didichuxing.doraemonkit.mc.R +import com.didichuxing.doraemonkit.util.SPUtils import com.didichuxing.doraemonkit.util.ToastUtils import com.didichuxing.doraemonkit.widget.recyclerview.DividerItemDecoration import kotlinx.coroutines.launch @@ -23,6 +26,7 @@ import kotlinx.coroutines.launch */ class DoKitMcDatasFragment : BaseFragment() { lateinit var mRv: RecyclerView + lateinit var mEmpty: TextView lateinit var mAdapter: McCaseListAdapter override fun onRequestLayout(): Int { @@ -33,6 +37,7 @@ class DoKitMcDatasFragment : BaseFragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) mRv = findViewById(R.id.rv) + mEmpty = findViewById(R.id.tv_empty) mRv.layoutManager = LinearLayoutManager(requireActivity()) val decoration = DividerItemDecoration(DividerItemDecoration.VERTICAL) decoration.setDrawable(resources.getDrawable(R.drawable.dk_divider)) @@ -46,14 +51,42 @@ class DoKitMcDatasFragment : BaseFragment() { item.isChecked = true adapter.notifyDataSetChanged() ToastUtils.showShort("用例${item.caseName}已被选中") + saveCaseId(item.caseId) } mRv.adapter = mAdapter lifecycleScope.launch { - val data = McHttpManager.caseList>().data - mAdapter.setList(data) + val data = McHttpManager.caseList().data + + data?.let { + if (it.isEmpty()) { + mEmpty.visibility = View.VISIBLE + } else { + val caseId = loadCaseId() + it.forEach { info -> + info.isChecked = caseId == info.caseId + } + mAdapter.setList(it) + } + + } } } + private fun saveCaseId(caseId: String) { + McConstant.MC_CASE_ID = caseId + SPUtils.getInstance().put("mc_case_id", caseId) + } + + private fun loadCaseId(): String { + return if (McConstant.MC_CASE_ID.isEmpty()) { + val caseId = SPUtils.getInstance().getString("mc_case_id", "") + McConstant.MC_CASE_ID = caseId + McConstant.MC_CASE_ID + } else { + McConstant.MC_CASE_ID + } + } + } \ No newline at end of file diff --git a/Android/java/doraemonkit-mc/src/main/java/com/didichuxing/doraemonkit/kit/mc/all/ui/DoKitMcMainFragment.kt b/Android/java/doraemonkit-mc/src/main/java/com/didichuxing/doraemonkit/kit/mc/all/ui/DoKitMcMainFragment.kt index b16721bc..6eeeb74b 100644 --- a/Android/java/doraemonkit-mc/src/main/java/com/didichuxing/doraemonkit/kit/mc/all/ui/DoKitMcMainFragment.kt +++ b/Android/java/doraemonkit-mc/src/main/java/com/didichuxing/doraemonkit/kit/mc/all/ui/DoKitMcMainFragment.kt @@ -23,8 +23,9 @@ import com.didichuxing.doraemonkit.kit.mc.ability.McHttpManager import com.didichuxing.doraemonkit.kit.mc.ability.McHttpManager.RESPONSE_OK import com.didichuxing.doraemonkit.kit.mc.all.DoKitWindowManager import com.didichuxing.doraemonkit.kit.mc.all.McConstant -import com.didichuxing.doraemonkit.kit.mc.all.ui.data.McCaseInfo +import com.didichuxing.doraemonkit.kit.mc.data.McCaseInfo import com.didichuxing.doraemonkit.kit.mc.client.DoKitWsClient +import com.didichuxing.doraemonkit.kit.mc.data.McConfigInfo import com.didichuxing.doraemonkit.kit.mc.server.HostInfo import com.didichuxing.doraemonkit.kit.mc.server.RecordingDokitView import com.didichuxing.doraemonkit.mc.R @@ -69,9 +70,23 @@ class DoKitMcMainFragment : BaseFragment() { ToastUtils.showShort("当前处于数据录制状态,请先执行上传操作") return@setOnClickListener } - if (activity is DoKitMcActivity) { - (activity as DoKitMcActivity).changeFragment(WSMode.HOST) + if (McConstant.MC_CASE_ID.isEmpty()) { + lifecycleScope.launch(exceptionHandler) { + privacyInterceptDialog( + "操作提醒", + "当前未选中任何的数据用例,请确认要否要以数据不同步模式运行?" + ).isTrueWithCor { + if (activity is DoKitMcActivity) { + (activity as DoKitMcActivity).changeFragment(WSMode.HOST) + } + } + } + } else { + if (activity is DoKitMcActivity) { + (activity as DoKitMcActivity).changeFragment(WSMode.HOST) + } } + } val client = findViewById