iOS打印 AirPrint

使用iOS AirPrint 让你的APP轻松实现打印功能

2016/05/13 · iOS开发 · 打印
分享到:3

原文出处: hejunm
说在前面的话
最近在做的一个iOS项目有个打印 pdf的功能。查找资料发现苹果早在 iOS 4.2 就有了 AirPrint 功能。网上关于AirPrint 的资料不多,所以就写了这篇博文。 下面就和大家分享一下自己的学习收获。
内容
1, 什么是AirPrint
其实就是将iOS(iphone,ipad)上的内容,使用支持AirPrint的打印机打印出来。打印过程无线控制, 非常方便。

2, 第一手资料
学习iOS, 第一手资料肯定非苹果官方文档莫属.here。 (我下面叙述的内容基本上是对文档的总结, 英语可以的建议直接看文档。。。)

3, Printer Simulator,使用打印模拟器进行测试
既然涉及打印功能,那么就需要有一台支持AirPrint 功能的打印机进行测试喽,你没有?没关系!苹果已经为我们准备好了模拟器。 这个模拟器在Xcode中没有, 需要自己到官网下载:下载Printer Simulator (需要先注册登录)


打印模拟器位置

4, 了解一下AirPrint可以打印的内容
an array of ready-to-print images and PDF documents: 一组图片文件和PDF文件。
a single image or PDF document: 一张图片或是一个pdf文件。、
an instance of any of the built-in print formatter classes: 打印格式化者的实例。(简单文本,html文档,某些View显示的内容)。
a custom page renderer: 自定义页渲染者。注释: 1,2 很简单,就不详细解释了,3,4姑且这样翻译了,不懂没关系, 继续向下看。。。

5, 关于AirPrint的API
AirPrint的api包含 eight classes and one protocol。 下图是它们之间的关系。(下面这张图明白了, 那你基本就掌握了)。


AirPrint相关类

UIPrintInteractionController 属性:
UIPrintInfo *printInfo: 打印任务的信息。
UIPrintPaper * printPaper : 打印内容的区域。
delegate: 遵守UIPrintInteractionControllerDelegate 协议的代理。
最重要的就是制定需要打印的内容: printingItem , printingItems, printFormatter, printPageRenderer。 四个属性都是用来指定要打印的内容的。 这四个参数是互斥的, 也就是说只要一个赋值, 其他三个参数就得是nil. 很容易理解,一个打印任务, 不能同时干多个活呀。 这里如果使用 swift的枚举,就很容易理解了。这里提到的四个关于内容的属性, 和 第4 点是关联起来的。 下面这张表是对应关系:



需要打印的内容与相应参数的对应方式

6, 打印流程
创建 UIPrintInteractionController 实例。
创建UIPrintInfo 实例。 并 配置参数 output type(输出类型), print orientation(打印方向), job name(打印工作标识), 然后赋值给UIPrintInteractionController 实例的 printInfo属性。
给delegate 属性赋值, 赋的值必须遵守 UIPrintInteractionControllerDelegate 协议。 这个代理可以 响应 printing options界面的显示和消失, 打印工作的开始和结束 等。
指定要打印的内容。 也就是指定 printingItem , printingItems, printFormatter, printPageRenderer. 参数的其中一个。
当你使用 printPageRenderer. 时情况会复杂一些。 你可以绘制每一页的header, footer, 内容。 这是你需要自己计算页数。 另外, 你也可以创建一个或多个 UIPrintFormatter实例, 通过 addPrintFormatter:startingAtPageAtIndex: 或者 printFormatters参数 赋值给 printPageRenderer.实例。 这种情况下不需要自己计算多少页。
最后就是显示显示出printing options 界面了。 方法:

在iPad上: presentFromBarButtonItem:animated:completionHandler: 或者 presentFromRect:inView:animated:completionHandler:;

1

在iPad上: presentFromBarButtonItem:animated:completionHandler: 或者 presentFromRect:inView:animated:completionHandler:;

在手机上: presentAnimated:completionHandler:

说了这么多, 理论知识就介绍的差不多了, 下面通过代码演示具体实现。
7,Printing Printer-Ready Content (打印准备好的内容)
AirPrint可以直接打印一些内容。 这些内容是 NSData, NSURL, UIImage, and ALAsset 类的实例, 但是这些实例的内容, 或者引用的类型(NSURL)必须是 image 或者pdf.
对于 image来说, NSData, NSURL, UIImage, and ALAsset 类型都可以的。 对于PDF, 只能使用 NSData, NSURL。 然后需要将这些数据实例直接赋值 给 UIPrintInteractionController实例的 printingItem 或者 printingItems 属性。
打印pdf:

  • (IBAction)printContent:(id)sender { UIPrintInteractionController *pic = [UIPrintInteractionController sharedPrintController]; if (pic & [UIPrintInteractionController canPrintData: self.myPDFData] ) { pic.delegate = self; UIPrintInfo *printInfo = [UIPrintInfo printInfo]; printInfo.outputType = UIPrintInfoOutputGeneral; printInfo.jobName = [self.path lastPathComponent]; printInfo.duplex = UIPrintInfoDuplexLongEdge; pic.printInfo = printInfo; pic.showsPageRange = YES; pic.printingItem = self.myPDFData; void (^completionHandler)(UIPrintInteractionController *, BOOL, NSError *) = ^(UIPrintInteractionController *pic, BOOL completed, NSError *error) { self.content = nil; if (!completed & error) NSLog(@"FAILED! due to error in domain %@ with error code %u", error.domain, error.code); }; if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { [pic presentFromBarButtonItem:self.printButton animated:YES completionHandler:completionHandler]; } else { [pic presentAnimated:YES completionHandler:completionHandler]; }}

  • (IBAction)printContent:(id)sender {
    UIPrintInteractionController *pic = [UIPrintInteractionController sharedPrintController];
    if (pic & [UIPrintInteractionController canPrintData: self.myPDFData] ) {
    pic.delegate = self;

      UIPrintInfo *printInfo = [UIPrintInfo printInfo];
      printInfo.outputType = UIPrintInfoOutputGeneral;
      printInfo.jobName = [self.path lastPathComponent];
      printInfo.duplex = UIPrintInfoDuplexLongEdge;
      pic.printInfo = printInfo;
      pic.showsPageRange = YES;
      pic.printingItem = self.myPDFData;
    
      void (^completionHandler)(UIPrintInteractionController *, BOOL, NSError *) =
         ^(UIPrintInteractionController *pic, BOOL completed, NSError *error) {
           self.content = nil;
           if (!completed & error)
                NSLog(@"FAILED! due to error in domain %@ with error code %u",
                error.domain, error.code);
      };
      if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
      [pic presentFromBarButtonItem:self.printButton animated:YES
          completionHandler:completionHandler];
      } else {
      [pic presentAnimated:YES completionHandler:completionHandler];
    

    }
    }

通过在iPhone上测试, 显示出的全部是英文的,不要担心, 因为这是系统的控件,也就是说系统会自动帮你作国际化处理,你不用作任何事情!你唯一要作的事–––将Info.plist文件中的第一项 Localization native development region(CFBundleDevelopmentRegion)的值设为 China(zh_CN);


Printer Options显示英文


将英文修改成中文

8, Using Print Formatters (打印格式化者)
系统提供了三个 Print Formatters类, 分别是:
UIViewPrintFormatter—automatically lays out the content of a view over multiple pages. To obtain a print formatter for a view, call the view’s viewPrintFormatter method. Not all built-in UIKit classes support printing. Currently, only the view classes UIWebView, UITextView, and MKMapView know how to draw their contents for printing. View formatters should not be used for printing your own custom views. To print the contents of a custom view, use a UIPrintPageRenderer instead.
UISimpleTextPrintFormatter—automatically draws and lays out plain-text documents. This formatter allows you to set global properties for the text, such a font, color, alignment, and line-break mode.
UIMarkupTextPrintFormatter—automatically draws and lays out HTML documents.

英文介绍已经很详细了, 就不啰嗦了, 直接展示出打印HTML文档的代码:

  • (IBAction)printContent:(id)sender { UIPrintInteractionController *pic = [UIPrintInteractionController sharedPrintController]; pic.delegate = self; UIPrintInfo *printInfo = [UIPrintInfo printInfo]; printInfo.outputType = UIPrintInfoOutputGeneral; printInfo.jobName = self.documentName; pic.printInfo = printInfo; UIMarkupTextPrintFormatter *htmlFormatter = [[UIMarkupTextPrintFormatter alloc] initWithMarkupText:self.htmlString]; htmlFormatter.startPage = 0; htmlFormatter.contentInsets = UIEdgeInsetsMake(72.0, 72.0, 72.0, 72.0); // 1 inch margins pic.printFormatter = htmlFormatter; pic.showsPageRange = YES; void (^completionHandler)(UIPrintInteractionController *, BOOL, NSError *) = ^(UIPrintInteractionController *printController, BOOL completed, NSError *error) { if (!completed & error) { NSLog(@"Printing could not complete because of error: %@", error); } }; if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { [pic presentFromBarButtonItem:sender animated:YES completionHandler:completionHandler]; } else { [pic presentAnimated:YES completionHandler:completionHandler]; }}

  • (IBAction)printContent:(id)sender {
    UIPrintInteractionController *pic = [UIPrintInteractionController sharedPrintController];
    pic.delegate = self;

    UIPrintInfo *printInfo = [UIPrintInfo printInfo];
    printInfo.outputType = UIPrintInfoOutputGeneral;
    printInfo.jobName = self.documentName;
    pic.printInfo = printInfo;

    UIMarkupTextPrintFormatter *htmlFormatter = [[UIMarkupTextPrintFormatter alloc]
    initWithMarkupText:self.htmlString];
    htmlFormatter.startPage = 0;
    htmlFormatter.contentInsets = UIEdgeInsetsMake(72.0, 72.0, 72.0, 72.0); // 1 inch margins
    pic.printFormatter = htmlFormatter;
    pic.showsPageRange = YES;

    void (^completionHandler)(UIPrintInteractionController *, BOOL, NSError *) =
    ^(UIPrintInteractionController *printController, BOOL completed, NSError *error) {
    if (!completed & error) {
    NSLog(@"Printing could not complete because of error: %@", error);
    }
    };
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
    [pic presentFromBarButtonItem:sender animated:YES completionHandler:completionHandler];
    } else {
    [pic presentAnimated:YES completionHandler:completionHandler];
    }
    }

将UIWebView 界面上显示的内容打印出来。

  • (void)printWebPage:(id)sender { UIPrintInteractionController *controller = [UIPrintInteractionController sharedPrintController]; void (^completionHandler)(UIPrintInteractionController *, BOOL, NSError *) = ^(UIPrintInteractionController *printController, BOOL completed, NSError *error) { if(!completed & error){ NSLog(@"FAILED! due to error in domain %@ with error code %u", error.domain, error.code); } }; UIPrintInfo *printInfo = [UIPrintInfo printInfo]; printInfo.outputType = UIPrintInfoOutputGeneral; printInfo.jobName = [urlField text]; printInfo.duplex = UIPrintInfoDuplexLongEdge; controller.printInfo = printInfo; controller.showsPageRange = YES; UIViewPrintFormatter *viewFormatter = [self.myWebView viewPrintFormatter]; viewFormatter.startPage = 0; controller.printFormatter = viewFormatter; if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { [controller presentFromBarButtonItem:printButton animated:YES completionHandler:completionHandler]; }else [controller presentAnimated:YES completionHandler:completionHandler];}
  • (void)printWebPage:(id)sender {
    UIPrintInteractionController *controller = [UIPrintInteractionController sharedPrintController];
    void (^completionHandler)(UIPrintInteractionController *, BOOL, NSError *) =
    ^(UIPrintInteractionController *printController, BOOL completed, NSError *error) {
    if(!completed & error){
    NSLog(@"FAILED! due to error in domain %@ with error code %u",
    error.domain, error.code);
    }
    };
    UIPrintInfo *printInfo = [UIPrintInfo printInfo];
    printInfo.outputType = UIPrintInfoOutputGeneral;
    printInfo.jobName = [urlField text];
    printInfo.duplex = UIPrintInfoDuplexLongEdge;
    controller.printInfo = printInfo;
    controller.showsPageRange = YES;

    UIViewPrintFormatter *viewFormatter = [self.myWebView viewPrintFormatter];
    viewFormatter.startPage = 0;
    controller.printFormatter = viewFormatter;

    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
    [controller presentFromBarButtonItem:printButton animated:YES completionHandler:completionHandler];
    }else
    [controller presentAnimated:YES completionHandler:completionHandler];
    }

10, Using a Page Renderer(页渲染器)
这部分内容是最复杂的了, 感觉不怎么用,暂且不深究了, 大家如果项目需要, 自己看文档吧。
总结
到这里,我学习到的 AirPrint的主要技术点已经和大家分享完了。基本可以搞定大部分的需求。 如果那里说错了, 非常欢迎大家能给提出。 另外刚开始写技术博客, 经验不足, 希望大家多提宝贵意见。

via:http://ios.jobbole.com/85020/

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容