Browse Source

1.添加跳转查看训练日报功能

王鹏鹏 2 years ago
parent
commit
7f1b8aa3a7
22 changed files with 820 additions and 14 deletions
  1. 6 0
      .idea/misc.xml
  2. 4 2
      baselib/build.gradle
  3. 2 0
      baselib/src/main/java/com/yingyangfly/baselib/BaseApplication.kt
  4. 5 0
      baselib/src/main/java/com/yingyangfly/baselib/router/RouterUrlCommon.kt
  5. 21 0
      baselib/src/main/java/com/yingyangfly/baselib/webview/JsInterface.kt
  6. 282 0
      baselib/src/main/java/com/yingyangfly/baselib/webview/base/RobustWebView.kt
  7. 55 0
      baselib/src/main/java/com/yingyangfly/baselib/webview/base/WebViewCacheHolder.kt
  8. 43 0
      baselib/src/main/java/com/yingyangfly/baselib/webview/base/WebViewInitTask.kt
  9. 142 0
      baselib/src/main/java/com/yingyangfly/baselib/webview/base/WebViewInterceptRequestProxy.kt
  10. 15 0
      baselib/src/main/java/com/yingyangfly/baselib/webview/utils/ContextHolder.kt
  11. 44 0
      baselib/src/main/java/com/yingyangfly/baselib/webview/utils/Utils.kt
  12. 3 1
      config.gradle
  13. 6 0
      webview/src/main/AndroidManifest.xml
  14. 0 2
      webview/src/main/java/com/yingyangfly/webview/BridgeWebActivity.kt
  15. 88 0
      webview/src/main/java/com/yingyangfly/webview/TencentWebviewActivity.kt
  16. 6 0
      webview/src/main/manifest/AndroidManifest.xml
  17. 10 0
      webview/src/main/res/layout/activity_tencent_webview.xml
  18. 15 5
      webview/src/main/res/layout/activity_webview.xml
  19. 4 0
      webview/src/main/res/values/colors.xml
  20. 56 0
      webview/src/main/res/values/styles.xml
  21. 11 3
      workbenches/src/main/java/com/yingyang/workbenches/datamonitor/DataMonitorFragment.kt
  22. 2 1
      workbenches/src/main/java/com/yingyang/workbenches/entity/DayRecordDetailBean.kt

+ 6 - 0
.idea/misc.xml

@@ -479,6 +479,8 @@
         <entry key="..\:/workspace/hcp-pad/workbenches/src/main/res/layout/spinner_list_item.xml" value="0.1" />
         <entry key="..\:/workspace/hcp-pads/baselib/src/main/res/layout/activity_base.xml" value="0.23697916666666666" />
         <entry key="..\:/workspace/hcp-pads/baselib/src/main/res/layout/rv_empty.xml" value="0.23697916666666666" />
+        <entry key="..\:/workspace/hcp-pads/healthconsultation/src/main/res/layout/activity_consultation_request.xml" value="0.23697916666666666" />
+        <entry key="..\:/workspace/hcp-pads/healthconsultation/src/main/res/layout/activity_payment.xml" value="0.23697916666666666" />
         <entry key="..\:/workspace/hcp-pads/home/src/main/res/layout/activity_home.xml" value="0.23697916666666666" />
         <entry key="..\:/workspace/hcp-pads/livebroadcast/src/main/res/drawable/bg_item_live_broadcast.xml" value="0.1715" />
         <entry key="..\:/workspace/hcp-pads/livebroadcast/src/main/res/drawable/bg_live_status.xml" value="0.1715" />
@@ -500,6 +502,10 @@
         <entry key="..\:/workspace/hcp-pads/push/src/main/res/layout/activity_messge_list.xml" value="0.23697916666666666" />
         <entry key="..\:/workspace/hcp-pads/push/src/main/res/layout/item_push_list.xml" value="0.23697916666666666" />
         <entry key="..\:/workspace/hcp-pads/push/src/main/res/layout/item_push_type.xml" value="0.23697916666666666" />
+        <entry key="..\:/workspace/hcp-pads/webview/src/main/res/layout/activity_tencent_webview.xml" value="0.22239583333333332" />
+        <entry key="..\:/workspace/hcp-pads/webview/src/main/res/layout/activity_webview.xml" value="0.23697916666666666" />
+        <entry key="..\:/workspace/hcp-pads/workbenches/src/main/res/drawable/bg_total_training_duration.xml" value="0.151" />
+        <entry key="..\:/workspace/hcp-pads/workbenches/src/main/res/drawable/bg_training_daily.xml" value="0.151" />
         <entry key="..\:/workspace/hcp-pads/workbenches/src/main/res/drawable/bg_work_benches_btn.xml" value="0.164" />
         <entry key="..\:/workspace/hcp-pads/workbenches/src/main/res/drawable/selector_train_monitor.xml" value="0.164" />
         <entry key="..\:/workspace/hcp-pads/workbenches/src/main/res/drawable/selector_train_radio.xml" value="0.164" />

+ 4 - 2
baselib/build.gradle

@@ -40,7 +40,7 @@ android {
             buildConfigField "String", "BAIDU_SECRETKEY", "\"41Fzb2ZIuKRGNtrVcQOHxEI3vFM4Rkxi\""
             buildConfigField "Boolean", "SINGLE_MODULE", "${singleModule}"
             buildConfigField "String", "BUGLY_APPID", "\"d400f20398\""
-            buildConfigField "String", "API_URL", "\"http://60.205.201.7:8110\""
+            buildConfigField "String", "API_URL", "\"http://192.168.0.66:8110\""
             proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
         }
 
@@ -54,7 +54,7 @@ android {
             buildConfigField "String", "BAIDU_SECRETKEY", "\"41Fzb2ZIuKRGNtrVcQOHxEI3vFM4Rkxi\""
             buildConfigField "Boolean", "SINGLE_MODULE", "${singleModule}"
             buildConfigField "String", "BUGLY_APPID", "\"ad3db4d529\""
-            buildConfigField "String", "API_URL", "\"http://60.205.201.7:8110\""
+            buildConfigField "String", "API_URL", "\"http://192.168.0.66:8110\""
             proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
         }
     }
@@ -143,4 +143,6 @@ dependencies {
     api(rootProject.ext.dependencies.xxPermission)
     debugApi(rootProject.ext.dependencies.leakcanary)
     api(rootProject.ext.dependencies.tbssdk)
+    api(rootProject.ext.dependencies.chuckerteam_chucker)
+    api(rootProject.ext.dependencies.lifecycle)
 }

+ 2 - 0
baselib/src/main/java/com/yingyangfly/baselib/BaseApplication.kt

@@ -13,6 +13,7 @@ import com.scwang.smartrefresh.layout.header.ClassicsHeader
 import com.tencent.bugly.crashreport.CrashReport
 import com.yingyangfly.baselib.config.AccountConfig
 import com.yingyangfly.baselib.utils.LogUtil
+import com.yingyangfly.baselib.webview.base.WebViewInitTask
 import java.lang.reflect.Field
 import java.lang.reflect.Method
 
@@ -71,6 +72,7 @@ open class BaseApplication : Application() {
             formalInitThirdParty()
             closeAndroidPDialog()
             initViews()
+            WebViewInitTask.init(this)
         }
     }
 

+ 5 - 0
baselib/src/main/java/com/yingyangfly/baselib/router/RouterUrlCommon.kt

@@ -30,6 +30,11 @@ object RouterUrlCommon {
      */
     const val WEB_VIEW_INTERACTION_JS = "/web/webViewInteractionJs"
 
+    /**
+     * 腾讯x5 webview
+     */
+    const val WEB_VIEW_TENCENT_WEBVIEW = "/tencent/webview"
+
     /**
      * 个人中心
      */

+ 21 - 0
baselib/src/main/java/com/yingyangfly/baselib/webview/JsInterface.kt

@@ -0,0 +1,21 @@
+package com.yingyangfly.baselib.webview
+
+import android.webkit.JavascriptInterface
+import com.yingyangfly.baselib.webview.utils.log
+import com.yingyangfly.baselib.webview.utils.showToast
+
+/**
+ * @Author: leavesC
+ * @Date: 2021/9/21 15:08
+ * @Desc:
+ * @Github:https://github.com/leavesC
+ */
+class JsInterface {
+
+    @JavascriptInterface
+    fun showToastByAndroid(log: String) {
+        log("showToastByAndroid:$log")
+//        showToast(log)
+    }
+
+}

+ 282 - 0
baselib/src/main/java/com/yingyangfly/baselib/webview/base/RobustWebView.kt

@@ -0,0 +1,282 @@
+package com.yingyangfly.baselib.webview.base
+
+import android.content.Context
+import android.content.MutableContextWrapper
+import android.graphics.Bitmap
+import android.util.AttributeSet
+import android.view.ViewGroup
+import androidx.lifecycle.DefaultLifecycleObserver
+import androidx.lifecycle.LifecycleOwner
+import com.tencent.smtt.export.external.interfaces.*
+import com.tencent.smtt.sdk.*
+import com.yingyangfly.baselib.webview.JsInterface
+import com.yingyangfly.baselib.webview.utils.log
+import java.io.File
+
+/**
+ * @Author: leavesC
+ * @Date: 2021/9/20 22:45
+ * @Desc:
+ * @Github:https://github.com/leavesC
+ */
+interface WebViewListener {
+
+    fun onProgressChanged(webView: RobustWebView, progress: Int) {
+
+    }
+
+    fun onReceivedTitle(webView: RobustWebView, title: String) {
+
+    }
+
+    fun onPageFinished(webView: RobustWebView, url: String) {
+
+    }
+
+}
+
+class RobustWebView(context: Context, attributeSet: AttributeSet? = null) :
+    WebView(context, attributeSet) {
+
+    private val baseCacheDir by lazy {
+        File(context.cacheDir, "webView")
+    }
+
+    private val databaseCachePath by lazy {
+        File(baseCacheDir, "databaseCache").absolutePath
+    }
+
+    private val appCachePath by lazy {
+        File(baseCacheDir, "appCache").absolutePath
+    }
+
+    var hostLifecycleOwner: LifecycleOwner? = null
+
+    var webViewListener: WebViewListener? = null
+
+    private val mWebChromeClient = object : WebChromeClient() {
+
+        override fun onProgressChanged(webView: WebView, newProgress: Int) {
+            super.onProgressChanged(webView, newProgress)
+            log("onProgressChanged-$newProgress")
+            webViewListener?.onProgressChanged(this@RobustWebView, newProgress)
+        }
+
+        override fun onReceivedTitle(webView: WebView, title: String?) {
+            super.onReceivedTitle(webView, title)
+            log("onReceivedTitle-$title")
+            webViewListener?.onReceivedTitle(this@RobustWebView, title ?: "")
+        }
+
+        override fun onJsAlert(
+            webView: WebView,
+            url: String?,
+            message: String?,
+            result: JsResult
+        ): Boolean {
+            log("onJsAlert: $webView $message")
+            return super.onJsAlert(webView, url, message, result)
+        }
+
+        override fun onJsConfirm(
+            webView: WebView,
+            url: String?,
+            message: String?,
+            result: JsResult
+        ): Boolean {
+            log("onJsConfirm: $url $message")
+            return super.onJsConfirm(webView, url, message, result)
+        }
+
+        override fun onJsPrompt(
+            webView: WebView,
+            url: String?,
+            message: String?,
+            defaultValue: String?,
+            result: JsPromptResult?
+        ): Boolean {
+            log("onJsPrompt: $url $message $defaultValue")
+            return super.onJsPrompt(webView, url, message, defaultValue, result)
+        }
+    }
+
+    private val mWebViewClient = object : WebViewClient() {
+
+        private var startTime = 0L
+
+        override fun shouldOverrideUrlLoading(webView: WebView, url: String): Boolean {
+            webView.loadUrl(url)
+            return true
+        }
+
+        override fun onPageStarted(webView: WebView, url: String?, favicon: Bitmap?) {
+            super.onPageStarted(webView, url, favicon)
+            startTime = System.currentTimeMillis()
+        }
+
+        override fun onPageFinished(webView: WebView, url: String?) {
+            super.onPageFinished(webView, url)
+            log("onPageFinished-$url")
+            webViewListener?.onPageFinished(this@RobustWebView, url ?: "")
+            log("onPageFinished duration: " + (System.currentTimeMillis() - startTime))
+        }
+
+        override fun onReceivedSslError(
+            webView: WebView,
+            handler: SslErrorHandler?,
+            error: SslError?
+        ) {
+            log("onReceivedSslError-$error")
+            super.onReceivedSslError(webView, handler, error)
+        }
+
+        override fun shouldInterceptRequest(webView: WebView, url: String): WebResourceResponse? {
+            return super.shouldInterceptRequest(webView, url)
+        }
+
+        override fun shouldInterceptRequest(
+            webView: WebView,
+            request: WebResourceRequest
+        ): WebResourceResponse? {
+            return WebViewInterceptRequestProxy.shouldInterceptRequest(request)
+                ?: super.shouldInterceptRequest(webView, request)
+        }
+    }
+
+    init {
+        webViewClient = mWebViewClient
+        webChromeClient = mWebChromeClient
+        initWebViewSettings(this)
+        initWebViewSettingsExtension(this)
+        addJavascriptInterface(JsInterface(), "android")
+        setDownloadListener { url, userAgent, contentDisposition, mimetype, contentLength ->
+            log(
+                "setDownloadListener: $url \n" +
+                        "$userAgent \n " +
+                        " $contentDisposition \n" +
+                        " $mimetype \n" +
+                        " $contentLength"
+            )
+        }
+    }
+
+    fun toLoadUrl(url: String, cookie: String) {
+        val mCookieManager = CookieManager.getInstance()
+        mCookieManager?.setCookie(url, cookie)
+        mCookieManager?.flush()
+        loadUrl(url)
+    }
+
+    fun toGoBack(): Boolean {
+        if (canGoBack()) {
+            goBack()
+            return false
+        }
+        return true
+    }
+
+    private fun initWebViewSettings(webView: WebView) {
+        val settings = webView.settings
+
+        settings.userAgentString = "android-leavesC"
+
+        settings.javaScriptEnabled = true
+        settings.pluginsEnabled = true
+
+        settings.useWideViewPort = true
+        settings.loadWithOverviewMode = true
+
+        settings.setSupportZoom(false)
+        settings.builtInZoomControls = false
+//        settings.displayZoomControls = false
+
+        settings.allowFileAccess = true
+        settings.allowContentAccess = true
+
+        settings.loadsImagesAutomatically = true
+
+        settings.safeBrowsingEnabled = false
+
+        settings.domStorageEnabled = true
+        settings.databaseEnabled = true
+        settings.databasePath = databaseCachePath
+        settings.setAppCacheEnabled(true)
+        settings.setAppCachePath(appCachePath)
+        settings.cacheMode = WebSettings.LOAD_DEFAULT
+
+        settings.javaScriptCanOpenWindowsAutomatically = true
+        settings.mixedContentMode = android.webkit.WebSettings.MIXED_CONTENT_ALWAYS_ALLOW
+    }
+
+    private fun initWebViewSettingsExtension(webView: WebView) {
+        val settingsExtension = webView.settingsExtension ?: return
+        //开启后前进后退将不再重新加载页面
+        settingsExtension.setContentCacheEnable(true)
+        //对于刘海屏机器如果WebView被遮挡会自动padding
+        settingsExtension.setDisplayCutoutEnable(true)
+        settingsExtension.setDayOrNight(true)
+    }
+
+    override fun onAttachedToWindow() {
+        super.onAttachedToWindow()
+        log("onAttachedToWindow : $context")
+        (hostLifecycleOwner ?: findLifecycleOwner(context))?.let {
+            addHostLifecycleObserver(it)
+        }
+    }
+
+    private fun findLifecycleOwner(context: Context): LifecycleOwner? {
+        if (context is LifecycleOwner) {
+            return context
+        }
+        if (context is MutableContextWrapper) {
+            val baseContext = context.baseContext
+            if (baseContext is LifecycleOwner) {
+                return baseContext
+            }
+        }
+        return null
+    }
+
+    private fun addHostLifecycleObserver(lifecycleOwner: LifecycleOwner) {
+        log("addLifecycleObserver")
+        lifecycleOwner.lifecycle.addObserver(object : DefaultLifecycleObserver {
+            override fun onResume(owner: LifecycleOwner) {
+                onHostResume()
+            }
+
+            override fun onPause(owner: LifecycleOwner) {
+                onHostPause()
+            }
+
+            override fun onDestroy(owner: LifecycleOwner) {
+                onHostDestroy()
+            }
+        })
+    }
+
+    private fun onHostResume() {
+        log("onHostResume")
+        onResume()
+    }
+
+    private fun onHostPause() {
+        log("onHostPause")
+        onPause()
+    }
+
+    private fun onHostDestroy() {
+        log("onHostDestroy")
+        release()
+    }
+
+    private fun release() {
+        hostLifecycleOwner = null
+        webViewListener = null
+        webChromeClient = null
+        webViewClient = null
+        (parent as? ViewGroup)?.removeView(this)
+        destroy()
+    }
+
+}

+ 55 - 0
baselib/src/main/java/com/yingyangfly/baselib/webview/base/WebViewCacheHolder.kt

@@ -0,0 +1,55 @@
+package com.yingyangfly.baselib.webview.base
+
+import android.app.Application
+import android.content.Context
+import android.content.MutableContextWrapper
+import android.os.Looper
+import com.yingyangfly.baselib.webview.utils.log
+import java.util.*
+
+/**
+ * @Author: leavesC
+ * @Date: 2021/10/4 18:57
+ * @Desc:
+ * @公众号:字节数组
+ */
+object WebViewCacheHolder {
+
+    private val webViewCacheStack = Stack<RobustWebView>()
+
+    private const val CACHED_WEB_VIEW_MAX_NUM = 4
+
+    private lateinit var application: Application
+
+    fun init(application: Application) {
+        WebViewCacheHolder.application = application
+        prepareWebView()
+    }
+
+    fun prepareWebView() {
+        if (webViewCacheStack.size < CACHED_WEB_VIEW_MAX_NUM) {
+            Looper.myQueue().addIdleHandler {
+                log("WebViewCacheStack Size: " + webViewCacheStack.size)
+                if (webViewCacheStack.size < CACHED_WEB_VIEW_MAX_NUM) {
+                    webViewCacheStack.push(createWebView(MutableContextWrapper(application)))
+                }
+                false
+            }
+        }
+    }
+
+    fun acquireWebViewInternal(context: Context): RobustWebView {
+        if (webViewCacheStack.isEmpty()) {
+            return createWebView(context)
+        }
+        val webView = webViewCacheStack.pop()
+        val contextWrapper = webView.context as MutableContextWrapper
+        contextWrapper.baseContext = context
+        return webView
+    }
+
+    private fun createWebView(context: Context): RobustWebView {
+        return RobustWebView(context)
+    }
+
+}

+ 43 - 0
baselib/src/main/java/com/yingyangfly/baselib/webview/base/WebViewInitTask.kt

@@ -0,0 +1,43 @@
+package com.yingyangfly.baselib.webview.base
+
+import android.app.Application
+import android.content.Context
+import com.tencent.smtt.export.external.TbsCoreSettings
+import com.tencent.smtt.sdk.QbSdk
+import com.yingyangfly.baselib.webview.utils.log
+import com.yingyangfly.baselib.webview.utils.showToast
+
+/**
+ * @Author: leavesC
+ * @Date: 2021/9/20 23:47
+ * @Desc:
+ * @Github:https://github.com/leavesC
+ */
+object WebViewInitTask {
+
+    fun init(application: Application) {
+        initWebView(application)
+        WebViewCacheHolder.init(application)
+        WebViewInterceptRequestProxy.init(application)
+    }
+
+    private fun initWebView(context: Context) {
+        QbSdk.setDownloadWithoutWifi(true)
+        val map = mutableMapOf<String, Any>()
+        map[TbsCoreSettings.TBS_SETTINGS_USE_SPEEDY_CLASSLOADER] = true
+        map[TbsCoreSettings.TBS_SETTINGS_USE_DEXLOADER_SERVICE] = true
+        QbSdk.initTbsSettings(map)
+        val cb: QbSdk.PreInitCallback = object : QbSdk.PreInitCallback {
+            override fun onViewInitFinished(arg0: Boolean) {
+//                showToast("onViewInitFinished: $arg0")
+                log("onViewInitFinished: $arg0")
+            }
+
+            override fun onCoreInitFinished() {
+                log("onCoreInitFinished")
+            }
+        }
+        QbSdk.initX5Environment(context, cb)
+    }
+
+}

+ 142 - 0
baselib/src/main/java/com/yingyangfly/baselib/webview/base/WebViewInterceptRequestProxy.kt

@@ -0,0 +1,142 @@
+package com.yingyangfly.baselib.webview.base
+
+import android.app.Application
+import android.net.Uri
+import com.chuckerteam.chucker.api.ChuckerCollector
+import com.chuckerteam.chucker.api.ChuckerInterceptor
+import com.tencent.smtt.export.external.interfaces.WebResourceRequest
+import com.tencent.smtt.export.external.interfaces.WebResourceResponse
+import com.yingyangfly.baselib.webview.utils.log
+import okhttp3.Cache
+import okhttp3.OkHttpClient
+import okhttp3.Request
+import java.io.File
+
+/**
+ * @Author: leavesC
+ * @Date: 2021/10/4 18:56
+ * @Desc:
+ * @公众号:字节数组
+ */
+object WebViewInterceptRequestProxy {
+
+    private lateinit var application: Application
+
+    private val webViewResourceCacheDir by lazy {
+        File(application.cacheDir, "RobustWebView")
+    }
+
+    private val okHttpClient by lazy {
+        OkHttpClient.Builder().cache(Cache(webViewResourceCacheDir, 100L * 1024 * 1024))
+            .followRedirects(false)
+            .followSslRedirects(false)
+            .addNetworkInterceptor(
+                ChuckerInterceptor.Builder(application)
+                    .collector(ChuckerCollector(application))
+                    .maxContentLength(250000L)
+                    .alwaysReadResponseBody(true)
+                    .build()
+            )
+            .build()
+    }
+
+    fun init(application: Application) {
+        WebViewInterceptRequestProxy.application = application
+    }
+
+    fun shouldInterceptRequest(webResourceRequest: WebResourceRequest?): WebResourceResponse? {
+        if (webResourceRequest == null || webResourceRequest.isForMainFrame) {
+            return null
+        }
+        val url = webResourceRequest.url ?: return null
+        if (isHttpUrl(url)) {
+            return getHttpResource(url.toString(), webResourceRequest)
+        }
+        return null
+    }
+
+    private fun isHttpUrl(url: Uri): Boolean {
+        val scheme = url.scheme
+        log("url: $url")
+        log("scheme: $scheme")
+        if (scheme == "http" || scheme == "https") {
+            return true
+        }
+        return false
+    }
+
+    private fun getHttpResource(
+        url: String,
+        webResourceRequest: WebResourceRequest
+    ): WebResourceResponse? {
+        val method = webResourceRequest.method
+        if (method.equals("GET", true)) {
+            try {
+                val requestBuilder =
+                    Request.Builder().url(url).method(webResourceRequest.method, null)
+                val requestHeaders = webResourceRequest.requestHeaders
+                if (!requestHeaders.isNullOrEmpty()) {
+                    var requestHeadersLog = ""
+                    requestHeaders.forEach {
+                        requestBuilder.addHeader(it.key, it.value)
+                        requestHeadersLog = it.key + " : " + it.value + "\n" + requestHeadersLog
+                    }
+                    log("requestHeaders: $requestHeadersLog")
+                }
+                val response = okHttpClient.newCall(requestBuilder.build())
+                    .execute()
+                val body = response.body
+                if (body != null) {
+                    val mimeType = response.header(
+                        "content-type", body.contentType()?.type
+                    ).apply {
+                        log(this)
+                    }
+                    val encoding = response.header(
+                        "content-encoding",
+                        "utf-8"
+                    ).apply {
+                        log(this)
+                    }
+                    val responseHeaders = mutableMapOf<String, String>()
+                    var responseHeadersLog = ""
+                    for (header in response.headers) {
+                        responseHeaders[header.first] = header.second
+                        responseHeadersLog =
+                            header.first + " : " + header.second + "\n" + responseHeadersLog
+                    }
+                    log("responseHeadersLog: $responseHeadersLog")
+                    var message = response.message
+                    val code = response.code
+                    if (code == 200 && message.isBlank()) {
+                        message = "OK"
+                    }
+                    val resourceResponse =
+                        WebResourceResponse(mimeType, encoding, body.byteStream())
+                    resourceResponse.responseHeaders = responseHeaders
+                    resourceResponse.setStatusCodeAndReasonPhrase(code, message)
+                    return resourceResponse
+                }
+            } catch (e: Throwable) {
+                log("Throwable: $e")
+            }
+        }
+        return null
+    }
+
+    private fun getAssetsImage(url: String): WebResourceResponse? {
+        if (url.contains(".jpg")) {
+            try {
+                val inputStream = application.assets.open("ic_launcher.webp")
+                return WebResourceResponse(
+                    "image/webp",
+                    "utf-8", inputStream
+                )
+            } catch (e: Throwable) {
+                log("Throwable: $e")
+            }
+        }
+        return null
+    }
+
+}

+ 15 - 0
baselib/src/main/java/com/yingyangfly/baselib/webview/utils/ContextHolder.kt

@@ -0,0 +1,15 @@
+package com.yingyangfly.baselib.webview.utils
+
+import android.app.Application
+
+/**
+ * @Author: leavesC
+ * @Date: 2021/10/1 23:16
+ * @Desc:
+ * @Github:https://github.com/leavesC
+ */
+object ContextHolder {
+
+    lateinit var application: Application
+
+}

+ 44 - 0
baselib/src/main/java/com/yingyangfly/baselib/webview/utils/Utils.kt

@@ -0,0 +1,44 @@
+package com.yingyangfly.baselib.webview.utils
+
+import android.os.Build
+import android.util.Log
+import android.view.View
+import android.view.ViewParent
+import android.widget.Toast
+import java.lang.reflect.Method
+
+/**
+ * @Author: leavesC
+ * @Date: 2021/9/20 0:11
+ * @Desc:
+ * @Github:https://github.com/leavesC
+ */
+fun log(log: Any?) {
+    Log.e("RobustWebView-" + Thread.currentThread().name, log.toString())
+}
+
+fun showToast(msg: String) {
+    Toast.makeText(ContextHolder.application, msg, Toast.LENGTH_SHORT).show()
+}
+
+
+/**
+ * 让 activity transition 动画过程中可以正常渲染页面
+ */
+fun setDrawDuringWindowsAnimating(view: View) {
+    if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M
+        || Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1
+    ) {
+        //小于 4.3 和大于 6.0 时不存在此问题,无须处理
+        return
+    }
+    try {
+        val rootParent: ViewParent = view.rootView.parent
+        val method: Method = rootParent.javaClass
+            .getDeclaredMethod("setDrawDuringWindowsAnimating", Boolean::class.javaPrimitiveType)
+        method.isAccessible = true
+        method.invoke(rootParent, true)
+    } catch (e: Throwable) {
+        e.printStackTrace()
+    }
+}

+ 3 - 1
config.gradle

@@ -120,6 +120,8 @@ ext {
             "Luban"                    : 'top.zibin:Luban:1.1.8',
             // 动态申请权限 https://github.com/getActivity/XXPermissions
             "xxPermission"             : "com.github.getActivity:XXPermissions:18.3",
-            "tbssdk"                   : 'com.tencent.tbs:tbssdk:44085'
+            "tbssdk"                   : 'com.tencent.tbs:tbssdk:44085',
+            "lifecycle"                : 'androidx.lifecycle:lifecycle-common-java8:2.3.1',
+            "chuckerteam_chucker"      :'com.github.chuckerteam.chucker:library-no-op:3.5.2'
     ]
 }

+ 6 - 0
webview/src/main/AndroidManifest.xml

@@ -22,6 +22,12 @@
             android:configChanges="keyboardHidden|orientation|screenSize"
             android:screenOrientation="landscape"
             android:windowSoftInputMode="adjustResize|adjustPan" />
+
+        <activity
+            android:name=".TencentWebviewActivity"
+            android:configChanges="keyboardHidden|orientation|screenSize"
+            android:screenOrientation="landscape"
+            android:windowSoftInputMode="adjustResize|adjustPan" />
     </application>
 
 </manifest>

+ 0 - 2
webview/src/main/java/com/yingyangfly/webview/BridgeWebActivity.kt

@@ -25,7 +25,6 @@ import com.yingyangfly.baselib.player.VoicePlayer
 import com.yingyangfly.baselib.router.RouterUrlCommon
 import com.yingyangfly.baselib.utils.LiveEventBusUtil
 import com.yingyangfly.baselib.utils.RxBusCodes
-import com.yingyangfly.baselib.utils.ViewTool
 import com.yingyangfly.webview.databinding.ActivityBridgeWebBinding
 import com.yingyangfly.webview.net.WebViewServiceFactory
 import io.reactivex.schedulers.Schedulers
@@ -56,7 +55,6 @@ class BridgeWebActivity : AppCompatActivity() {
         voicePlayer = VoicePlayer.getInstance(this)
         url = intent.getStringExtra("url") ?: ""
         binding = DataBindingUtil.setContentView(this, R.layout.activity_bridge_web)
-        ViewTool.inflateLayoutPixels(this, binding.root, 1194, 834)
         requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
         initWebView()
         initView()

+ 88 - 0
webview/src/main/java/com/yingyangfly/webview/TencentWebviewActivity.kt

@@ -0,0 +1,88 @@
+package com.yingyangfly.webview
+
+import android.content.pm.ActivityInfo
+import android.os.Bundle
+import android.text.TextUtils
+import android.view.ViewGroup
+import androidx.appcompat.app.AppCompatActivity
+import com.alibaba.android.arouter.facade.annotation.Route
+import com.gyf.immersionbar.BarHide
+import com.gyf.immersionbar.ktx.immersionBar
+import com.yingyangfly.baselib.db.AppDataBase
+import com.yingyangfly.baselib.db.VoicePlayerDao
+import com.yingyangfly.baselib.player.VoicePlayer
+import com.yingyangfly.baselib.router.RouterUrlCommon
+import com.yingyangfly.baselib.webview.base.RobustWebView
+import com.yingyangfly.baselib.webview.base.WebViewCacheHolder
+import com.yingyangfly.baselib.webview.base.WebViewListener
+
+@Route(path = RouterUrlCommon.WEB_VIEW_TENCENT_WEBVIEW)
+class TencentWebviewActivity : AppCompatActivity() {
+
+    private var url: String = ""
+    private var db: AppDataBase? = null
+    private var dao: VoicePlayerDao? = null
+    private var voicePlayer: VoicePlayer? = null
+
+    private val rootLayout by lazy {
+        findViewById<ViewGroup>(R.id.rootLayout)
+    }
+
+    private lateinit var webView: RobustWebView
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        immersionBar {
+            hideBar(BarHide.FLAG_HIDE_BAR)
+            navigationBarColor(R.color.transparent)
+        }
+        setContentView(R.layout.activity_tencent_webview)
+        requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
+        db = AppDataBase.getInstance(this)
+        if (db != null) {
+            dao = db?.getVoicePlayerDao()
+        }
+        voicePlayer = VoicePlayer.getInstance(this)
+        url = intent.getStringExtra("url") ?: ""
+        webView = WebViewCacheHolder.acquireWebViewInternal(this)
+        webView.webViewListener = webViewListener
+        rootLayout.addView(webView)
+        if (TextUtils.isEmpty(url).not()) {
+            webView.loadUrl(url)
+        }
+    }
+
+    override fun onDestroy() {
+        if (voicePlayer != null) {
+            if (voicePlayer!!.isPlaying) {
+                voicePlayer?.stop()
+            }
+        }
+        super.onDestroy()
+        WebViewCacheHolder.prepareWebView()
+    }
+
+    private val webViewListener = object : WebViewListener {
+        override fun onProgressChanged(webView: RobustWebView, progress: Int) {
+
+        }
+
+        override fun onReceivedTitle(webView: RobustWebView, title: String) {
+
+        }
+
+        override fun onPageFinished(webView: RobustWebView, url: String) {
+
+        }
+    }
+
+    override fun onResume() {
+        /**
+         * 设置为横屏
+         */
+        if (requestedOrientation != ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) {
+            requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
+        }
+        super.onResume()
+    }
+}

+ 6 - 0
webview/src/main/manifest/AndroidManifest.xml

@@ -16,6 +16,12 @@
             android:configChanges="keyboardHidden|orientation|screenSize"
             android:screenOrientation="landscape"
             android:windowSoftInputMode="adjustResize|adjustPan" />
+
+        <activity
+            android:name=".TencentWebviewActivity"
+            android:configChanges="keyboardHidden|orientation|screenSize"
+            android:screenOrientation="landscape"
+            android:windowSoftInputMode="adjustResize|adjustPan" />
     </application>
 
 </manifest>

+ 10 - 0
webview/src/main/res/layout/activity_tencent_webview.xml

@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/rootLayout"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="@android:color/white"
+    tools:ignore="ResourceName">
+
+</FrameLayout>

+ 15 - 5
webview/src/main/res/layout/activity_webview.xml

@@ -1,21 +1,31 @@
 <?xml version="1.0" encoding="utf-8"?>
-<layout xmlns:tools="http://schemas.android.com/tools"
-    xmlns:android="http://schemas.android.com/apk/res/android"
+<layout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
     tools:ignore="ResourceName">
 
     <data>
 
     </data>
 
-    <LinearLayout
+    <FrameLayout
         android:layout_width="match_parent"
         android:layout_height="match_parent">
 
         <WebView
             android:id="@+id/web"
             android:layout_width="match_parent"
-            android:layout_height="match_parent"/>
+            android:layout_height="match_parent" />
 
-    </LinearLayout>
+        <LinearLayout
+            android:id="@+id/layoutHead"
+            style="@style/back_home_layout"
+            tools:ignore="MissingConstraints">
+
+            <androidx.appcompat.widget.AppCompatImageView style="@style/back_home_image" />
+
+            <androidx.appcompat.widget.AppCompatTextView style="@style/back_home_text" />
+        </LinearLayout>
+
+    </FrameLayout>
 
 </layout>

+ 4 - 0
webview/src/main/res/values/colors.xml

@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources xmlns:tools="http://schemas.android.com/tools">
+    <color name="transparent" tools:ignore="ResourceName">#00000000</color><!-- 透明   -->
+</resources>

+ 56 - 0
webview/src/main/res/values/styles.xml

@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools">
+
+    <!--自适应高度-->
+    <style name="layout_properties_self_adaption" tools:ignore="ResourceName">
+        <item name="android:layout_width">wrap_content</item>
+        <item name="android:layout_height">wrap_content</item>
+    </style>
+
+    <!--自适应高度 居中-->
+    <style name="layout_properties_self_adaption_center" parent="layout_properties_self_adaption" tools:ignore="ResourceName">
+        <item name="layout_constraintStart_toStartOf">parent</item>
+        <item name="layout_constraintEnd_toEndOf">parent</item>
+        <item name="layout_constraintTop_toTopOf">parent</item>
+        <item name="layout_constraintBottom_toBottomOf">parent</item>
+    </style>
+
+    <!--指定宽度和高度-->
+    <style name="layout_properties_specify_width_geight" tools:ignore="ResourceName">
+        <item name="android:layout_width">match_parent</item>
+        <item name="android:layout_height">match_parent</item>
+    </style>
+
+    <!--指定宽度和高度-->
+    <style name="layout_properties_specify_width_geight_center" parent="layout_properties_specify_width_geight" tools:ignore="ResourceName">
+        <item name="layout_constraintStart_toStartOf">parent</item>
+        <item name="layout_constraintEnd_toEndOf">parent</item>
+        <item name="layout_constraintTop_toTopOf">parent</item>
+        <item name="layout_constraintBottom_toBottomOf">parent</item>
+    </style>
+
+    <!--指定宽度-->
+    <style name="layout_properties_specify_width" tools:ignore="ResourceName">
+        <item name="android:layout_width">match_parent</item>
+        <item name="android:layout_height">wrap_content</item>
+    </style>
+
+    <!--指定宽度-->
+    <style name="layout_properties_specify_width_center" parent="layout_properties_specify_width" tools:ignore="ResourceName">
+        <item name="layout_constraintStart_toStartOf">parent</item>
+        <item name="layout_constraintEnd_toEndOf">parent</item>
+        <item name="layout_constraintTop_toTopOf">parent</item>
+        <item name="layout_constraintBottom_toBottomOf">parent</item>
+    </style>
+
+    <style name="back_home_layout" tools:ignore="ResourceName">
+        <item name="android:layout_width">@dimen/divider_195px</item>
+        <item name="android:layout_height">wrap_content</item>
+        <item name="android:orientation">horizontal</item>
+        <item name="layout_constraintStart_toStartOf">parent</item>
+        <item name="layout_constraintTop_toTopOf">parent</item>
+    </style>
+
+
+
+</resources>

+ 11 - 3
workbenches/src/main/java/com/yingyang/workbenches/datamonitor/DataMonitorFragment.kt

@@ -39,6 +39,11 @@ class DataMonitorFragment : BaseMVVMFragment<FragmentDataMonitorBinding, DataMon
     private var dataMonitorList = mutableListOf<Record>()
     private val dataMonitorAdapter by lazy { DataMonitorAdapter() }
 
+    /**
+     * 每日训练报告连接入口
+     */
+    private var url: String = ""
+
     override fun initViews() {
         binding {
             swipeWeek.setEnableLoadMore(true)
@@ -83,9 +88,11 @@ class DataMonitorFragment : BaseMVVMFragment<FragmentDataMonitorBinding, DataMon
             }
 
             btnTrainingDaily.setOnSingleClickListener {
-                val url =
-                    "http://60.205.201.7/hcp-h5/?userId=" + User.getUserId() + "&time=" + selectedTime + "&userToken=" + User.getToken()
-                JumpUtil.jumpActivityWithUrl(RouterUrlCommon.WEB_VIEW_INTERACTION_JS, url, mContext)
+                if (TextUtils.isEmpty(url).not()) {
+                    val trainingDailyUrl = url +
+                            "?userId=" + User.getUserId() + "&time=" + selectedTime + "&userToken=" + User.getToken()
+                    JumpUtil.jumpActivityWithUrl(RouterUrlCommon.load_web_view, trainingDailyUrl, mContext)
+                }
             }
         }
     }
@@ -146,6 +153,7 @@ class DataMonitorFragment : BaseMVVMFragment<FragmentDataMonitorBinding, DataMon
                 } else {
                     binding.swipeWeek.finishLoadMoreWithNoMoreData()
                 }
+                url = it.url
             }
             dataMonitorAdapter.setData(dataMonitorList)
         })

+ 2 - 1
workbenches/src/main/java/com/yingyang/workbenches/entity/DayRecordDetailBean.kt

@@ -5,5 +5,6 @@ package com.yingyang.workbenches.entity
  */
 data class DayRecordDetailBean(
     val record: List<Record>,
-    val time: String
+    val time: String,
+    val url: String
 )