分享

android阅读器pdf开发...

 创始元灵6666 2022-07-28 发布于河北

最近项目里,需要集成PDF阅读,翻阅了很多网站,发现Android系统不支持PDF阅读,网上现有的库和插件,都会增大apk的体积,综合比较了一下,解决方案有如下几种:

1.谷歌提供了在线阅读,在webView中调用GoogleDocs

     但是由于国内手机无法获取Google提供支持,所以这种方案基本被否决,其使用方式如下:

public void setDocumentPath(final String path) {
    WebView webView = (WebView) findViewById(R.id.webview);
    webView.getSettings().setJavaScriptEnabled(true);
    webView.getSettings().setPluginsEnabled(true);
    webView.loadUrl("https://docs.google.com/viewer?url=http://www./cms/wwwroot/ng/downLoad/011615200732.pdf");
}

2.最简单的方式就是跳第三方的浏览器,下载阅读

   下载完成后,如果浏览器含有PDF阅读插件,便可以在浏览器中直接打开,否则还要下载PDF阅读器方可阅读,使用方式如下:

public Intent getPdfFileIntent(File file) {
    Intent intent = new Intent("android.intent.action.VIEW");
    intent.addCategory("android.intent.category.DEFAULT");
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    Uri uri = Uri.fromFile(file);
    intent.setDataAndType(uri, "application/pdf");
    return Intent.createChooser(intent, "Open File");
}

3.利用腾讯X5内核浏览器的Tbs,下载阅读

  下载完成后,首先加载X5插件,中间会有一段时间特别缓慢,官方建议可以再application中进行加载初始化,但这会导致APP启动时间增长,更糟糕的是卡在启动页,出现的原因:手机没有X5内核浏览器,需要开启服务下载(鉴于自己的项目,仅仅是猜测),其具体的使用方法如下(我这里自己封装了一个下载工具,下面的几种方式都采用这个工具):

import android.app.DownloadManager;
import android.app.DownloadManager.Query;
import android.app.DownloadManager.Request;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.database.Cursor;
import android.net.Uri;
import android.os.Environment;
import android.util.Log;


import com.mysteel.android.steelphone.bean.ebe.EBPdfMsg;

import org.greenrobot.eventbus.EventBus;

import java.io.File;

import static android.app.DownloadManager.ACTION_DOWNLOAD_COMPLETE;
import static android.app.DownloadManager.ACTION_NOTIFICATION_CLICKED;
import static android.app.DownloadManager.STATUS_FAILED;
import static android.app.DownloadManager.STATUS_PAUSED;
import static android.app.DownloadManager.STATUS_PENDING;
import static android.app.DownloadManager.STATUS_RUNNING;
import static android.app.DownloadManager.STATUS_SUCCESSFUL;

public class DownloadPdfUtils {

    //下载器
    private DownloadManager downloadManager;

    //上下文
    private Context mContext;

    //下载的ID
    private long downloadId;

    private boolean mReceiverTag = false;

    public DownloadPdfUtils(Context context) {
        if (context == null) {
            return;
        }
        this.mContext = context;

    }


    public void downloadUrl(String url, String name) {


        //创建下载任务
        Request request = new Request(Uri.parse(url));
        //移动网络下是否允许
        request.setAllowedOverRoaming(false);

        //在通知栏中显示,默认就是显示的
        request.setNotificationVisibility(Request.VISIBILITY_HIDDEN);
        request.setVisibleInDownloadsUi(true);

        //设置下载路径
        final String sdcard = Environment.getExternalStorageDirectory().getAbsolutePath();
        final String pdfPath = sdcard + "/mysteel/pdf";
        if (!(new File(pdfPath)).exists()) {
            (new File(pdfPath)).mkdirs();
        }
        File file = new File(pdfPath, name);

        request.setDestinationUri(Uri.fromFile(file));

        downloadManager = ((DownloadManager) mContext.getSystemService(Context.DOWNLOAD_SERVICE));
        removePdfFile();
        downloadId = downloadManager.enqueue(request);
        mContext.registerReceiver(receiver, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
        mReceiverTag = true;
    }

    private BroadcastReceiver receiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent.getAction() == ACTION_DOWNLOAD_COMPLETE) {
                checkStatus();
            }
        }
    };

    private BroadcastReceiver receiver1 = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent.getAction() == DownloadManager.ACTION_NOTIFICATION_CLICKED) {
                downloadManager.remove(downloadId);
            }
        }
    };

    /**
     * 下载状态
     */
    private void checkStatus() {
        Query query = new Query();

        //通过下载的ID查找
        Cursor cursor = downloadManager.query(query);

        if (cursor.moveToFirst()) {
            int status = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS));
            switch (status) {
                case STATUS_PAUSED:
                    break;
                case STATUS_PENDING:
                    break;
                case STATUS_RUNNING:
                    break;
                case STATUS_SUCCESSFUL:
                    EBPdfMsg event = new EBPdfMsg();
                    event.setUrl(queryUrl());
                    EventBus.getDefault().post(event);
                    break;
                case STATUS_FAILED:
                    break;
                default:
                    break;
            }
        }
        cursor.close();
        mContext.unregisterReceiver(receiver);
        mReceiverTag = false;
    }

    /**
     * 返回文件下载路径
     *
     * @return
     */
    public String queryUrl() {
        String url = "";
        if (downloadId != -1) {
            DownloadManager.Query query = new DownloadManager.Query();
            query.setFilterById(downloadId);
            query.setFilterByStatus(DownloadManager.STATUS_SUCCESSFUL);
            Cursor cursor = downloadManager.query(query);
            if (cursor != null) {
                if (cursor.moveToFirst()) {
                    url = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));
                }
            }
            assert cursor != null;
            cursor.close();
        }
        return url;
    }

    /**
     * 取消下载
     */
    public void cancelDownload() {
        mContext.registerReceiver(receiver1, new IntentFilter(ACTION_NOTIFICATION_CLICKED));
    }

    /**
     * 取消广播注册
     */
    public void unRegister() {
        if (mReceiverTag) {
            mContext.unregisterReceiver(receiver);
        }
        mContext.unregisterReceiver(receiver1);
    }

    /**
     * 删除PDF文件
     */
    private void removePdfFile() {
        DownloadManager.Query query = new DownloadManager.Query();
        query.setFilterByStatus(DownloadManager.STATUS_SUCCESSFUL);
        Cursor cursor = downloadManager.query(query);
        if (cursor != null) {
            while (cursor.moveToNext()) {
                if (cursor.getColumnIndex(DownloadManager.COLUMN_ID) != -1) {
                    downloadManager.remove(cursor.getLong(cursor.getColumnIndex(DownloadManager.COLUMN_ID)));
                }
            }
        }
        assert cursor != null;
        cursor.close();
    }
}

具体的集成方式可以去腾讯官网查看:https://x5.tencent.com/

首先,在Application中初始化X5浏览,虽说这是一个轻量级的不会造成ANR但是还是采用服务比较稳妥,具体如下:

写一个服务类:

import android.app.IntentService;
import android.content.Intent;
import android.support.annotation.Nullable;

import com.tencent.smtt.sdk.QbSdk;

/**
 * 预加载X5内核浏览器
 */
public class X5CorePreLoadService extends IntentService{

    private static final String TAG = X5CorePreLoadService.class.getSimpleName();

    public X5CorePreLoadService() {
        super(TAG);
    }

    @Override
    protected void onHandleIntent(@Nullable Intent intent) {
        //在这里添加我们要执行的代码,Intent中可以保存我们所需的数据,
        //每一次通过Intent发送的命令将被顺序执行
        initX5();
    }

    /**
     * 初始化X5内核
     */
    private void initX5() {
        if (!QbSdk.isTbsCoreInited()) {
            QbSdk.preInit(getApplicationContext(), null);// 设置X5初始化完成的回调接口
        }

        QbSdk.initX5Environment(getApplicationContext(), cb);
    }

    QbSdk.PreInitCallback cb = new QbSdk.PreInitCallback() {

        @Override
        public void onViewInitFinished(boolean arg0) {
            // TODO Auto-generated method stub
            //初始化完成回调
        }

        @Override
        public void onCoreInitFinished() {
            // TODO Auto-generated method stub
        }
    };
}

其次,在Application中初始化:

public class MyApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();        
        preInitX5Core();
    }

    
    /**
     * 初始化X5内核
     */
    private void preInitX5Core() {
        //预加载x5内核
        Intent intent = new Intent(this, X5CorePreLoadService.class);
        startService(intent);
    }  
}

在Activity中显示,这里需要注意6.0权限,我用的EasyPermission,具体用法:https://github.com/googlesamples/easypermissions,TBS在Activity中使用

public class WebActivity extends AppCompatActivity implements TbsReaderView.ReaderCallback {


    private static final int PERMISSION_CODE3 = 1;
    private TbsReaderView mTbsReaderView;

    private FrameLayout mPdf;

    public static final String url = "";//PDF链接
    private DownloadPdfUtils downloadUtils;
    private String[] PERMISSION_ARRAYS3 = {Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_web);
        mPdf = findViewById(R.id.read_pdf);
        mTbsReaderView = new TbsReaderView(this, this);
        mPdf.addView(mTbsReaderView, new RelativeLayout.LayoutParams(-1, -1));
        downloadUtils = new DownloadPdfUtils(this);
        if (url != null) {
            checkPermission();
        }
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onMessageEvent(EBPdfMsg event) {
        String urls = event.getUrl();
        displayFile(new File(urls).getName());
    }

    /**
     * 检查是否有权限
     */
    @AfterPermissionGranted(PERMISSION_CODE3)
    private void checkPermission() {
        if (EasyPermissions.hasPermissions(this, PERMISSION_ARRAYS3)) {
            downloadUtils.downloadUrl(url, pdfName);
        } else {
            //Auto to do
        }
    }

    /**
     * PDF阅读
     *
     * @param name
     */
    private void displayFile(String name) {
        Bundle bundle = new Bundle();
        bundle.putString("filePath", Environment.getExternalStorageDirectory().getAbsolutePath() + "/mysteel/pdf" + File.separator + name);
        bundle.putString("tempPath", Environment.getExternalStorageDirectory().getAbsolutePath() + "/mysteel/pdf");
        boolean result = mTbsReaderView.preOpen(getFileType(name), false);
        if (result) {
            mTbsReaderView.openFile(bundle);
        }
    }

    /**
     * 文件类型是否是.pdf
     *
     * @param paramString
     * @return
     */
    public static String getFileType(String paramString) {
        String str = "";

        if (TextUtils.isEmpty(paramString)) {
            return str;
        }
        int i = paramString.lastIndexOf('.');
        if (i <= -1) {
            return str;
        }
        try {
            str = paramString.substring(i + 1);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return str;
    }

    @Override
    public void onCallBackAction(Integer integer, Object o, Object o1) {
    }
}

activity的xml如下:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
        xmlns:android="http://schemas./apk/res/android"
        android:id="@+id/read_pdf"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

4.利用PDFVIew进行加载,可能会使apk增大4M左右,其依赖地址:https://github.com/barteksc/AndroidPdfViewer

使用方式如下:

public class ReadPdfActivity extends AppCompatActivity  {


    private static final int PERMISSION_CODE3 = 1;
    private PDFView mPdf ;

    public static final String url = "";//PDF链接
    private DownloadPdfUtils downloadUtils;
    private String[] PERMISSION_ARRAYS3 = {Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_web);
        mPdf = findViewById(R.id.read_pdf);
        downloadUtils = new DownloadPdfUtils(this);
        if (url != null) {
            checkPermission();
        }
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onMessageEvent(EBPdfMsg event) {
        String urls = event.getUrl();
        displayFile(new File(urls).getName());
    }

    /**
     * 检查是否有权限
     */
    @AfterPermissionGranted(PERMISSION_CODE3)
    private void checkPermission() {
        if (EasyPermissions.hasPermissions(this, PERMISSION_ARRAYS3)) {
            downloadUtils.downloadUrl(url, pdfName);
        } else {
            //Auto to do
        }
    }

    /**
     * PDF阅读
     *
     * @param name
     */
    private void displayFile(String name) {
        mReadPdf.fromFile(new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/mysteel/pdf" + File.separator + name))
                .swipeHorizontal(false)
                .enableDoubletap(true)
                .defaultPage(0)
                .onError(new OnErrorListener() {
                    @Override
                    public void onError(Throwable t) {
                        showEmpty();
                    }
                })
                .load();
    }

 
}

5.利用PDFJS,这种效果不是很好,感兴趣的可以去官网自行查看:https://github.com/mozilla/pdf.js/

总结:

    这五种方式,体积最小的是腾讯的TBS,体积最大的PDFView,个人比较推崇使用PDFView,pdfjs这个实现方式有三种,服务器前后端配合这种我没有使用,其他两者种,在下拉滑动时,可能会出现空白页,界面不太友好,但最终能显示。当然刨去网络问题还是Google docs最好,但是这种在国内无法使用。以上代码中有误的地方还望各位小伙伴指出。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多