pull/1352/head
gedoor 3 years ago
parent fbee6a9dd3
commit c2ae61b71c
  1. 14
      app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt
  2. 174
      app/src/main/java/io/legado/app/ui/web/WebViewActivity.kt
  3. 54
      app/src/main/java/io/legado/app/ui/web/WebViewModel.kt
  4. 32
      app/src/main/res/layout/activity_web_view.xml

@ -109,8 +109,8 @@ class ReadRssActivity : VMBaseActivity<ActivityRssReadBinding, ReadRssViewModel>
@SuppressLint("SetJavaScriptEnabled") @SuppressLint("SetJavaScriptEnabled")
private fun initWebView() { private fun initWebView() {
binding.webView.webChromeClient = RssWebChromeClient() binding.webView.webChromeClient = CustomWebChromeClient()
binding.webView.webViewClient = RssWebViewClient() binding.webView.webViewClient = CustomWebViewClient()
binding.webView.settings.apply { binding.webView.settings.apply {
mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW
domStorageEnabled = true domStorageEnabled = true
@ -124,8 +124,7 @@ class ReadRssActivity : VMBaseActivity<ActivityRssReadBinding, ReadRssViewModel>
hitTestResult.type == WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE hitTestResult.type == WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE
) { ) {
hitTestResult.extra?.let { hitTestResult.extra?.let {
webPic = it saveImage(it)
saveImage()
return@setOnLongClickListener true return@setOnLongClickListener true
} }
} }
@ -140,7 +139,8 @@ class ReadRssActivity : VMBaseActivity<ActivityRssReadBinding, ReadRssViewModel>
} }
private fun saveImage() { private fun saveImage(webPic: String) {
this.webPic = webPic
val path = ACache.get(this@ReadRssActivity).getAsString(imagePathKey) val path = ACache.get(this@ReadRssActivity).getAsString(imagePathKey)
if (path.isNullOrEmpty()) { if (path.isNullOrEmpty()) {
selectSaveFolder() selectSaveFolder()
@ -281,7 +281,7 @@ class ReadRssActivity : VMBaseActivity<ActivityRssReadBinding, ReadRssViewModel>
binding.webView.destroy() binding.webView.destroy()
} }
inner class RssWebChromeClient : WebChromeClient() { inner class CustomWebChromeClient : WebChromeClient() {
override fun onShowCustomView(view: View?, callback: CustomViewCallback?) { override fun onShowCustomView(view: View?, callback: CustomViewCallback?) {
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR
binding.llView.invisible() binding.llView.invisible()
@ -296,7 +296,7 @@ class ReadRssActivity : VMBaseActivity<ActivityRssReadBinding, ReadRssViewModel>
} }
} }
inner class RssWebViewClient : WebViewClient() { inner class CustomWebViewClient : WebViewClient() {
override fun shouldOverrideUrlLoading( override fun shouldOverrideUrlLoading(
view: WebView?, view: WebView?,
request: WebResourceRequest? request: WebResourceRequest?

@ -0,0 +1,174 @@
package io.legado.app.ui.web
import android.annotation.SuppressLint
import android.content.pm.ActivityInfo
import android.net.Uri
import android.os.Bundle
import android.view.View
import android.webkit.*
import androidx.activity.viewModels
import androidx.webkit.WebSettingsCompat
import androidx.webkit.WebViewFeature
import io.legado.app.R
import io.legado.app.base.VMBaseActivity
import io.legado.app.constant.AppConst
import io.legado.app.databinding.ActivityWebViewBinding
import io.legado.app.help.AppConfig
import io.legado.app.lib.dialogs.SelectItem
import io.legado.app.model.Download
import io.legado.app.ui.association.OnLineImportActivity
import io.legado.app.ui.document.HandleFileContract
import io.legado.app.utils.*
import io.legado.app.utils.viewbindingdelegate.viewBinding
class WebViewActivity : VMBaseActivity<ActivityWebViewBinding, WebViewModel>() {
override val binding by viewBinding(ActivityWebViewBinding::inflate)
override val viewModel by viewModels<WebViewModel>()
private val imagePathKey = "imagePath"
private var customWebViewCallback: WebChromeClient.CustomViewCallback? = null
private var webPic: String? = null
private val saveImage = registerForActivityResult(HandleFileContract()) {
it ?: return@registerForActivityResult
ACache.get(this).put(imagePathKey, it.toString())
viewModel.saveImage(webPic, it.toString())
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
initWebView()
}
@SuppressLint("JavascriptInterface")
private fun initWebView() {
binding.webView.webChromeClient = CustomWebChromeClient()
binding.webView.webViewClient = CustomWebViewClient()
binding.webView.settings.apply {
mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW
domStorageEnabled = true
allowContentAccess = true
}
binding.webView.addJavascriptInterface(this, "app")
upWebViewTheme()
binding.webView.setOnLongClickListener {
val hitTestResult = binding.webView.hitTestResult
if (hitTestResult.type == WebView.HitTestResult.IMAGE_TYPE ||
hitTestResult.type == WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE
) {
hitTestResult.extra?.let {
saveImage(it)
return@setOnLongClickListener true
}
}
return@setOnLongClickListener false
}
binding.webView.setDownloadListener { url, _, contentDisposition, _, _ ->
val fileName = URLUtil.guessFileName(url, contentDisposition, null)
binding.llView.longSnackbar(fileName, getString(R.string.action_download)) {
Download.start(this, url, fileName)
}
}
}
private fun upWebViewTheme() {
if (AppConfig.isNightTheme) {
if (WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK_STRATEGY)) {
WebSettingsCompat.setForceDarkStrategy(
binding.webView.settings,
WebSettingsCompat.DARK_STRATEGY_PREFER_WEB_THEME_OVER_USER_AGENT_DARKENING
)
}
if (WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK)) {
WebSettingsCompat.setForceDark(
binding.webView.settings,
WebSettingsCompat.FORCE_DARK_ON
)
} else {
binding.webView
.evaluateJavascript(AppConst.darkWebViewJs, null)
}
}
}
private fun saveImage(webPic: String) {
this.webPic = webPic
val path = ACache.get(this).getAsString(imagePathKey)
if (path.isNullOrEmpty()) {
selectSaveFolder()
} else {
viewModel.saveImage(webPic, path)
}
}
private fun selectSaveFolder() {
val default = arrayListOf<SelectItem<Int>>()
val path = ACache.get(this).getAsString(imagePathKey)
if (!path.isNullOrEmpty()) {
default.add(SelectItem(path, -1))
}
saveImage.launch {
otherActions = default
}
}
inner class CustomWebChromeClient : WebChromeClient() {
override fun onShowCustomView(view: View?, callback: CustomViewCallback?) {
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR
binding.llView.invisible()
binding.customWebView.addView(view)
customWebViewCallback = callback
}
override fun onHideCustomView() {
binding.customWebView.removeAllViews()
binding.llView.visible()
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
}
}
inner class CustomWebViewClient : WebViewClient() {
override fun shouldOverrideUrlLoading(
view: WebView?,
request: WebResourceRequest?
): Boolean {
request?.let {
return shouldOverrideUrlLoading(it.url)
}
return true
}
@Suppress("DEPRECATION")
override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean {
url?.let {
return shouldOverrideUrlLoading(Uri.parse(it))
}
return true
}
override fun onPageFinished(view: WebView?, url: String?) {
super.onPageFinished(view, url)
upWebViewTheme()
}
private fun shouldOverrideUrlLoading(url: Uri): Boolean {
when (url.scheme) {
"http", "https" -> {
return false
}
"legado", "yuedu" -> {
startActivity<OnLineImportActivity> {
data = url
}
return true
}
else -> {
binding.root.longSnackbar("跳转其它应用", "确认") {
openUrl(url)
}
return true
}
}
}
}
}

@ -0,0 +1,54 @@
package io.legado.app.ui.web
import android.app.Application
import android.net.Uri
import android.util.Base64
import android.webkit.URLUtil
import androidx.documentfile.provider.DocumentFile
import io.legado.app.base.BaseViewModel
import io.legado.app.constant.AppConst
import io.legado.app.help.http.newCall
import io.legado.app.help.http.okHttpClient
import io.legado.app.utils.*
import java.io.File
import java.util.*
class WebViewModel(application: Application) : BaseViewModel(application) {
fun saveImage(webPic: String?, path: String) {
webPic ?: return
execute {
val fileName = "${AppConst.fileNameFormat.format(Date(System.currentTimeMillis()))}.jpg"
webData2bitmap(webPic)?.let { biteArray ->
if (path.isContentScheme()) {
val uri = Uri.parse(path)
DocumentFile.fromTreeUri(context, uri)?.let { doc ->
DocumentUtils.createFileIfNotExist(doc, fileName)
?.writeBytes(context, biteArray)
}
} else {
val file = FileUtils.createFileIfNotExist(File(path), fileName)
file.writeBytes(biteArray)
}
} ?: throw Throwable("NULL")
}.onError {
context.toastOnUi("保存图片失败:${it.localizedMessage}")
}.onSuccess {
context.toastOnUi("保存成功")
}
}
private suspend fun webData2bitmap(data: String): ByteArray? {
return if (URLUtil.isValidUrl(data)) {
@Suppress("BlockingMethodInNonBlockingContext")
okHttpClient.newCall {
url(data)
}.bytes()
} else {
Base64.decode(data.split(",").toTypedArray()[1], Base64.DEFAULT)
}
}
}

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical">
<LinearLayout
android:id="@+id/ll_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<io.legado.app.ui.widget.TitleBar
android:id="@+id/title_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:fitStatusBar="false" />
<io.legado.app.ui.rss.read.VisibleWebView
android:id="@+id/web_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
<FrameLayout
android:id="@+id/custom_web_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
Loading…
Cancel
Save