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

news2024/9/29 3:24:39

文章目录

  • 前言
  • 一、效果图
  • 二、实现步骤
    • 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文件了,都有注释自己慢慢去理解,有问题欢迎提出并指正!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

深度卷积网络的实际应用

1、三种经典的深度卷积网络 1.1、LeNet-5 使用 sigmoid 函数和 tanh 函数&#xff0c;而不是ReLu 函数&#xff0c;这篇论文中使用的正是 sigmoid 函数和 tanh 函数LeNet-5 是针对灰度图片训练的&#xff0c;所以图片的大小只有 32321 6 个 55 的过滤器&#xff0c;步幅为 …

【如何在深度学习的道路上越走越远?】

作为近几年人工智能领域的主要研究方向之一&#xff0c;深度学习主要通过构建深度卷积神经网络和采用大量样本数据作为输入&#xff0c;最终得到-一个具有强大分析能力和识别能力的模型。深度学习可以是有监督的、半监督的或无监督的。深度学习架构(例如深度神经网络、深度信念…

el-input输入框type=“number“时,禁止鼠标上下滑动改变数值

el-input输入框type"number"时&#xff0c;禁止鼠标上下滑动改变数值 解决方法&#xff1a;在el-input中添加属性设置 mousewheel.native.prevent

【达哥讲网络——只讲你不知道的】第1集:网络体系结构中的功能模块

大家好&#xff0c;经过公司缜密的思考和策划&#xff0c;【达哥讲网络——只讲你不知道的】系列连载今天正式与大家见面了。经过深入考虑&#xff0c;本系列只对一些重要的网络技术原理、网络功能实现原理及配置进行连载&#xff0c;其中会穿插一些实战案例&#xff0c;以帮助…

python与蒸散发与植被总初级生产力估算

植被总初级生产力(GPP)是指植物通过光合作用吸收的碳&#xff0c;是陆地生物圈和大气之间最大的碳通量&#xff0c;GPP的准确量化对于理解气候变化中生态系统功能、农业生产和碳循环的动态以及对气候的反馈具有重要意义 蒸散发&#xff08;Evapotranspiration&#xff0c;ET&a…

websdk上传阿里云视频完整教程

批量上传视频到阿里云 这段时间项目里有一个上传视频到阿里云的功能是我来负责写的&#xff0c;之前一直没有写过这种功能&#xff0c;感觉很难的亚子&#xff0c;但是后来仔细研究了一遍发现也没想象中那么难&#xff0c;最后经过不懈的努力也算是搞出来了哈哈哈&#xff0c;开…

集合List和Map

ArrayList底层的实现原理 初始化后ArrayList添加元素的步骤 首先计算数组的容量&#xff0c;如果当前数组已使用长度1后的大于当前的数组长度&#xff0c;则调用grow方法扩容(原来的1.5倍)&#xff0c;确保新增的数据有地方存储之后&#xff0c;则添加元素到size的位置上。返回…

docker环境下安装mysql 5.6

一、查看mgsql镜像版本 docker search mysql 二、拉取mysql镜像到本地标签为5.6版本 docker pull mysql:5.6 三、使用mysql5.6镜像创建容器(也叫运行镜像) 1.执行命令&#xff1a; docker run -p 3306:3306 --name mysql -v /haolb/mysql/conf:/etc/mysql/conf.d -v /haolb/my…

P2P、BT、ED2k、FTP、磁力链接下载到底是什么鬼?

1、HTTP/HTTPS 下载 有小伙伴会问&#xff0c;这个协议不是用来浏览网页的时候用的吗&#xff1f; 其实不然&#xff0c;用来下载文件一样可以&#xff0c;本质上都是从服务器拉取资源到本地&#xff0c;不同的是网页内容被渲染到浏览器上&#xff0c;而文件直接放在你的下载…

财富航向:企业为何急需财务管理软件?

随着市场的竞争日益激烈&#xff0c;企业对于财务数据的管理越来越重视。财务管理软件存在的好处越来越明显&#xff0c;它们可以帮助企业更好地管理财务信息并提高工作效率。 企业为什么需要财务管理软件&#xff1f; 1、方便管理财务数据 财务管理软件能够方便地管理与公司财…

教程学习:AutoQSAR

教程和练习文件从软件官网下载 内容&#xff1a; 1、拷贝教程提供的练习文件素材&#xff1a; 在软件的help中选择需要的教程&#xff0c;点击Copy to&#xff0c;可以将教程需要的文件拷贝到指定的文件夹里。点击Browse可以进行预览。 2、建立一个数值型的QSAR模型评估结合…

msvcr120.dll找不到是什么原因,怎样修复

msvcr120.dll的定义 msvcr120.dll是微软Visual C Redistributable软件包中的一个动态链接库文件。它是Microsoft Visual 所需的一个重要组件。这个文件主要用于支持和管理C语言编写的应用程序的运行。它包含了许多C的运行库函数和类&#xff0c;以便应用程序能够正常运行和调用…

2023-07-10:Kafka如何做到消息不丢失?

2023-07-10&#xff1a;Kafka如何做到消息不丢失&#xff1f; 答案2023-07-10&#xff1a; Kafka采用多种机制来确保消息的不丢失&#xff0c;其中包括副本机制、ISR&#xff08;In-Sync Replicas&#xff09;机制以及ACK机制等。 1.副本机制 Kafka通过副本机制来确保消息不…

【ElasticSearch】ES自动补全查询与Java接口实现

文章目录 1、安装拼音分词器2、自定义分词器3、completion suggester查询4、hotel索引库更新5、代码修改6、RestAPI实现自动补全7、需求&#xff1a;搜索框实现自动补全 自动补全就是当用户在搜索框输入字符时&#xff0c;我们应该提示出与该字符有关的搜索项。 1、安装拼音分词…

“小程序化”,一种创新的超级App开发模式

超级App是一种集成了多个功能和服务的移动应用程序&#xff0c;它在一个平台上提供了广泛的服务和体验。超级App通常具有大量的用户群体和高度活跃的用户社区&#xff0c;通过提供便利、多样化的功能&#xff0c;吸引用户在一个应用中完成多个任务和满足多个需求。 与传统的单…

postgresql 数据库 重建索引 所需时间测试

postgresql 数据库 重建索引 所需时间测试 文章目录 postgresql 数据库 重建索引 所需时间测试前言测试前准备重建索引前数据库状态测试计划重建索引命令测试开始1.先对表2进行测试2. 表3测试3. 表1测试 &#x1f308;后记 前言 众所周知&#xff0c;postgresql数据库使用久了…

【业务功能篇42】ThreadPoolTaskExecutor多线程处理耗时较高的数据接口

业务场景&#xff1a;当前业务模块中&#xff0c;有个查询产品直通率接口&#xff0c;随着数据量的递增&#xff0c;百万级数据&#xff0c;并且需要并表的情况下&#xff0c;那么返回数据就会开始变慢&#xff0c;而在数据层方面&#xff0c;已经比较难去做进一步的sql优化&am…

一致性哈希算法小结

在实际生产应用中&#xff0c;经常会设置多台服务器共同组成一个集成对外提供服务&#xff0c;为了确保合理的分配来自客户端的请求&#xff0c;我们会采取负载均衡的策略。例如采用「轮询」的方式让每个节点都能公平的接收到请求&#xff1b;采用「加权轮询」的方式让硬件配置…

MySQL-MySQL分组查询每组最新的一条数据

方法一&#xff1a; 1055 - Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column ‘se_jck的博客-CSDN博客 这个错误是由于 MySQL 的新版本中默认开启了ONLY_FULL_GROUP_BY模式&#xff0c;即在 GROUP BY 语句中的 SELECT 列表中&am…

[MMDetection]测试模型

以下是基于MMdetection3.10版本 1、简单测试模型 测试模型一般使用tools中的test.py&#xff0c;一般使用方式 python tools/test.py config文件路径 权重文件路径 可以通过--show 来以gui展示检测结果 python tools/test.py config文件路径 权重文件路径 --show 可以通过--s…