安卓调用PrinterShare实现无线打印功能
最近项目需要用到蓝牙打印,百度了很多资料,关于安卓移动打印的文章都不是很详细。要知道自己去写一个蓝牙打印模块那可是一个比较大的工作量了,而且还需要对市面上的打印机进行兼容。这个我引用一篇文章大家看下:
一、Android客户端打印技术现状
云打印
在Android KitKat之前,Google推出云打印,用户将需要打印的数据上传到服务器并填写好联系信息,打印好的图片邮寄给用户。
这是一种商业模式而非技术手段。也就是说在Android KitKat之前,Google一直没有推出Android打印的技术方案。除了Google推出的云打印方案,还存在很多第三方公司,也提供类似的方案(参考:2)。
打印框架
KitKat发布,Google推出了打印框架。该框架作为需要使用打印服务的应用于实现打印服务的应用之间的接口,通过该框架方便了开发者对打印功能的使用。其中,需要使用打印服务的应用使用打印框架API申请服务,具体的打印服务由打印机原始设备生产生提供。本质上,该框架方便了应用打印功能的使用,但实际上打印中最为关键的打印数据流的创建仍然是打印机生产商提供的APK来完成。(参考:3)
第三方
除了各大打印机生产厂商提供的打印APK,还有部分第三方也提供具有打印功能的应用,比如 PrinterShare这款应用。该应用的实现原理不明,猜测可能是其获取到了各个厂商的PDL的支持情况,并且拥有特定PDL的开发参考数据。
市场上的产品
以金山公司的 WPS为例,该应用支持常用办公文件的打印,打印提供两种选项:第一,使用系统的打印服务,即之前提到的KitKat之后的打印框架;第二,生成.ps文件。需要说明的一点是,该文件的内容是PostScript,根据前面的描述可知,该文件并不被所有打印机支持。所以,该应用的做法是,通过使用打印框架提供打印功能,同时提供对部分打印机的支持。此外,通过搜索可以发现,目前市场上关于打印类的应用非常少。(参考:4)
二、可行方案
通过前面的了解,确定两种方案
- 方式一:应用操作 excel 文件填入数据,打印功能由第三方应用实现
- 方式二:使用PDL实现打印
方式一
- 应用更新并下载打印模板(.xsl文件)
- 应用通过第三方SDK操作模板文件,将相应的数据填入
- 打印目标文件生成完成后,用户通过第三方应用实施打印
第三方应用:
1)厂商提供的APK,支持某些型号的打印机(支持范围不广)
2)第三方提供的APK,比如PrintShare(支持的范围较广,参考:5)
关于打印机的选择,支持的打印机要求:
a. 便于携带
b. 插件支持
c. 价格在一定范围
方式二
- 同方式一,但是下载的文件是.txt文件
- 应用将模板txt与数据拼合
- 应用生成打印数据流通过蓝牙发往打印机
比较
打印方式 | 打印效果 | 开发和维护难度 | 应用的使用难度 |
---|---|---|---|
方式一 | 好 | 简单 | 比较复 |
方式二 | 不好 | 复杂 | 低 |
打印效果方面,方式一的打印效果几乎与通过PC打印效果一直,方式二的打印效果存在字体模糊、样式不能被完全体现等问题。
技术实现方面,方式一可利用现有的比价成熟的excel文件操作SDK,方式二需要处理格式转换、文件拼接以及打印数据生成等问题。
实际选用:方式二。
三、HP PCL 3 打印语言
具体内容参考手册:PCL3_developers_guide.pdf
下面简要介绍一下该语言的基础知识
- 改语言由指令构成,类似汇编语言,每种功能通过特定的指令实现。比如,字号的设置通过某条指令实现
- 该指令存在多个版本,目标打印机使用的版本是 PCL 3 GUI,其是 PCL的第三版,相对 PCL 3对图形打印有较好的支持,其语言指令是PCL 3的超集。
可以看到还是比较复杂的。今天我们就调用PrinterShare实现打印,打印工作交给它去做,我们把文件传给他就行,具体实现流程:
1、下载官方apk,不要去国内市场去下载,ps:我在国内市场上下载的apk包名跟官方不一样(/ □ \)com.dynamixsoftware.printershareoaj,最新版是这个com.dynamixsoftware.printershare
2、反编译apk,这个不用说了大家都会;
3、查看清单文件我们需要关注几点:
1)、包名
2)、相关activity这里有很多打印模式:图片、pdf、word、doc、xls、ppt等等,我打印的是txt文本,选择的是这个activity
4、撸代码。。。
1)、把apk安装包copy到assets目录下
2)、安装apk,检测是否已经安装:
public static boolean isInstallApp(Context context, String packageName) { return !RxDataUtils.isNullString(packageName) && RxIntentUtils.getLaunchAppIntent(context, packageName) != null; }
如果已经安装就去打印,这里就用到了我们上面解析清单文件的内容了,设置包名、动作传递、文件类型、设置数据:
ComponentName comp = new ComponentName("com.dynamixsoftware.printershare","com.dynamixsoftware.printershare.ActivityPrintDocuments"); Intent intent = new Intent(); intent.setComponent(comp); intent.setAction("android.intent.action.VIEW"); intent.setType("text/plain"); intent.setData(Uri.parse(Environment.getExternalStorageDirectory().getPath()+"/test.txt")); startActivity(intent);
ps:这里我直接在sd卡跟目录放置了一个test文本。
关于ComponentName大家可以查下资料,可以打开另一个应用的组件。
如果没有安装就把文件拷贝出来再安装:
从assets里面copy文件:
public File getAssetFileToCacheDir( String fileName) { try { File cacheDir = FileUtil.getCacheDir(MyApp.getApplictaion()); final String cachePath = cacheDir.getAbsolutePath()+ File.separator + fileName; InputStream is = MyApp.getApplictaion().getAssets().open(fileName); File file = new File(cachePath); file.createNewFile(); FileOutputStream fos = new FileOutputStream(file); byte[] temp = new byte[1024]; int i = 0; while ((i = is.read(temp)) > 0) { fos.write(temp, 0, i); } fos.close(); is.close(); getActivity().runOnUiThread(new Runnable() { @Override public void run() { mRxDialogLoading.cancel(); } }); return file; } catch (IOException e) { e.printStackTrace(); } return null; }
安装:
public static void InstallAPK(Context context, String APK_PATH) {//提示安装APK Intent i = new Intent(Intent.ACTION_VIEW); i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); i.setDataAndType(Uri.parse("file://" + APK_PATH), "application/vnd.android.package-archive"); context.startActivity(i); }
到此整个调用PrinterShare打印就完成了我们看下效果:
点击打印提示安装apk:
安装成功,再点击“打印”按钮
继续,这个时候提示需要加载渲染库,点击是,ps:慢慢等它加载完~~~
最后预览图:
test原文本是这样的:
吐槽,PrinterShare的UI是真的丑~~~~~