Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PDF in Android #170

Open
soapgu opened this issue Oct 8, 2022 · 0 comments
Open

PDF in Android #170

soapgu opened this issue Oct 8, 2022 · 0 comments
Labels
Demo Demo JAVA This doesn't seem right Research 安卓 安卓

Comments

@soapgu
Copy link
Owner

soapgu commented Oct 8, 2022

  • 前言

iOS有专门的相对成熟的解决方案PDF的官方库PdfKit,而Android确没有“正规军”
只能从第三方库里去“收编”了
一开始想用MuPdf,原来我在windows桌面程序使用过。算是C#二次封装的,但是好歹免费好用。
后来查了下官网,直接有AppKit
问题兴奋没多久,原来“免费”对是带水印的版本,真正能用的是要lisence。
图片

  • 寻找新方向

无奈之下,只能再找方向。既要好用又要免费,其实条件不算低了,找来找去只能在github上翻。
总算翻到一个

7.4K的Star,貌似搜一下也有蛮多人用。看上去还行。
ReadME里面的Quick Start非常简单粗暴。

  • 试用填坑之旅

  1. 无法下载引用问题
    首先按照QuickStart的方法先加入引用
    implementation 'com.github.barteksc:android-pdf-viewer:3.2.0-beta.1'
    结果Failed to resolve: com.github.barteksc:android-pdf-viewer,上来就翻车,真不给面子!
    搜了下StackOverflow,原来默认仓库里面是没有的,要加gradlePluginPortal()
    其实这个解决方案有点迷,gradlePluginPortal不是插件的仓库嘛,问题是管用!
    毕竟是一个3年没维护的组件,可能在更新上有点问题
  1. Android X冲突解决
    引用下载是第一步,接下来如果使用了引用,编译后会各种冲突。因为组件不是AndroidX编译的是用的老版本。
    这里我们需要在gradle.properties里面加上
    android.enableJetifier=true
    这样可以保证老版本的兼容性。
    注:我们用的是AndroidX,所以肯定会有这行android.useAndroidX=true
  • 调用assets资源

这里学一个新技能assets。

  1. 新建

我们可以通过New -> Folder -> Assets Folder 完成。
然后把我们的预设PDF放到这个文件夹内。这样打包APK的时候这些文件可以被一起打包。

  1. 访问

注意:这些文件和res文件夹下的文件是不同的,是不可以直接用R来访问的
但是可以通过AssetManager来访问

private String[] loadPdfList() {
        try {
            return Arrays.stream(this.getAssets().list(""))
                    .filter(n -> n.endsWith(".pdf"))
                    .toArray(String[]::new);
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

这里其实除来我自己定义的,还“混”进来其他文件,我需要做一个筛选

这些文件不能直接使用!只能通过open把文件拷贝出来使用!

public static File fileFromAsset(Context context, String assetName) throws IOException {
        File outFile = new File(context.getCacheDir(), assetName + "-pdfview.pdf");
        if (assetName.contains("/")) {
            outFile.getParentFile().mkdirs();
        }
        copy(context.getAssets().open(assetName), outFile);
        return outFile;
    }
  • 获取封面缩略图

看ReadME的API好像没有,也没正式的文档。只能到issue里面找解决方案

private Bitmap loadImage(String fileName) throws IOException {
        File f = Utils.fileFromAsset(this,fileName);
        ParcelFileDescriptor pfd = ParcelFileDescriptor.open(f, ParcelFileDescriptor.MODE_READ_ONLY);
        PdfDocument pdfDocument = pdfiumCore.newDocument(pfd);

        pdfiumCore.openPage(pdfDocument, 0);
        int width = pdfiumCore.getPageWidthPoint(pdfDocument, 0);
        int height = pdfiumCore.getPageHeightPoint(pdfDocument, 0);

        float scaleValue = size / Math.max(width,height);

        // ARGB_8888 - best quality, high memory usage, higher possibility of OutOfMemoryError
        // RGB_565 - little worse quality, twice less memory usage

        int targetWidth = (int) (width*scaleValue);
        int targetHeight = (int) (height*scaleValue);
        Bitmap bitmap = Bitmap.createBitmap(targetWidth, targetHeight,
                Bitmap.Config.RGB_565);
        pdfiumCore.renderPageBitmap(pdfDocument, bitmap, 0, 0, 0,
                targetWidth , targetHeight);
        pdfiumCore.closeDocument(pdfDocument);
        return bitmap;
    }
  1. 图片的生成可以随意控制像素和质量来满足不同需求
  2. 注意pdfiumCore.closeDocument(pdfDocument);不要忘记,内存泄露很危险
  • PDF浏览

这其实照抄QuickStart就行最简单了

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:clickable="true"
    tools:context=".PdfFragment"
    android:focusable="true">
    <com.github.barteksc.pdfviewer.PDFView
        android:id="@+id/pdfView"
        android:background="@color/teal_200"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

这里最好加个background,否则白色的底浏览效果不佳

private void displayFromFile(String assetFileName) {
        try {
            File pdfFile = Utils.fileFromAsset(requireContext(),assetFileName);
            pdfView.fromFile(pdfFile)
                    .defaultPage(0)
                    //.onPageChange(this)
                    .enableAnnotationRendering(true)
                    //.onLoad(this)
                    .scrollHandle(new DefaultScrollHandle(requireContext()))
                    .spacing(10) // in dp
                    //.onPageError(this)
                    .pageFitPolicy(FitPolicy.BOTH)
                    .load();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

这里就是直接抄Demo,把一些钩子去掉了。

  • 题外话

细心的同学会发现我前面的ConstraintLayout加了android:clickable="true"。
那是解决一个点击事件穿透的问题。
也是刚刚发现的。在WPF里面是没有的。发现上层的元素点击后会穿到下层去!这点就有点困扰了,还会产生不必要的bug。
解决方法就是在上层的元素里加android:clickable="true",这样点击后穿不下去了。

@soapgu soapgu added 安卓 安卓 JAVA This doesn't seem right Research Demo Demo labels Oct 9, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Demo Demo JAVA This doesn't seem right Research 安卓 安卓
Projects
None yet
Development

No branches or pull requests

1 participant