Android PDF阅读开发

最近项目里,需要集成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.asce1885.com/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.android.com/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
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Android开发教程PDF是一种用于学习和掌握Android开发的教学材料。通过阅读和学习这些PDF教程,开发者可以学习到Android开发的基础知识、开发环境的搭建、Android应用的UI设计、数据存储与处理、网络通信、多媒体应用开发等相关内容。 Android开发教程PDF通常由专业的Android开发者编写,经过系统整理和优化,以便于初学者理解和学习。这些教程一般包含了详细的代码示例、图文并茂的解析和实例项目,帮助读者逐步掌握Android开发的各个方面。 在学习Android开发过程中,阅读PDF教程有以下几个优点: 1. 系统性:Android开发教程PDF一般按照从基础到高级的顺序编排,帮助读者系统性地学习和掌握Android开发的各个知识点。 2. 实用性:教程中经常会以实际的应用场景为例,让读者能够将所学知识应用到实际项目中,加深理解。 3. 自学性:PDF格式的教程可以随时随地进行学习,避免了受时间和地点限制的问题。读者可以按照自己的节奏进行学习。 4. 丰富性:Android开发领域涉及的知识点众多,PDF教程的内容也很丰富,能够帮助读者全面了解和掌握Android开发的方方面面。 当然,PDF教程也有一些局限性,比如更新速度相对较慢,无法及时跟上Android开发技术的更新。此外,由于PDF教程通常是静态的,可能会缺乏与动态互动的体验。 总体而言,Android开发教程PDF是学习Android开发的一种有效方式。读者可以结合在线资源,例如官方文档、社区问答、实例代码等,综合提高自己的开发能力。 ### 回答2: Android开发教程是一种指导开发者学习和了解如何使用Android平台进行应用程序开发的工具。这种教程通常以PDF格式提供,以便开发者可以方便地在各种设备上阅读和学习。 Android开发教程PDF通常包含以下内容: 1. Android平台的基础知识:介绍Android操作系统的版本、架构和基本原理,帮助初学者建立对Android平台的基本认识。 2. Java编程基础:Android应用程序开发的核心语言是Java,因此教程通常会包含一些Java编程的基本知识和技巧,以帮助开发者在Android开发中更加熟练地运用Java语言。 3. Android应用程序架构:教程会介绍Android应用程序的组成部分,如活动、服务、广播接收器和内容提供者,以及它们之间的关系和交互。 4. 用户界面设计:教程会详细介绍如何使用Android提供的界面布局和控件来设计用户界面,以及如何处理用户输入和响应用户操作。 5. 数据存储和管理:教程会介绍如何使用Android的数据库、文件系统和SharedPreferences等工具来存储和管理应用程序的数据。 6. 网络和多媒体:教程会介绍如何使用Android的网络通信和多媒体功能,如HTTP请求、图片加载和音频播放等。 7. 调试和测试:教程会教开发者如何使用Android提供的调试工具和测试框架来调试和测试应用程序,以确保应用程序的稳定性和性能。 Android开发教程PDF可以帮助开发者系统地学习和掌握Android应用程序开发的基本知识和技能,使他们能够更加高效地开发出功能丰富、稳定可靠的Android应用程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值