This article has participated in the “Digitalstar Project” and won a creative gift package to challenge the creative incentive money.

Source of problem

It all started that day…

One day, Product Xiao Wang came to my desk with a computer in his hand and said, “Hey, Xiao Fu, here is an online PDF preview function. See if you can do it.”

After hearing this, I thought to myself: this is not easy, loading online PDF is not the same as loading a web page, webView plus PDF link, done!

This one thought, immediately than an OK: “no problem, simple!”

So let’s get started, create a new project, get webView, PDF link, webView? LoadUrl (” https://www.gjtool.cn/pdfh5/git.pdf “), click on the Run, joy waiting for PDF loading out of that a moment.

Yi? How blank, is there a problem with the WebView Settings, but there is no problem with loading web pages? At this time glimpse next door iOS big brother has successfully loaded the PDF, ask is also loaded with webview, that why put me this can not? Look down on me?

I looked it up with some doubt.

It turns out that Android webView doesn’t support loading PDFS at all.

Android is different from iOS. IOS loads PDFS, whether local or online, and renders them directly using webView. Android cannot do this.

How do I load the PDF?

There are many ways to load, such as directly jumping to a third-party browser to load, but the product requires that you can only preview within the app, pass; Such as adding Google services before PDF links that are not accessible in China, pass; For example, after downloading and then loading, but when the PDF volume is large and the network is not good, there will be problems in downloading, and pass;

There are a variety of ways, there are also a lot of third-party wheels, but for their own development needs, as well as to meet the UI design, it is necessary to carry out a second transformation.

After many comparisons, the webView loading PDF scheme is more consistent with most scenarios.

The following will describe the problem points involved in development, starting with the webView loading PDF solution.

My pit climb has begun!

Preliminary loading

The initial idea of webView loading PDF is to use JS to render,

Create a new JS

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

PDFJS.cMapUrl = 'https://unpkg.com/[email protected]/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)
    }
});
Copy the code

The new Html

<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="Width = device - width, initial - scale = 1.0, the minimum - scale = 1.0, the 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/[email protected]/build/pdf.min.js"></script>
    <script type="text/javascript" src="index.js"></script>
</head>
<body>
</body>
</html>
Copy the code

After ready to js and HTML, using the webview to online PDF (www.gjtool.cn/pdfh5/git.p… To load,

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

After a successful run, the PDF is loaded.

Add two finger zoom

Good boy, finally loading out the PDF, I am full of joy to take the result to the product to have a look.

“You’ve got it loaded, but the font looks a bit small. See if you can add double finger zoom.” Product Xiao Wang took a look,

“It must.”

Set webView to zoom, useWideViewPort to true, and Webivew to support the viewPort attribute of the meta tag.

settings? .useWideViewPort =truesettings? .builtInZoomControls =truesettings? .setSupportZoom(true) settings? .displayZoomControls =false // The zoom button is not displayed
Copy the code

And modify the META attributes in the HTML to set minimum-scale, maximum-scale, and user-scalable to yes.

After a successful run, the PDF can be zoomed in and out with two fingers.

The product looked at it and nodded. I also happily submitted the code.

Signature cannot be displayed

I thought this little feature was already developed and didn’t have much of a problem, until the test sister came to me one day,

“There is something wrong with the PDF display. When there is a seal on the PDF, the seal cannot be displayed.”

“What?”

Signature can not display, this is not self-tested, quickly find a test to link to verify, after verification, the display of the signature does have a problem. The so-called signature is the official seal or signature on the PDF. The following figure

(Source network)

The signature is added to the PDF at a later stage. For the loading of the signature, simple JS cannot be successfully loaded.

How to deal with that?

In fact, there is a very powerful third-party library pdf.js has helped us deal with it, pdF.js can be obtained by the PDF file address or PDF data stream, the concrete implementation is to call the interface function PDfjs.getDocument (URL /buffer) to load the PDF into HTML, By canvas processing and then rendering the PDF file, you can of course display the signature as well.

Download pdf.js and copy it to the Assert folder in the Android project.

The final loading method is the same as above using a WebView to load. The disadvantage is that the package size increases.

When we load PDF using pdf.js by default, we will find redundant control buttons at the top of the renderings, as shown below:

However, in the UI design, there is no control button, if I submit it like this, IT will not be long before the UI sister comes to me.

How to deal with that?

In fact, in the way used at the beginning of this article, there is no control button when loading the PDF. So the question is, can we combine the first way with pdF.js to load the PDF?

Pdf.js mainly contains two core library files, one pdf.js and one pdf.worker.js, one is responsible for API parsing and one is responsible for core parsing. If you need to incorporate the first approach, copy pdf.js, pdf.worker.js, and pdf.sandbox.js and put them in Assert.

Add references to pdf.js, pdf.worker.js, etc., to script tags in HTML

<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>
Copy the code

Modify the index.js file

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)
    }
});
Copy the code

It can be seen that after the successful operation, the seal is displayed successfully and the redundant control buttons will not be displayed. Here the effect picture is not displayed.

I happily submitted the code again.

Chinese characters are not displayed completely

After a while, I was happily typing code, when the test sister found me again,

“There is something wrong with the PDF display. Some words and characters are not displayed completely, and there is a phenomenon of missing characters.”

“What?”

When there are multiple fonts on the PDF, there will be a probability of incomplete character display. I checked and saw some warning messages appear on the console when running this type of PDF.

“Error during the font loading”

This is because when parsing PDF, the default font library can no longer cover multiple fonts, and therefore cannot display all fonts completely.

How to deal with that?

If the default font library doesn’t work, add a new font library,

In the PDF. Add cMapUrl js file = “cdn.jsdelivr.net/npm/pdfjs-d…” .

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/[email protected]/cmaps/"
Copy the code

Ok, run and see, Chinese has been shown completely.

Above, the problem of webView loading PDF has been basically solved. For the solution of webView loading PDF, the main solutions are as follows:

  • Double finger scaling;
  • Signature cannot be displayed;
  • Redundant control buttons exist.
  • Chinese characters are not displayed completely.

These are the main problems in loading PDF, the other small problems are easy to solve.

All code has been placed on Github: PDF – webView

Recommended reading:

Imitation wechat chat fried “shit” effect!! Ah, play!

Compose is coming! Mimicking free naked eye 3D effect

“Performance Optimization Series” APP memory optimization theory and practice