当前位置: 首页 > news >正文

Android本地浏览PDF(Android PDF.js 简要学习手册)

环境

Min SDK: 21
依赖:

implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.1"
implementation "androidx.webkit:webkit:1.12.0"

权限:

<uses-permission android:name="android.permission.INTERNET" />

下载pdf.js :https://github.com/mozilla/pdf.js/tree/v2.10.377/web

引入步骤

app/src/main/assets/pdfjs/
├── web/
│   ├── viewer.html
│   ├── viewer.js
│   └── ...
├── build/
│   ├── pdf.js
│   ├── pdf.worker.js
│   └── ...

实现

import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.view.WindowManager
import android.webkit.WebChromeClient
import android.webkit.WebResourceRequest
import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.core.content.ContextCompat
import androidx.webkit.WebViewAssetLoader
import com.gyf.immersionbar.ImmersionBar
import com.sunward.markettools.R
import com.sunward.markettools.base.BaseActivity
import com.sunward.markettools.databinding.ActivityWebviewBinding
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.cancel
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.File
import java.io.FileOutputStream
import java.net.URL
import java.net.URLEncoder
import java.nio.channels.Channels/***@dateTime:2025/4/29*@作者:MaoYoung*/
class WebViewPDFActivity : BaseActivity<MarketViewModel, ActivityWebviewBinding>(R.layout.activity_webview
) {companion object {fun newInstance(activity: Context?, url: String, fileName: String) {activity?.startActivity(Intent(activity, WebViewPDFActivity::class.java).apply {putExtra(activity.getString(R.string.params_web_url), url)putExtra(activity.getString(R.string.params_file_name), fileName)})}}private val coroutineScope = MainScope()private val domain = "appassets.androidplatform.net"override fun initView(savedInstanceState: Bundle?) {val pdfUrl =intent.getStringExtra(getString(R.string.params_web_url)) ?: ""val fileName = intent.getStringExtra(getString(R.string.params_file_name)) ?: ""window.setFlags(WindowManager.LayoutParams.FLAG_SECURE,WindowManager.LayoutParams.FLAG_SECURE)mBinding.apply {tvTitle.text = fileNametoolbar.setNavigationOnClickListener { finishActivity() }}val downloadDir = saveDownloadFilePath()val assetLoader = WebViewAssetLoader.Builder().setDomain(domain).addPathHandler("/assets/", WebViewAssetLoader.AssetsPathHandler(this)).addPathHandler("/Download/",WebViewAssetLoader.InternalStoragePathHandler(this, downloadDir)).build()mBinding.apply {webview.apply {settings.apply {javaScriptEnabled = truedomStorageEnabled = trueallowFileAccess = false // 不再需要 file 访问}//设置WebViewClient与AssetLoaderwebViewClient = object : WebViewClient() {override fun shouldInterceptRequest(view: WebView?,request: WebResourceRequest?): android.webkit.WebResourceResponse? {return assetLoader.shouldInterceptRequest(request?.url!!)}override fun shouldOverrideUrlLoading(view: WebView?,request: WebResourceRequest?): Boolean {return super.shouldOverrideUrlLoading(view, request)}override fun onPageFinished(view: WebView?, url: String?) {view?.loadUrl("javascript:(function() {" +"var rightToolbar = document.getElementById('toolbarViewerRight');" +"if (rightToolbar) { rightToolbar.style.display = 'none'; }" +"})()")}override fun onReceivedError(view: WebView?,errorCode: Int,description: String?,failingUrl: String?) {Log.e("WebViewActivity", "Error: $description, URL: $failingUrl")}}webChromeClient = WebChromeClient()downloadAndDisplayPdf(pdfUrl, fileName)}}}private fun saveDownloadFilePath(): File {val downloadDir = File(this.filesDir, "Download")if (!downloadDir.exists()) {downloadDir.mkdirs()}return downloadDir}private fun downloadAndDisplayPdf(pdfUrl: String, fileName: String) {coroutineScope.launch {try {val finalFileName = if (fileName.endsWith(".pdf")) fileName else "$fileName.pdf"val downloadedFileName =withContext(Dispatchers.IO) {val downloadDir = saveDownloadFilePath()val file = File(downloadDir, finalFileName)if (file.exists()) file.delete()val url = URL(pdfUrl)val connection = url.openConnection()connection.connect()val inputStream = connection.getInputStream()FileOutputStream(file).use { output ->Channels.newChannel(inputStream).use { inputChannel ->output.channel.use { outputChannel ->outputChannel.transferFrom(inputChannel, 0, Long.MAX_VALUE)}}}finalFileName}val encodedPath = URLEncoder.encode("$downloadedFileName", "UTF-8")val viewerUrl ="https://$domain/assets/pdfjs/web/viewer.html?file=%2FDownload%2F$encodedPath"mBinding.webview.loadUrl(viewerUrl)} catch (e: Exception) {e.printStackTrace()val encodedUrl = try {URLEncoder.encode(pdfUrl, "UTF-8")} catch (e: Exception) {pdfUrl}val fallbackUrl = "file:///android_asset/pdfjs/web/viewer.html?file=$encodedUrl"mBinding.webview.loadUrl(fallbackUrl)}}}override fun onResume() {super.onResume()mBinding.webview.onResume()}override fun onPause() {super.onPause()mBinding.webview.onPause()}override fun onDestroy() {mBinding.webview.destroy()coroutineScope.cancel()super.onDestroy()}override fun initImmersionBar() {ImmersionBar.with(this).statusBarColorTransformEnable(false).keyboardEnable(false).statusBarDarkFont(true).navigationBarDarkIcon(true).fitsSystemWindowsInt(true, ContextCompat.getColor(this, R.color.color_fa)).navigationBarColor(R.color.color_fa).init()}
}
WebViewActivity.newInstance(context, "这里传递下载PDF的地址")

工作原理

  1. 初始化

    • 从intent中获取PDF 的URL
    • 配置域名: .setDomain(domain)
  2. 下载
    使用协成下载到/Download/文件夹中

  3. 显示
    将文件加载到本地PDF路径(file://…/temp.pdf)的"https://$domain/assets/pdfjs/web/viewer.html

http://www.dtcms.com/a/284585.html

相关文章:

  • [MRCTF2020]PYWebsite
  • 大语言模型任务分解与汇总:从认知瓶颈到系统化解决方案
  • ubuntu基础搭建
  • 学习笔记(39):结合生活案例,介绍 10 种常见模型
  • Matplotlib 轴标题与刻度字号调整方法
  • 渗透总结一
  • docker中 contriner 和 images 什么关系
  • Oracle 成本优化器(CBO)与数据库统计信息:核心原理与实践
  • 深度学习计算图学习路线
  • Python获取网页乱码问题终极解决方案 | Python爬虫编码处理指南
  • UE5 lumen
  • 《Oracle SQL:使用 RTRIM 和 TO_CHAR 函数格式化数字并移除多余小数点》
  • 解读PLM系统软件在制造企业研发管理中的应用
  • 【神经网络在MATLAB中是如何实现的?】
  • 解锁Windows下Composer切换PHP版本的奥秘
  • 老牌支付品牌钱如潮入局本地生活抽佣系统,行业竞争加剧
  • Linux Shell脚本
  • linux端口监听命令
  • 支付宝智能助理用户会话实时统计:Flink定时器与状态管理实战解析
  • 全面升级!WizTelemetry 可观测平台 2.0 深度解析:打造云原生时代的智能可观测平台
  • cve-2012-0809 sudo格式化字符串漏洞分析及利用
  • TASK01【datawhale组队学习】地瓜机器人具身智能概述
  • Jmeter系列(八)-定时器(待更新)
  • 电缆安全双保险:不止防盗,更能防触电的塔能智慧照明守护方案
  • 【推荐100个unity插件】使用C#或者unity实现爬虫爬取静态网页数据——Html Agility Pack (HAP)库和XPath 语法的使用
  • 腾讯位置商业授权鸿蒙地图SDK
  • 【中等】题解力扣22:括号生成
  • 【专题十二】栈
  • 调用接口报错,使用postman调用就没问题如何解决
  • Redis 生产实战 7×24:容量规划、性能调优、故障演练与成本治理 40 条军规