最近有个需求,在 App 内查看使用第三方签名的电子协议,电子协议为 PDF 文件。
上网查了一下,要实现 App 内在线查看 PDF,主要思路都是先把 PDF 文件下载下来,再通过 GitHub 第三方的库,打开 PDF 文件。
参考文章
使用腾讯TBS打开Office文件 https://www.jianshu.com/p/8bd1c4918857
Android应用内展示word、excel、pdf、ppt等文件 https://www.jianshu.com/p/3f57d640b24d
常用的第三库:
https://github.com/voghDev/PdfViewPager
|
AndroidPdfViewer
https://github.com/barteksc/AndroidPdfViewer
|
android-pdfview
https://github.com/JoanZapata/android-pdfview
|
腾讯浏览服务
https://tes.qq.com/tbs/guide.html
|
这里我选择了使用腾讯浏览服务的 SDK 查看 PDF 文件。
主要步骤如下:
一、下载腾讯浏览服务 SDK 并集成到应用
腾讯浏览服务官网 https://tes.qq.com/tbs/guide.html
sdk中主要包含一个jar包和一个.so文件,将jar包和.so文件导入到lib目录
二、NDK 设置
打开对应 module 中的 build.gradle 文件,
在文件的 android{} 中的 defaultConfig{} 里,
添加如下配置: ndk{abiFilters “armeabi”}
android { defaultConfig { ndk { abiFilters "armeabi-v7a", "armeabi" } } sourceSets { main { jniLibs.srcDirs = ['libs'] } } }
|
三、AndroidManifest.xml 里加入权限声明
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
|
四、初始化 X5 内核
// 设置是否在没有WiFi的情况下下载内核 //QbSdk.setDownloadWithoutWifi(true); //初始化X5内核 QbSdk.initX5Environment(this, new QbSdk.PreInitCallback() { @Override public void onCoreInitFinished() { } @Override public void onViewInitFinished(boolean b) { //x5內核初始化完成的回调,为true表示x5内核加载成功,否则表示x5内核加载失败,会自动切换到系统内核。 } });
|
五、将 PDF 文件下载到本地,然后使用 SDK 里面的 TbsReaderView 打开 PDF 文件。
下载文件的方法,项目中是使用的 Retfrofit 和 Okhttp,并且进行了的封装,并不通用。所以下载文件的方法请自行编写。
1、xml 布局页面
<android.support.v7.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/ll_root" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".ui.activity.ReadPdfAgreementActivity"> </android.support.v7.widget.LinearLayoutCompat>
|
2、Activity 核心代码
public class ReadPdfAgreementActivity extends BaseAbstractActivity {
@BindView(R.id.ll_root) LinearLayoutCompat mLlRoot; private String TAG = "ReadPdfAgreementActivity"; private TbsReaderView mTbsReaderView private String url; @Override protected void onCreate() { ButterKnife.bind(this); setContentView(R.layout.activity_read_pdf_agreement); url = getIntent().getStringExtra(Constants.AGREEMENT_URL); mTbsReaderView = new TbsReaderView(this, new TbsReaderView.ReaderCallback() { @Override public void onCallBackAction(Integer integer, Object o, Object o1) { } }); mLlRoot.addView(mTbsReaderView, new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); downLoadPDF(); }
private void downLoadPDF() {
RxRestClient.builder() .url(url) .build() .download() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Observer<ResponseBody>() { @Override public void onSubscribe(Disposable d) {
}
@Override public void onNext(ResponseBody responseBody) { InputStream is = null; byte[] buf = new byte[2048]; int len = 0; FileOutputStream fos = null; try { is = responseBody.byteStream(); long total = responseBody.contentLength(); File fileDir = getAgreementCacheDir(); if (!fileDir.exists()) { fileDir.mkdirs(); } File fileN = getCacheFile(url); if (!fileN.exists()) { boolean mkdir = fileN.createNewFile(); }else { fileN.delete(); } fos = new FileOutputStream(fileN); long sum = 0; while ((len = is.read(buf)) != -1) { fos.write(buf, 0, len); sum += len; int progress = (int) (sum * 1.0f / total * 100); } fos.flush(); displayPdfFile(fileN); } catch (Exception e) { PLog.d(TAG, "文件下载异常 = " + e.toString()); } finally { try { if (is != null) is.close(); } catch (IOException e) { } try { if (fos != null) fos.close(); } catch (IOException e) { } } }
@Override public void onError(Throwable e) { PLog.d(TAG, "文件下载失败"); File file = getCacheFile(url); if (!file.exists()) { PLog.d(TAG, "删除下载失败文件"); file.delete(); } }
@Override public void onComplete() {
} }); }
private void displayPdfFile(File file){ if (file != null && !TextUtils.isEmpty(file.toString())) { //加载文件 Bundle localBundle = new Bundle(); localBundle.putString("filePath", file.toString()); localBundle.putString("tempPath", getExternalFilesDir("TbsReaderTemp").getAbsolutePath()); if (mTbsReaderView != null) { boolean bool = this.mTbsReaderView.preOpen(getFileType(mFile.toString()), false); if (bool) { mTbsReaderView.openFile(localBundle); } } } }
/*** * 获取缓存目录 * * @return */ private File getAgreementCacheDir() { String path = getExternalFilesDir("agreement").getAbsolutePath(); return new File(path); } /*** * 绝对路径获取缓存文件 * * @param url * @return */ private File getCacheFile(String url) { String fileName = "agreement" + "." + getFileType(url); File cacheFile = new File(getAgreementCacheDir(),fileName); return cacheFile; }
/*** * 获取文件类型 * * @param paramString * @return */ private String getFileType(String paramString) { String str = "";
if (TextUtils.isEmpty(paramString)) { return str; } int i = paramString.lastIndexOf('.'); if (i <= -1) { return str; } str = paramString.substring(i + 1); return str; }
@Override protected void onDestroy() { super.onDestroy(); if (mTbsReaderView != null) { mTbsReaderView.onStopDisplay(); } } }
|
3、退出 Activity 销毁 TbsReaderView
退出页面时,一定要销毁 TbsReaderView,否则下次进来无法打开文件。
@Override protected void onDestroy() { super.onDestroy(); if (mSuperFileview != null) { mSuperFileview.onStopDisplay(); } }
|