避坑!!webview如何加載pdf ?

問題來源

問題一切的來源還是得從那天說起...

有一天產(chǎn)品小王拿著電腦興致勃勃的來到我的工位旁:“誒,小付,這里有個在線pdf預(yù)覽的功能,你看下能不能做?!?/p>

聽完我心中暗想:這還不簡單,加載在線pdf不就和加載網(wǎng)頁一樣的,webview加上pdf鏈接,搞定!

這一想完,立即比了個OK:“沒問題,簡單!”

說完立馬開干,新建項目,準(zhǔn)備好webview,pdf鏈接,webView?.loadUrl("https://www.gjtool.cn/pdfh5/git.pdf"),點擊Run,滿心歡喜等待pdf加載出來的那一刻。

咦?怎么一片空白,難道是webview設(shè)置項有問題,但是加載網(wǎng)頁一點問題都沒啊。這時候瞥見隔壁iOS老大哥已經(jīng)成功加載出pdf了,一問也是用webview加載的,那為啥擱我這就不行?看不起我?

帶著疑惑查了下。

原來Android的webview壓根就不支持加載pdf。

Android與iOS不同,iOS加載pdf,不管本地還是在線,直接使用webview渲染就可以了,而Android卻做不到。

那該怎樣去加載pdf?

加載的方案有很多,比如直接跳到第三方瀏覽器加載,但產(chǎn)品要求只能在app內(nèi)部預(yù)覽,pass;比如在pdf鏈接前加上谷歌服務(wù),但在國內(nèi)是無法訪問的,pass;比如下載后再進(jìn)行加載,但當(dāng)pdf體積大且網(wǎng)絡(luò)不好時,下載就會出現(xiàn)問題,又pass;

方式有多種,第三方的輪子也有很多,但適合自己的開發(fā)需求,以及滿足UI設(shè)計,則就需要進(jìn)行二次改造了。

經(jīng)過多方對比,使用webview加載pdf的方案更符合大多數(shù)的場景。

以下就會從webview加載pdf的方案出發(fā),描述在開發(fā)時所涉及到的問題點。

我的爬坑之旅開始了!

初步加載

webview加載pdf的初步設(shè)想是使用js的方式去渲染,

新建一個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)
    }
});

新建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>

準(zhǔn)備好js和html后,使用webview對在線pdf(https://www.gjtool.cn/pdfh5/git.pdf) 進(jìn)行加載,

webView?.loadUrl("file:///android_asset/index.html?https://www.gjtool.cn/pdfh5/git.pdf");

運行成功后,pdf也加載出來了。

[圖片上傳失敗...(image-d55aea-1634226795111)]

添加雙指縮放

好家伙,終于是加載出了pdf,我滿心歡喜的拿著效果給產(chǎn)品看一看。

“你這是加載出來了,但是字體看著有點小,你看能不能加上雙指縮放的功能”。產(chǎn)品小王看了一眼,

“那必須能啊。”

將webview設(shè)置為支持縮放狀態(tài),并且useWideViewPort設(shè)置為true,讓W(xué)ebivew支持meta標(biāo)簽的viewport屬性,

settings?.useWideViewPort = true
settings?.builtInZoomControls = true
settings?.setSupportZoom(true)
settings?.displayZoomControls = false //不顯示縮放按鈕

并且修改html中的meta屬性,設(shè)置minimum-scalemaximum-scale屬性,以及將user-scalable置為yes,

運行成功后,成功對pdf進(jìn)行雙指縮放。

產(chǎn)品看了過后,點了點頭。我也開開心心的提交了代碼。

簽章無法顯示

以為這個小功能已經(jīng)開發(fā)完成,沒有多大的問題,直到有一天測試小姐姐找到我,

“你這pdf顯示有問題,當(dāng)pdf上有簽章時,簽章無法顯示”

“what?”

簽章無法顯示,這個倒是沒有自測過,趕緊找測試要了鏈接來驗證,經(jīng)過驗證,簽章的顯示確實有問題。所謂簽章,即在pdf上加蓋公章或者簽名。如下圖

(來源網(wǎng)絡(luò))

[圖片上傳失敗...(image-bea130-1634226795111)]

簽章是屬于后期添加在pdf上,對于簽章的加載,簡單的js是無法加載成功的。

那該如何處理?

其實有個非常強(qiáng)大的第三方庫pdf.js已經(jīng)幫我們處理好了,pdf.js可通過pdf文件的地址或pdf數(shù)據(jù)流獲取pdf,具體實現(xiàn)是調(diào)用接口函數(shù) PDFJs.getDocument(url/buffer)將pdf載入html,通過canvas處理, 然后渲染pdf文件,當(dāng)然也能夠顯示出簽章。

只不過它的使用有點麻煩,需要先將pdf.js下載出來,下載地址 ,copy到Android項目中assert文件夾中,

[圖片上傳失敗...(image-cfe1af-1634226795111)]

最后加載方式還是和上方一樣使用webview來加載。缺點就是包體積增大。

當(dāng)我們使用pdf.js默認(rèn)加載pdf時,會發(fā)現(xiàn)效果圖的上方出現(xiàn)了多余的控制按鈕,比如下圖:

[圖片上傳失敗...(image-3bc62c-1634226795111)]

但是在UI設(shè)計圖中,是沒有包含這些控制按鈕的,如果就這么提交,估計不一會UI小姐姐就來找我了。

那該如何處理?

其實在本篇一開始使用的方式中,加載完成pdf是沒有這些控制按鈕的,那么問題來了,我們是不是可以將第一種方式與pdf.js相結(jié)合,來進(jìn)行加載?

pdf.js主要包含兩個核心庫文件,一個pdf.js和一個pdf.worker.js,一個負(fù)責(zé)API解析,一個負(fù)責(zé)核心解析。如果需要與第一種方式結(jié)合,我們就將pdf.js、pdf.worker.js以及pdf.sandbox.js三個文件copy出來,放到assert中。

在html中的script標(biāo)簽中添加對pdf.js、pdf.worker.js等的引用,

<script type="text/javascript" src="pdf.js"></script>
<script type="text/javascript" src="pdf.worker.js"></script>
<script type="text/javascript" src="pdf.sandbox.js"></script>
<script type="text/javascript" src="index.js"></script>

修改index.js文件

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

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

alert(url);

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

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

        page.render({
            canvasContext: ctx,
            viewport: viewport
        }).promise.then(() => {});
    });
}

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

可以看到運行成功后,簽章成功展示且多余的控制按鈕也不會顯示,這里效果圖就不展示了。

我又開開心心的提交了代碼。

中文字符顯示不全

又過了一段時間,我正愉快的敲著代碼,這時候測試小姐姐又找到了我,

“這邊pdf顯示有點問題,一些文字、字符顯示不全,出現(xiàn)缺少字符的現(xiàn)象”

“what?”

我趕緊重現(xiàn)驗證下,當(dāng)pdf上有多種字體時,會有概率出現(xiàn)字符顯示不全的現(xiàn)象。查了查,當(dāng)運行加載此類pdf時,在控制臺上會出現(xiàn)了一些警告信息。

[圖片上傳失敗...(image-5bbc07-1634226795111)]

“Error during font loading”

是因為在解析pdf時,默認(rèn)的字體庫已經(jīng)不能覆蓋多種字體,也就無法將所有字體顯示完全。

那如何處理?

默認(rèn)字體庫無法滿足,那就添加新的字體庫,

在pdf.js文件中添加cMapUrl = "https://cdn.jsdelivr.net/npm/pdfjs-dist@2.2.228/cmaps/" ,

params.rangeChunkSize = params.rangeChunkSize || DEFAULT_RANGE_CHUNK_SIZE;
params.CMapReaderFactory = params.CMapReaderFactory || DefaultCMapReaderFactory;
params.ignoreErrors = params.stopAtErrors !== true;
params.fontExtraProperties = params.fontExtraProperties === true;
params.pdfBug = params.pdfBug === true;
params.enableXfa = params.enableXfa === true;
params.cMapPacked = true
params.cMapUrl = "https://cdn.jsdelivr.net/npm/pdfjs-dist@2.2.228/cmaps/"

ok,運行看看,中文已顯示完全。

以上,webview加載pdf的問題基本已經(jīng)解決。針對webview加載pdf的方案,主要解決問題如下:

  • 雙指縮放;
  • 簽章無法顯示;
  • 存在多余控制按鈕;
  • 中文字符顯示不全。

這幾個是加載pdf中最主要的問題,其他的小問題都好解決。

全部代碼已放置在github:pdf-webview

推薦閱讀:

仿微信聊天炸“屎”效果!!誒,就是玩!

Compose版來啦!仿自如裸眼3D效果

「性能優(yōu)化系列」APP內(nèi)存優(yōu)化理論與實踐

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容