从去年9月份进入新公司后,项目中需要在APP中展示PDF,这个之前没有接触过,因此也查了好多的资料和demo,这里我说明下我用过的pdf展示比较好点View或者第三方,本人亲测。
1.使用Google doc支持来展示word,excel,pdf,txt(WebView方式在线预览):
WebView urlWebView = (WebView)findViewById(R.id.containWebView);
urlWebView.setWebViewClient(new AppWebViewClients());
urlWebView.getSettings().setJavaScriptEnabled(true);
urlWebView.getSettings().setUseWideViewPort(true);
urlWebView.loadUrl("http://docs.google.com/gview?embedded=true&url="
+ "YOUR_DOC_URL_HERE");
public class AppWebViewClients extends WebViewClient {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
// TODO Auto-generated method stub
view.loadUrl(url);
return true;
}
@Override
public void onPageFinished(WebView view, String url) {
// TODO Auto-generated method stub
super.onPageFinished(view, url);
}
}
https://docs.google.com/gview?embedded=true&url=文档地址
优点:无需服务器和客户端的额外部署工作,也不用下载到本地来进行展示
缺点:国内需要翻墙访问(大多数APP估计能翻墙的少,因此也用的少)
2.使用Github上第三方自定义控件,链接:
https://github.com/barteksc/AndroidPdfViewer
使用方法:
①XML布局
<com.github.barteksc.pdfviewer.PDFView
android:id="@+id/pdf_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
②Activity或者Fragment使用,实现OnPageChangeListener和OnLoadCompleteListener接口监听,目的是为了PDF翻页时的操作和PDF加载完成后的操作(如:关闭加载进度条等)
//pdf展示方法
private void displayFromFile(String pdfPath) {
mPdfView.fromFile(new File(pdfPath))
.defaultPage(1)
.onPageChange(this)
.swipeHorizontal(false)
//.swipeVertical(false)
//.showMinimap(false)
.enableAnnotationRendering(true)
.onLoad(this)
.load();
}
优点:加载快,不需要考虑手机的硬件的兼容,可以展示本地PDF文件,也可以展示Android中assets目录中的PDF文件
缺点:不支持在线预览,引入到项目中后,APK体积增加12-15M左右。
3.基于腾讯浏览服务Tbs,使用X5Webkit内核来展示,想了解腾讯X5的可以去官网:https://x5.tencent.com/tbs/ 。 使用过程如下:
①下载Jar包:https://x5.tencent.com/tbs/sdk.html
②兼容64位手机,在app的build.gradle中添加:
defaultConfig {
applicationId "com.fssmw.qc"
minSdkVersion 18
targetSdkVersion 25
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
ndk { X5兼容64位手机
abiFilters 'armeabi', 'x86', "armeabi-v7a", "mips"
}
}
③添加so文件
④调用,在Appliacation中初始化X5,并自定义View来使用X5Webkit内核
public void X5Init() {
//搜集本地tbs内核信息并上报服务器,服务器返回结果决定使用哪个内核。
QbSdk.PreInitCallback cb = new QbSdk.PreInitCallback() {
@Override
public void onViewInitFinished(boolean arg0) {
// TODO Auto-generated method stub
//x5內核初始化完成的回调,为true表示x5内核加载成功,否则表示x5内核加载失败,会自动切换到系统内核。
LogUtil.e("X5", " onViewInitFinished is " + arg0);
}
@Override
public void onCoreInitFinished() {
LogUtil.e("X5", " onCoreInitFinished @@@@@@@@@@" );
// TODO Auto-generated method stub
}
};
//x5内核初始化接口
QbSdk.initX5Environment(getApplicationContext(), cb);
}
package com.fssmw.qc.widget;
import android.content.Context;
import android.os.Bundle;
import android.os.Environment;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import com.smw.arch_pattern.util.LogUtil;
import com.tencent.smtt.sdk.TbsReaderView;
import java.io.File;
/**
* @date: 2017/10/19
* @autror: LiFei
* @description: 使用腾讯X5加载word,ppt,pdf
*/
public class SuperFileView extends FrameLayout implements TbsReaderView.ReaderCallback {
private static String TAG = "SuperFileView";
private TbsReaderView mTbsReaderView;
private int saveTime = -1;
private Context context;
public SuperFileView(Context context) {
this(context, null, 0);
}
public SuperFileView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SuperFileView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mTbsReaderView = new TbsReaderView(context, this);
this.addView(mTbsReaderView, new LinearLayout.LayoutParams(-1, -1));
this.context = context;
}
private OnGetFilePathListener mOnGetFilePathListener;
public void setOnGetFilePathListener(OnGetFilePathListener mOnGetFilePathListener) {
this.mOnGetFilePathListener = mOnGetFilePathListener;
}
private TbsReaderView getTbsReaderView(Context context) {
return new TbsReaderView(context, this);
}
public void displayFile(File mFile) {
if (mFile != null && !TextUtils.isEmpty(mFile.toString())) {
//增加下面一句解决没有TbsReaderTemp文件夹存在导致加载文件失败
String bsReaderTemp = "/storage/emulated/0/TbsReaderTemp";
File bsReaderTempFile =new File(bsReaderTemp);
if (!bsReaderTempFile.exists()) {
LogUtil.e("准备创建/storage/emulated/0/TbsReaderTemp!!");
boolean mkdir = bsReaderTempFile.mkdir();
if(!mkdir){
LogUtil.e("创建/storage/emulated/0/TbsReaderTemp失败!!!!!");
}
}
//加载文件
Bundle localBundle = new Bundle();
LogUtil.e(mFile.toString());
localBundle.putString("filePath", mFile.toString());
localBundle.putString("tempPath", Environment.getExternalStorageDirectory() + "/" + "TbsReaderTemp");
if (this.mTbsReaderView == null)
this.mTbsReaderView = getTbsReaderView(context);
boolean bool = this.mTbsReaderView.preOpen(getFileType(mFile.toString()), false);
if (bool) {
this.mTbsReaderView.openFile(localBundle);
}
} else {
LogUtil.e("文件路径无效!");
}
}
/***
* 获取文件类型
*
* @param paramString
* @return
*/
private String getFileType(String paramString) {
String str = "";
if (TextUtils.isEmpty(paramString)) {
LogUtil.e(TAG, "paramString---->null");
return str;
}
LogUtil.e(TAG, "paramString:" + paramString);
int i = paramString.lastIndexOf('.');
if (i <= -1) {
LogUtil.e(TAG, "i <= -1");
return str;
}
str = paramString.substring(i + 1);
LogUtil.e(TAG, "paramString.substring(i + 1)------>" + str);
return str;
}
public void show() {
if(mOnGetFilePathListener!=null){
mOnGetFilePathListener.onGetFilePath(this);
}
}
/***
* 将获取File路径的工作,“外包”出去
*/
public interface OnGetFilePathListener {
void onGetFilePath(SuperFileView mSuperFileView2);
}
@Override
public void onCallBackAction(Integer integer, Object o, Object o1) {
LogUtil.e("****************************************************" + integer);
}
public void onStopDisplay() {
if (mTbsReaderView != null) {
mTbsReaderView.onStop();
}
}
}
显示PDF:
mSfvView.displayFile(new File(file));