Android之WebView加载PDF链接预览PDF文件

文章目录

  • 前言
  • 一、效果图
  • 二、实现步骤
    • 1.在项目main目录下新建一个assets
    • 2.新建一个js为index.js
    • 3.新建一个HTML为index.html
    • 4.xml布局
    • 4.Activity类(kotlin)
    • 5.Activity类(Java)
  • 总结


前言

Android的webview压根就不支持加载pdf,Android与iOS不同,iOS加载pdf,不管本地还是在线,直接使用webview渲染就可以了,而Android却做不到,所以我们必须得扣脑壳了。方法也有很多种,比如第三方PDFview,MuPDF等,但是不推荐,引入进去apk体积会大很多,所以大多场景都是通过js解析,然后在webview中加载PDF文件,所以内库很小也就2兆多,那我们就开始吧。


一、效果图

在这里插入图片描述

二、实现步骤

1.在项目main目录下新建一个assets

2.新建一个js为index.js

var url = location.search.substring(1);

PDFJS.cMapUrl = 'https://unpkg.com/pdfjs-dist@1.9.426/cmaps/';
PDFJS.cMapPacked = true;

var pdfDoc = null;

function createPage() {
    var div = document.createElement("canvas");
    document.body.appendChild(div);
    return div;
}

function renderPage(num) {
    pdfDoc.getPage(num).then(function (page) {
        var viewport = page.getViewport(2.0);
        var canvas = createPage();
        var ctx = canvas.getContext('2d');

        canvas.height = viewport.height;
        canvas.width = viewport.width;

        page.render({
            canvasContext: ctx,
            viewport: viewport
        });
    });
}

PDFJS.getDocument(url).then(function (pdf) {
    pdfDoc = pdf;
    for (var i = 1; i <= pdfDoc.numPages; i++) {
        renderPage(i)
    }
});


3.新建一个HTML为index.html

<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=4.0,user-scalable=no"/>
    <title>Document</title>
    <style type="text/css">
        canvas {
            width: 100%;
            height: 100%;
            border: 1px solid black;
        }
    </style>
    <script src="https://unpkg.com/pdfjs-dist@1.9.426/build/pdf.min.js"></script>
    <script type="text/javascript" src="index.js"></script>
</head>
<body>
</body>
</html>


4.xml布局

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#ffffff">

    <include
        android:id="@+id/include"
        layout="@layout/title_layout" />

    <WebView
        android:id="@+id/pdfwebview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_above="@+id/gosign"
        android:layout_below="@+id/include" />

    <TextView
        android:id="@+id/gosign"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:layout_alignParentBottom="true"
        android:layout_centerInParent="true"
        android:layout_marginLeft="30dp"
        android:layout_marginTop="10dp"
        android:layout_marginRight="30dp"
        android:layout_marginBottom="30dp"
        android:background="@drawable/blackground_home_blue"
        android:gravity="center"
        android:text="Go Sign"
        android:textColor="#ffffff"
        android:textSize="16dp" />

</RelativeLayout>

4.Activity类(kotlin)

注意:activity代码要点在于WebSettings设置的参数和loadUrl()加载URL时加"file:///android_asset/index.html?"

class PDFWebViewActivity : Activity(), OnClickListener {

    private lateinit var relative_back: RelativeLayout
    private lateinit var text_title: TextView
    private lateinit var url: String//接收URL
    private lateinit var title: String//接收title
    private lateinit var pdfwebview: WebView
    private lateinit var gosign: TextView

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        //去掉状态栏
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            val decorView = window.decorView
            val option = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
            decorView.systemUiVisibility = option
            window.statusBarColor = Color.parseColor("#00000000")
        }
        //修改状态栏文字为黑色
        window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or
                View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
        setContentView(R.layout.pdfwebviewlayout)
        url = intent.getStringExtra("url")!!.trim { it <= ' ' }
        title = intent.getStringExtra("title")!!.trim { it <= ' ' }
        instantiation()
    }

    fun instantiation() {
        EventBus.getDefault().register(this)
        relative_back = findViewById(R.id.relative_back)
        text_title = findViewById(R.id.text_title)
        text_title.text = title
        pdfwebview = findViewById(R.id.pdfwebview)
        gosign = findViewById(R.id.gosign)
        gosign.setOnClickListener(this)
        relative_back.setOnClickListener(this)
        webviewDe(url)
    }

    override fun onClick(v: View?) {
        when (v?.id) {
            R.id.relative_back ->
                finish()
        }
    }

    /**
     * webview显示
     */
    @SuppressLint("SetJavaScriptEnabled", "JavascriptInterface")
    private fun webviewDe(url: String) {
        println("网页url打印:$url")
        val webSettings: WebSettings = pdfwebview.getSettings()
        webSettings.cacheMode = WebSettings.LOAD_DEFAULT
        //设置加载进来的页面自适应手机屏幕
        webSettings.useWideViewPort = true
        webSettings.loadWithOverviewMode = true
        //问题2:基本都需要支持JS
        webSettings.javaScriptEnabled = true
        webSettings.allowFileAccess = true
        //支持通过JS打开新窗口
        webSettings.allowFileAccessFromFileURLs = true
        webSettings.allowUniversalAccessFromFileURLs = true
        webSettings.javaScriptCanOpenWindowsAutomatically = true
        webSettings.setGeolocationEnabled(true)
        webSettings.domStorageEnabled = true
        webSettings.setAppCacheEnabled(false)
        pdfwebview.scrollBarStyle = WebView.SCROLLBARS_OUTSIDE_OVERLAY
        //触摸焦点起作用
        pdfwebview.requestFocus()
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            //http与https的方法
            webSettings.mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW
        }
        // 添加js交互接口类,并起别名 Android
        pdfwebview.addJavascriptInterface(JavascriptImgInterface(), "Android")

        //设置WebChromeClient类
        pdfwebview.webChromeClient = object : WebChromeClient() {
            //获取网站标题
            override fun onReceivedTitle(view: WebView, title: String) {
                println("标题在这里$title")
            }

            //图片选取
            override fun onShowFileChooser(
                webView: WebView,
                filePathCallback: ValueCallback<Array<Uri>>,
                fileChooserParams: FileChooserParams,
            ): Boolean {
                return true
            }
        }
        //设置WebViewClient类
        pdfwebview.webViewClient = object : WebViewClient() {
            override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean {
                // 返回值是true的时候控制去WebView打开,为false调用系统浏览器或第三方浏览器
                view.loadUrl(url)
                return true
            }

            //设置加载前的函数 kotlin这里favicon: Bitmap?的Bitmap?必须加?
            override fun onPageStarted(view: WebView, url: String, favicon: Bitmap?) {
                if (!this@PDFWebViewActivity.isFinishing) 
                {
                    println("开始加载了")
                    DialogUtils.showLoadingDialog(this@PDFWebViewActivity)
                }
            }

            //设置结束加载函数
            override fun onPageFinished(view: WebView, url: String) {
                println("结束加载了")
                try {
                    DialogUtils.hideLoadingDialog()
                } catch (e: Exception) {
                }
            }
        }
        pdfwebview.loadUrl("file:///android_asset/index.html?$url")
    }

    class JavascriptImgInterface {
        /**
         * 注意: 在Android4.2极其以上系统需要给提供js调用的方法前加入一个注释:@JavaScriptInterface;
         * 在虚拟机当中 Javascript调用Java方法会检测这个anotation,
         * 如果方法被标识@JavaScriptInterface则Javascript可以成功调用这个Java方法,否则调用不成功。
         */
        //js调用Android方法给web返回Token值
        @JavascriptInterface
        open fun Android_Token(): String? {
            println("打印的token:" + SpUtil.get(ConstantUtil.TOKEN, ""))
            return SpUtil.get(ConstantUtil.TOKEN, "")
        }

    }
}

5.Activity类(Java)

注意:activity代码要点在于WebSettings设置的参数和loadUrl()加载URL时加"file:///android_asset/index.html?"


public class PDFWebViewActivity extends Activity implements View.OnClickListener {

    private String url;//接收URL
    private String title;//接收title
    private ImageView left_black_risk;//返回键
    private TextView text_title;//title
    private RelativeLayout gosign;//去签名
    private static String message;//返回消息
    private WebView webviewx5;//webview

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //去掉状态栏
        if (Build.VERSION.SDK_INT >= 21) {
            View decorView = getWindow().getDecorView();
            int option = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
            decorView.setSystemUiVisibility(option);
            getWindow().setStatusBarColor(Color.parseColor("#00000000"));
        }
        //修改状态栏文字为黑色
        getWindow().getDecorView().setSystemUiVisibility(
                View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
                        View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
        setContentView(R.layout.pdfwebviewlayout);
        url = getIntent().getStringExtra("url").trim();
        title = getIntent().getStringExtra("title").trim();
        instantiation();
    }

    private void instantiation() {
        webviewx5 = findViewById(R.id.webview);
        left_black_risk = findViewById(R.id.left_black_risk);
        text_title = findViewById(R.id.text_title);
        gosign = findViewById(R.id.gosign);
        text_title.setText(title);
        left_black_risk.setOnClickListener(this);
        gosign.setOnClickListener(this);
        webviewDe(url);
    }

    /**
     * webview显示
     */
    @SuppressLint({"SetJavaScriptEnabled", "JavascriptInterface"})
    private void webviewDe(String url) {
        System.out.println("网页url打印:" + url);
        WebSettings webSettings = webviewx5.getSettings();
        webSettings.setCacheMode(WebSettings.LOAD_DEFAULT);
        //设置加载进来的页面自适应手机屏幕
        webSettings.setUseWideViewPort(true);
        webSettings.setLoadWithOverviewMode(true);
        //问题2:基本都需要支持JS
        webSettings.setJavaScriptEnabled(true);
        webSettings.setAllowFileAccess(true);
        //支持通过JS打开新窗口
        webSettings.setAllowFileAccessFromFileURLs(true);
        webSettings.setAllowUniversalAccessFromFileURLs(true);
        webSettings.setJavaScriptCanOpenWindowsAutomatically(true);
        webSettings.setGeolocationEnabled(true);
        webSettings.setDomStorageEnabled(true);
        webSettings.setAppCacheEnabled(false);

        webviewx5.setScrollBarStyle(WebView.SCROLLBARS_OUTSIDE_OVERLAY);
        //触摸焦点起作用
        webviewx5.requestFocus();

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            //http与https的方法
            webSettings.setMixedContentMode(MIXED_CONTENT_ALWAYS_ALLOW);
        }
        // 添加js交互接口类,并起别名 Android
        webviewx5.addJavascriptInterface(new JavascriptImgInterface(), "Android");

        //设置WebChromeClient类
        webviewx5.setWebChromeClient(new WebChromeClient() {


            //获取网站标题
            @Override
            public void onReceivedTitle(WebView view, String title) {
                System.out.println("标题在这里" + title);
            }

            //图片选取
            @Override
            public boolean onShowFileChooser(WebView webView,
                                             ValueCallback<Uri[]> filePathCallback,
                                             FileChooserParams fileChooserParams) {
                return true;
            }
        });
        //设置WebViewClient类
        webviewx5.setWebViewClient(new WebViewClient() {

            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                // 返回值是true的时候控制去WebView打开,为false调用系统浏览器或第三方浏览器
                view.loadUrl(url);
                return true;
            }

            //设置加载前的函数
            @Override
            public void onPageStarted(WebView view, String url, Bitmap favicon) {
                if (!PDFWebViewActivity.this.isFinishing())//xActivity即为本界面的Activity
                {
                    System.out.println("开始加载了");
                    DialogUtils.showLoadingDialog(PDFWebViewActivity.this);
                }
            }

            //设置结束加载函数
            @Override
            public void onPageFinished(WebView view, String url) {
                System.out.println("结束加载了");
                try {
                    DialogUtils.hideLoadingDialog();
                } catch (Exception e) {

                }
            }
        });
        webviewx5.loadUrl("file:///android_asset/index.html?" + url);
    }

    public class JavascriptImgInterface {
        /**
         * 注意: 在Android4.2极其以上系统需要给提供js调用的方法前加入一个注释:@JavaScriptInterface;
         * 在虚拟机当中 Javascript调用Java方法会检测这个anotation,
         * 如果方法被标识@JavaScriptInterface则Javascript可以成功调用这个Java方法,否则调用不成功。
         */
        //js调用Android方法给web返回Token值
        @JavascriptInterface
        public String Android_Token() {
            System.out.println("打印的token:" + SpUtil.get(ConstantUtil.TOKEN, ""));
            return SpUtil.get(ConstantUtil.TOKEN, "");
        }

        //js调用Android方法下载apk
        @JavascriptInterface
        public String Android_DownloadApk(String url) {
            //方式一:代码实现跳转
            Intent intent = new Intent();
            //通过intent发送数据
            intent.setAction("android.intent.action.VIEW");
            //创建一个链接  链接.语法解析
            Uri content_url = Uri.parse(url);
            //通过intent接受
            intent.setData(content_url);
            //开始于当前intent
            startActivity(intent);
            return url;
        }
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            //返回键
            case R.id.left_black_risk:
                finish();
                break;
            //去签名
            case R.id.gosign:
                break;
        }
    }
}


总结

以上便是通过加载js的方式预览PDF文件了,都有注释自己慢慢去理解,有问题欢迎提出并指正!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/36186.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于单片机的智能空调系统的设计与实现

功能介绍 以51单片机作为主控系统&#xff1b;LCD1602液晶显示当前水温&#xff0c;定时提醒&#xff0c;水量变化DS18B20检测当前水体温度&#xff1b;水位传感器检测当前水位&#xff1b;继电器驱动加热片进行水温加热&#xff1b;定时提醒喝水&#xff0c;蜂鸣器报警&#x…

详解HTTP协议和HTTPS协议

目录 一.HTTP协议 1.什么是HTTP 2.HTTP发展历史 3.HTTP请求和响应 4. 抓包的方式和工具Fiddler 1.开发者工具 2.Fiddler 二.请求和响应 1.请求和响应报文 2.URL结构 3.常见的方法 1.GET方法 2.POST方法 3.其他方法 三.请求报头(header) 1.Host 2.Content-Length 3.Co…

python自动化办公——定制化将电子签名批量签写到PDF文件

python自动化办公——定制化将电子签名批量签写到PDF文件 文章目录 python自动化办公——定制化将电子签名批量签写到PDF文件1、安装依赖2、需求分析3、代码 1、安装依赖 首先需要下载所需要的库 pip install pdf2image pip install img2pdf pip install opencv-python此外还…

vue + el-table点击表头改变其当前样式

废话不多说&#xff0c;先看效果&#xff1a; 网上找了一大圈没有符合的&#xff0c;只能自己看着搞&#xff1a; 直接贴代码&#xff1a; <el-tableref"table":data"tableData"borderstripesort-change"changeColumn"><el-table-colu…

springMVC(二)—— 进阶

一、解决中文乱码问题 解决中文乱码问题的关键在于判断字符是什么时候乱码的 先在java程序里刚生成这个值的地方打印一下&#xff0c;如果在控制台输出就乱码了&#xff0c;那就排除浏览器和jsp页面的编码出问题。否则 看浏览器的编码 看这个jsp页面的编码是否设置好了 一般不用…

简要介绍 | 两阶段点云目标检测:理论与实践

注1&#xff1a;本文系“简要介绍”系列之一&#xff0c;仅从概念上对两阶段点云目标检测进行非常简要的介绍&#xff0c;不适合用于深入和详细的了解。 两阶段点云目标检测&#xff1a;理论与实践 在这篇博客中&#xff0c;我们将探索两阶段点云目标检测的理论基础和实际应用…

cancal 同步mysql数据到es中

1.环境&#xff1a; windocs service2012 、 jdk版本1.8 、canal版本1.5、mysql版本5.7、 注意&#xff1a;canal版本1.5需要的jdk是1.8 如果你下载的是canal1.6&#xff0c;jdk是1.8&#xff0c;那样会报错。 下载地址 Releases alibaba/canal GitHub 下载并上传到服…

创建数据库Market、Team,按要求完成指定操作

创建数据库Market&#xff0c;在Market中创建数据表customers&#xff0c;customers表结构如表4.6所示&#xff0c;按要求进行操作。 代码如下&#xff1a; #(1&#xff09;创建数据库Market mysql> create database Market; Query OK, 1 row affected (0.00 sec)mysql>…

Java阶段五Day02

Java阶段五Day02 文章目录 Java阶段五Day02MAVEN-聚合(多模块3)回顾多模块2个特性依赖:继承: 聚合场景聚合目的实现聚合聚合总结 远程仓库远程仓库概念配置settings.xml远程库配置注意事项 GIT详细学习git概括git历史本地版本控制相关命令git分支管理分支管理基本概念分支管理相…

Failed to initialize NVML: Driver/library version mismatch

nvidia驱动安装之后&#xff0c;nvidia-smi 报错 Driver/library version mismatch 不重启系统的解决方法 查看系统日志&#xff0c;确定具体报错信息&#xff1a; # dmesg | tail [8598493.408944] NVRM: API mismatch: the client has the version 525.125.06, butNVRM: t…

STL好难(4):list的使用

和列表很像 1.list的介绍 点击这里查看 list 的官方文档 list类似数据结构中的链表 1. list是可以在常数范围内在任意位置进行插入和删除的序列式容器&#xff0c;并且该容器可以前后双向迭代。2. list的底层是双向链表结构&#xff0c;双向链表中每个元素存储在互不相关的独…

flutter聊天界面-自定义表情键盘实现

flutter聊天界面-自定义表情键盘实现 flutter 是 Google推出并开源的移动应用开发框架&#xff0c;主打跨平台、高保真、高性能。开发者可以通过 Dart语言开发 App&#xff0c;一套代码同时运行在 iOS 和 Android平台。 flutter开发基础腾讯IM的聊天应用&#xff0c;使用的是t…

css设计表格圆角最简单的方法

代码如下&#xff1a; table {width: 100%;/* border-collapse: collapse; */background-color: #FBFBFB; /* 背景颜色; */border-collapse: separate; /* 让border-radius有效 */border-spacing: 0; /*表格中每个格边距设为0*/border: 1px solid #DFDFDF;/*边框*/border-radi…

ETHERNET/IP 转ETHERCAT连接倍福和欧姆龙PLC的配置方法

ETHERNET/IP和ETHERCAT是两种不同的协议&#xff0c;它们在工业生产中都有广泛的应用。然而&#xff0c;由于协议不同&#xff0c;这两种设备之间无法通讯&#xff0c;这给工业生产带来了很大的麻烦。而远创智控YC-EIP-ECT网关应运而生&#xff0c;它能够连接到ETHERNET/IP总线…

【Linux之拿捏信号3】阻塞信号

文章目录 相关概念原理sigset_t信号集信号集操作函数sigprocmask系统调用sigpending 相关概念 实际执行信号的处理动作——信号递达Delivery&#xff08;例如自定义捕捉动作&#xff0c;core&#xff0c;Term终止进程的动作&#xff09;。信号从产生到递达之间的状态——信号未…

Anaconda配置可视化绘图库seaborn的方法

本文介绍在Anaconda的环境中&#xff0c;安装Python语言中&#xff0c;常用的一个绘图库seaborn模块的方法。 seaborn模块是基于Matplotlib的数据可视化库&#xff0c;它提供了一种更简单、更漂亮的界面来创建各种统计图形。seaborn模块主要用于数据探索、数据分析和数据可视化…

换零钱——最小钱币张数(贪心算法)

贪心算法&#xff1a;根据给定钱币面值列表&#xff0c;输出给定钱币金额的最小张数。 (本笔记适合学完python基本数据结构&#xff0c;初通 Python 的 coder 翻阅) 【学习的细节是欢悦的历程】 Python 官网&#xff1a;https://www.python.org/ Free&#xff1a;大咖免费“圣…

C/C++编程安全标准GJB-8114解读——声明定义类

软件检测实验室在建立软件测试体系或申请cnas/cma相关资质时&#xff0c;需要依据相关标准&#xff0c;使用有效的方法开展检验检测活动&#xff0c;GJB-8114是一部嵌入式软件安全测试相关的国家标准&#xff0c;本系列文章我们就针对GJB-8114《C/C语言编程安全子集》的具体内容…

Android 热修复一

一、什么是热修复&#xff1f; 在我们应用上线后出现bug需要及时修复时&#xff0c;不用再发新的安装包&#xff0c;只需要发布补丁包&#xff0c;在客户无感知下修复掉bug。 实现效果&#xff1a; Demo源码&#xff1a; https://gitee.com/sziitjim/hotfix 二、怎么进行热修…

一文了解Docker之网络模型

目录 1.Docker网络 1.1 Docker网络模型概述 1.2 Docker网络驱动程序 1.2.1 host模式 1.2.2 bridge模式 1.2.3 container模式 1.2.4 none模式 1.3 Docker网络命令示例 1.3.1 创建一个自定义网络 1.3.2 列出所有网络 1.3.3 连接容器到网络 1.3.4 断开容器与网络的连接…