关于android端打开附件(pdf,cad,office等)方式的调查探究

最近项目有打开附件(pdf,cad图纸)功能,以下是我的总结。

一.关于pdf文件,目前google是支持打开pdf文件的,需要借助webview,但是最低支持版本是api16,以下是核心代码:

        mWebView = findViewById(R.id.mWebView);
        WebSettings webSettings = mWebView.getSettings();
        webSettings.setJavaScriptEnabled(true);
        webSettings.setAllowFileAccess(true);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
            webSettings.setAllowFileAccessFromFileURLs(true);
            webSettings.setAllowUniversalAccessFromFileURLs(true);
        }
        mWebView.loadUrl("http://docs.google.com/gviewembedded=true&url=" + testPath);
        

testPath是本地assets资源文件下的一个pdf文件,看起来很美好

但需要翻墙,所以这种方案不可取。

第二种方案:使用webview借助mozilla在github上的在线pdf.js打开。

mWebView.loadUrl("http://mozilla.github.io/pdf.js/web/viewer.html?file=" + testPath);

由于是在线编译可能会存在速度慢,性能差问题,甚至有的测试机可能会打开失败。

第三种方案:将上述pdf.js相关api下载到assets文件夹下,本地直接加载,下载地址传送门,集成完毕后

        WebSettings webSettings = mWebView.getSettings();
        webSettings.setJavaScriptEnabled(true);
        webSettings.setAllowFileAccess(true);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
            webSettings.setAllowFileAccessFromFileURLs(true);
            webSettings.setAllowUniversalAccessFromFileURLs(true);
        }
mWebView.loadUrl("http://mozilla.github.io/pdf.js/web/viewer.html?file=" + testPath);

这种方式能满足基本的pdf查看功能,效果图:

优点:支持缩放,关键字查找,顺时针逆时针旋转,跳页等功能;

与在线加载相比缺点:asserts文件增大了apk体积。

第四种方案:

基于第三种方案,自定义html布局实现,具体可参考:https://juejin.im/post/5aa73bf0518825556140ed46

第五种方案:

github上有很多开源的第三方view,比如pdfView:

添加依赖:

implementation 'com.github.barteksc:android-pdf-viewer:2.8.2'

以上是稳固版,作者还提供了个测试版:

compile 'com.github.barteksc:android-pdf-viewer:3.1.0-beta.1'

用法:

pdfView.fromUri(Uri)
or
pdfView.fromFile(File)
or
pdfView.fromBytes(byte[])
or
pdfView.fromStream(InputStream) // stream is written to bytearray - native code cannot use Java Streams
or
pdfView.fromSource(DocumentSource)
or
pdfView.fromAsset(String)
    .pages(0, 2, 1, 3, 3, 3) // all pages are displayed by default
    .enableSwipe(true) // allows to block changing pages using swipe
    .swipeHorizontal(false)
    .enableDoubletap(true)
    .defaultPage(0)
    // allows to draw something on the current page, usually visible in the middle of the screen
    .onDraw(onDrawListener)
    // allows to draw something on all pages, separately for every page. Called only for visible pages
    .onDrawAll(onDrawListener)
    .onLoad(onLoadCompleteListener) // called after document is loaded and starts to be rendered
    .onPageChange(onPageChangeListener)
    .onPageScroll(onPageScrollListener)
    .onError(onErrorListener)
    .onPageError(onPageErrorListener)
    .onRender(onRenderListener) // called after document is rendered for the first time
    // called on single tap, return true if handled, false to toggle scroll handle visibility
    .onTap(onTapListener)
    .onLongPress(onLongPressListener)
    .enableAnnotationRendering(false) // render annotations (such as comments, colors or forms)
    .password(null)
    .scrollHandle(null)
    .enableAntialiasing(true) // improve rendering a little bit on low-res screens
    // spacing between pages in dp. To define spacing color, set view background
    .spacing(0)
    .autoSpacing(false) // add dynamic spacing to fit each page on its own on the screen
    .linkHandler(DefaultLinkHandler)
    .pageFitPolicy(FitPolicy.WIDTH)
    .pageSnap(true) // snap pages to screen boundaries
    .pageFling(false) // make a fling change only a single page like ViewPager
    .nightMode(false) // toggle night mode
    .load();

具体用法参照原作者的wiki

效果图:

基于上面五种方法,我做了个简单的Demo

总结:

1.google 原生api支持 用在线的google需要翻墙

2.用在线的pdf.js 可能会存在打开失败的情况

3.非在线的pdf.js:app体积增大,但支持缩放,选页,搜索等等,pdf.js原生功能挺强大的

4.使用原生pdf.js,界面自定义

5.封装好的第三方:支持缩放,分页,能满足基本的查看需求。

二.关于cad文件(dwg等图纸格式)的打开方式

android原生并不支持直接打开cad文件,因此要做的话要么自己写一套打开cad的代码,这个工作量巨大,短时间内无法完成,不是专业做图纸的app的话建议还是不要采用这种方案了,

感兴趣可以参考下:https://www.opendesign.com

另一种方案是借助三方库进行二次开发。

通过调查,目前发现市场上的三方库也有不少,包括国外的Vectordraw公司提供的Vectordraw Developer Framework,国内公司,比如云图天下的CADViewer+,梦想凯德科技公司的MxDraw等。

我主要是对国内这两家公司做了个总结:

1.CADViewer+

官方网站http://www.yttxsoft.com/index.html

平台支持:支持web,ios,android的二次开发

开发文档地址http://www.yttxsoft.com/cadviewer/download.html?style=green

功能及特点:CADViewer+ for Android 是图纸浏览控件在 Android Studio 下的 Android SDK,开发者仅需要几行代码即可实现在 Android 应用中浏览、批注 图纸功能,非常容易集成到应用中。

CADViewer+ for Android 提供图纸的手指缩放、平移、布局切换、3D 视 图切换、图层显示控制、长度测量和面积测量等功能,完美支持中文字体和钢筋 符号。同时支持图纸简单批注功能,如随手画和文字批注,批注的文字可通过接 口获取。

价格:android,ios各2万,不限产品或项目,有其他需求另议。

2.MxDraw

官方网站http://www.mxdraw.com

平台支持:支持web,ios,android的二次开发

开发文档http://www.mxdraw.com/help_6_80.html

试用详细信息:http://www.mxdraw.com/help_2_10091.html

功能及特点:

1.文件操作功能,读写CAD文件

2.图纸预览与打印功能:放大,缩小,平移

3.参数化绘图:会直线、圆、圆弧、PL线、样条线、椭圆、椭圆弧、文字、点、块等;填充功能;可以自定义线性,文字样式、填充图案。

4.图形编辑:绘图捕捉、夹点编辑、删除操作、修改图层,线形等属性,遍历数据库,读写拓展数据库,拓展记录及其它编辑功能。

5.图面处理与交互:构造选择集,图面搜索,与用户交取点,动态拖放显示,鼠标事件反应器。

6.其他功能:实体闪烁,实体信息动态提示,相关接口使用例程,帮助文档。

价格:与点数(即同时在线使用手机台数)有关,2.8万-5.9万(无限点)。

三、关于Office文档的打开方式

1.在线打开

Google支持在线打开方式,通过系统自带的WebView直接:

mWebView.loadUrl(“https://docs.google.com/viewer?url=office文档服务器接口地址”);

但是访问Google的解析地址需要翻墙,还有一种类似方案是使用微软提供的解析接口地址:

mWebView.loadUrl(“https://view.officeapps.live.com/op/view.aspx?src=office文档服务器接口地址”);

webView相关设置:

mWebView.setWebViewClient(new MyWebViewClick());
        mWebView.getSettings().setJavaScriptEnabled(true);
        mWebView.getSettings().setUseWideViewPort(true);
public class MyWebViewClick extends WebViewClient {
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            view.loadUrl(url);
            return true;
        }

        @Override
        public void onPageFinished(WebView view, String url) {
            super.onPageFinished(view, url);
        }

    }

优点:集成简单,不会增大apk体积

缺点:在线支持,速度慢,性能问题有待商榷。

2.Apache POI

Apache POI  是用Java编写的免费开源的跨平台的 Java API,Apache POI提供API给Java程式对Microsoft Office格式档案读和写的功能。

官方网站:http://poi.apache.org

优点:定制化程度高

缺点:开发成本高,周期长,需要学习成本,且jar包比较大,增大apk体积

3.腾讯 x5内核

腾讯浏览服务(TBS,Tencent Browsing Service)整合腾讯底层浏览技术和腾讯平台资源及能力,提供整体浏览服务解决方案。

官网网站:https://x5.tencent.com/tbs/index.html

sdk接入文档:https://x5.tencent.com/tbs/guide/sdkInit.html

官方提供了三种sdk:完整版,TbsPlus 版,完整版 + 文件能力。

下面重点说下他的文件能力:

文件格式:46种
压缩包+办公文档+其它文档格式:26种
图形文件格式: 7种
音乐文件格式:12种
其他:1种

视频格式:30余种

打开office文档,目前发现两种方式:Qbsdk及TbsReaderView。

下面说下集成时遇到的坑及注意点:

1.X5暂不提供64位的so文件,为保证64位手机能正常加载x5内核,需要进行配置:64位手机无法加载x5(libmttwebview.so is 32-bit instead of 64-bit)

2.怎么验证测试机是否加载成功了x5内核?一般我们开发人员的测试机可能没有安装qq,微信等腾讯系列app,那么此测试机肯定是没有x5内核的,解决方法是:

在已经在清单文件注册了的application里的onCreate()方法里:

QbSdk.initX5Environment(this, new QbSdk.PreInitCallback() {
            @Override
            public void onCoreInitFinished() {

            }

            @Override
            public void onViewInitFinished(boolean b) {
                Log.e("tag", "x5内核是否加载成功=" + b);
            }
        });

如果官方对此测试机做了x5支持,且测试机里已安装了x5内核,那么以上会打印出:x5内核是否加载成功=true;

如果测试机没有安装x5内核,则通过查看源码:

public static void initX5Environment(Context var0, QbSdk.PreInitCallback var1) {
        z = new j(var0, var1);
        if(TbsShareManager.isThirdPartyApp(var0)) {
            ao.a().b(var0, true);
        }

        TbsDownloader.needDownload(var0, false, false, new com.tencent.smtt.sdk.k(var0, var1));
    }

此方法会自动去下载并安装x5内核,此过程是异步的,不会很影响app启动及初始化过程

那么我们想要加载下加载进度,怎么办呢?

可以通过以下监听来实现:

QbSdk.setTbsListener(new TbsListener() {
            @Override
            public void onDownloadFinish(int i) {
                Log.e("onDownloadFinish", "===" + i);//i=100时结束下载
            }

            @Override
            public void onInstallFinish(int i) {
                Log.e("onInstallFinish", "===" + i);//i=200时结束安装
            }

            @Override
            public void onDownloadProgress(int i) {
                Log.e("onDownloadProgress", "===" + i);//0-100
            }
        });

此监听只有在测试机没有安装x5内核的时候走一遍。成功安装完成后,最后走判断是否加载x5内核成功回调。

3.如果我的测试机很不幸,没有被覆盖怎么办(官方数据显示支持97%的机型)?通过调用QbSdk.openFileReader()方法解决这个问题。

调用此方法执行阅读器的优先顺序为:

1:用 QQ 浏览器打开
2:用 MiniQB 打开
3:调起阅读器弹框
-1:filePath 为空 打开失败

public static int openFileReader(Context context, String filePath, HashMap<String, String> extraParams,ValueCallback<String> callback)

参数说明:
context :调起 miniqb 的 Activity 的 context。此参数只能是 activity 类型的 context,不能设置为 Application
的 context。
filePath :文件路径。格式为 android 本地存储路径格式,例如:/sdcard/Download/xxx.doc. 不支持 file:///
格式。暂不支持在线文件。
extraParams :miniqb 的扩展功能。为非必填项,可传入 null 使用默认设置。
其格式是一个 key 对应一个 value。在文件查看器的产品形态中,当前支持 的 key 包括:
local: “true”表示是进入文件查看器,如果不设置或设置为“false”,则进入 miniqb 浏览器模式。不是必
须设置项。
style: “0”表示文件查看器使用默认的 UI 样式。“1”表示文件查看器使用微信的 UI 样式。不设置此 key
或设置错误值,则为默认 UI 样式。
topBarBgColor: 定制文件查看器的顶部栏背景色。格式为“#xxxxxx”,例“#2CFC47”;不设置此 key 或设置
错误值,则为默认 UI 样式。
menuData: 该参数用来定制文件右上角弹出菜单,可传入菜单项的 icon 的文本,用户点击菜单项后,sdk
会通过 startActivity+intent 的方式回调。menuData 是 jsonObject 类型,结构格式如下:
public static final String jsondata =
"{
pkgName:\"com.example.thirdfile\", "
+ "className:\"com.example.thirdfile.IntentActivity\","
+ "thirdCtx: {pp:123},"
+ "menuItems:"
+ "["
+ "{id:0,iconResId:"+ R.drawable.ic_launcher +",text:\"menu0\"},
{id:1,iconResId:" + R.drawable.bookmark_edit_icon + ",text:\"menu1\"},
{id:2,iconResId:"+ R.drawable.bookmark_folder_icon +",text:\" 菜单 2\"}"
+ "]"
+ "
}";
pkgName 和 className 是回调时的包名和类名。
thirdCtx 是三方参数,需要是 jsonObject 类型,sdk 不会处理该参数,只是在菜单点击事件发生的时候原样
回传给调用方。
menuItems 是 json 数组,表示菜单中的每一项。
ValueCallback :提供 miniqb 打开/关闭时给调用方回调通知,以便应用层做相应处理。

4.如果仅仅加载office文档及pdf文档,可以通过TbsReaderView来展示,但是听网上说用此View展示也存在部分机型不展示的坑,报错:找不到TbsReaderTemp文件。解决方案也很简单,如果没有此文件就创建一个:

String bsReaderTemp = "/storage/emulated/0/TbsReaderTemp";
        File bsReaderTempFile = new File(bsReaderTemp);
        if (!bsReaderTempFile.exists()) {
            Log.e("TAG", "准备创建/storage/emulated/0/TbsReaderTemp!!");
            boolean mkdir = bsReaderTempFile.mkdir();
            if (!mkdir) {
                Log.e("TAG", "创建/storage/emulated/0/TbsReaderTemp失败!!!!!");
            }
        }
        Bundle bundle = new Bundle();
        bundle.putString("filePath", new File(path).toString());
        bundle.putString("tempPath", Environment.getExternalStorageDirectory() + "/" + "TbsReaderTemp");
        boolean result = mReadView.preOpen(getFileType(new File(path).toString()), false);
        if (result) {
            mReadView.openFile(bundle);
        } else {
            Log.e("tag", "open failed!");
        }

优点:性能高,比较稳定,机型适配高。

缺点:源码阅读困难,定制化程度较低。

个人建议:

x5内核官方四个数字:2万+(应用接入数),5.9亿(日浏览用户数),150亿(日承载浏览量),97%(内核覆盖度),

综合考虑到性能,机型适配(支持97%以上的手机),稳定性等因素,增大apk体积(jar包仅250kb)建议选择x5内核。

参考资料:

1.https://juejin.im/post/5aa73bf0518825556140ed46

2.https://github.com/barteksc/AndroidPdfViewer

3.https://www.jianshu.com/p/3f57d640b24d

猜你喜欢

转载自blog.csdn.net/qq_20089667/article/details/81388826