前言:AirPrint技术存在已经有了很长的时间,但是对于通常实现来说,每次打印都需要用户在客户端点击选择打印机并确认打印,流程上很不方便。所幸的是apple在iOS8更新了此技术,使其可以支持iOS设备上的无交互后台打印。本文介绍了无交互打印的流程、原理和相关实现,并贴出源代码。

关于AirPrint

AirPrint 是可以让应用软件通过 Apple 的无驱动程序打印体系结构,创建无损打印输出的 Apple 技术。所有支持打印的 iOS 内建 app 均使用 AirPrint。App Store 上使用 iOS 打印系统的 App 也使用 AirPrint。官方 AirPrint 打印机和服务器经过 Apple 许可和认证。(以上文字来自百度百科)
简单说来,airPrint就是苹果定义的一种相对通用的规范或者说标准,满足这种规范的打印机就可以直接连接iOS设备进行打印(无需安装驱动)。而对于客户端来说,只需要调用苹果airPrint的相关API就可以实现连接airPrint打印机的打印,而无需集成各个厂商的sdk,大大方便的编程实现。

AirPrint打印简单实现(iOS8以前的解决方案)

主要代码如下:

- (IBAction)airPrint:(id)sender {
    UIPrintInteractionController *controller = [UIPrintInteractionController sharedPrintController];
    if(!controller){
        NSLog(@"Couldn't get shared UIPrintInteractionController!");
        return;
    }

    /* Set this object as delegate so you can  use the printInteractionController:cutLengthForPaper: delegate */
    controller.delegate = self;

    /************************* Set Print Info ************************/
    UIPrintInfo *printInfo = [UIPrintInfo printInfo];

    /* Four types of UIPrintInfoOutputType you can assign to, and Paper Size Selection will be shown in the AirPrint View,
     those Paper Sizes to be shown also depends on what kind of OutputType you selected , and the locale of your iDevice */
    printInfo.outputType = UIPrintInfoOutputPhoto;

    /* Use landscape orientation for a banner so the text  print along the long side of the paper. */
    printInfo.orientation = UIPrintInfoOrientationPortrait; // UIPrintInfoOrientationPortrait or UIPrintInfoOrientationLandscape

    printInfo.jobName = @"AirPrintWechatSize";
    controller.printInfo = printInfo;

    /******* Set Image to Print ***/
    UIImage *printImage = [UIImage imageNamed:@"7.jpg"];
    controller.printingItem = printImage;

    /************************* Print ************************/
    /* Set up a completion handler block.  If the print job has an error before spooling, this is where it's handled. */
    void (^completionHandler)(UIPrintInteractionController *, BOOL, NSError *) = ^(UIPrintInteractionController *printController, BOOL completed, NSError *error) {
        if(completed && error)
            NSLog( @"Printing failed due to error in domain %@ with error code %lu. Localized description: %@, and failure reason: %@", error.domain, (long)error.code, error.localizedDescription, error.localizedFailureReason );
    };

    if([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) 
    {
        //iPad
        [controller presentFromRect:self.view.frame inView:self.view animated:YES completionHandler:completionHandler];
    }
    else
    {
        [controller presentAnimated:YES completionHandler:completionHandler];
    }

}

iOS8以前实现的步骤和缺陷

这里主要步骤如下:
1.获取UIPrintInteractionController
2.设置Print Info
3.设置printingItem
4.设置打印回调
5.弹出UIPrintInteractionController
这里的缺陷在于我们每次打印都需要弹出这个UIPrintInteractionController,在其中进行打印机的选择并确认打印。但是很多情况下,我们希望这个过程能够在后台执行,我们的程序可以更智能,交互体验更棒。

首先是选择并保存打印机信息的代码:

  UIPrinterPickerController *pickerController =[UIPrinterPickerController printerPickerControllerWithInitiallySelectedPrinter:nil];

    CGRect rect;
    UIInterfaceOrientation currentOrientation = [UIApplication sharedApplication].statusBarOrientation;
    rect = CGRectMake(320, 130, 0, 0);
    [pickerController presentFromRect:rect inView:self.view animated:YES completionHandler:^(UIPrinterPickerController *controller, BOOL userDidSelect, NSError *err){
        if (userDidSelect)
        {
        // save the urlString and Printer name, do your UI interactions
            self.printerName.text = controller.selectedPrinter.displayName;
            self.submitButton.enabled = YES;

            GSignInConfig.airPrinterUrlStr = controller.selectedPrinter.URL.absoluteString;
            GSignInConfig.airPrinterName = controller.selectedPrinter.displayName;
            DDLogInfo(@"Selected printer:%@", controller.selectedPrinter.displayName);
        }
    }];

UIPrinterPickerController需要iOS 8+;其设计理念是通过一次用户交互将打印机相关信息从iOS系统传递到客户端,客户端后续可以用这些信息来进行打印。这里最关键的信息是controller.selectedPrinter.URL.absoluteString,有了它我们就可以找到打印机了(前提是打印机和iOS设备的网络连接情况没有变化)。GSignInConfig是我自己实现的配置持久化接口,可以简单理解成userdefault,这里持久化了打印机的absoluteString和displayName。

[
[UIPrinter printerWithURL:[NSURL URLWithString:printerUrlStr]] contactPrinter:^(BOOL available)
         {
             if (available)
             {
                 DDLogInfo(@"AIRPRINTER AVAILABLE");
             }
             else
             {
                 DDLogInfo(@"AIRPRINTER NOT AVAILABLE");
             }
         }];

上面的代码实现了打印机连接状态的后台检查;这里的printerUrlStr就是此前获取并保存的absoluteUrl。通过它我们就可以构建出一个UIPrinter对象了。这个步骤需要在实际打印操作前完成。

- (void)startAirPrintWithImage:(UIImage *)image
{
    /************************* Set Print Info ************************/
    UIPrintInfo *printInfo = [UIPrintInfo printInfo];
    printInfo.outputType = UIPrintInfoOutputGeneral;
    printInfo.orientation = UIPrintInfoOrientationPortrait;
    printInfo.jobName = @"CoolVisitAirPrint";

    self.airPrinterController.printInfo = printInfo;
    self.airPrinterController.printingItem = image;
    self.airPrinterController.delegate = self;

    /************************* Print ************************/
    /* Set up a completion handler block.  If the print job has an error before spooling, this is where it's handled. */
    void (^completionHandler)(UIPrintInteractionController *, BOOL, NSError *) = ^(UIPrintInteractionController *printController, BOOL completed, NSError *error) {
        if(completed && error)
            DDLogError(@"Printing failed due to error in domain %@ with error code %lu. Localized description: %@, and failure reason: %@", error.domain, (long)error.code, error.localizedDescription, error.localizedFailureReason);
    };

    UIPrinter *airPrinter = [UIPrinter printerWithURL:[NSURL URLWithString:GSignInConfig.airPrinterUrlStr]];
    [self.airPrinterController printToPrinter:airPrinter completionHandler:completionHandler];
}

在检查完毕后,即可调用上面的代码完成打印。同样的,这里的UIPrinter对象也是由之前的absoluteString构建而成。
打印相关的代理方法见UIPrintInteractionControllerDelegate,这里就不再赘述了,可以用其来控制一些打印中的流程和状态,这个代理方法是跟随UIPrintInteractionController而来,iOS8以前的版本也都可以使用。

参考链接:
airPrint苹果官方参考资料

<完>

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐