├── MMPrinterDemo ├── kfc.gif ├── ViewController.h ├── AppDelegate.h ├── main.m ├── PrinterManager │ ├── MMQRCode.h │ ├── MMSocketManager.h │ ├── MMReceiptManager.h │ ├── IGThermalSupport.h │ ├── MMSocketManager.m │ ├── MMPrinterManager.h │ ├── MMQRCode.m │ ├── MMPrinterManager.m │ ├── MMReceiptManager.m │ ├── IGThermalSupport.m │ └── AsyncSocket.h ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── Info.plist ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── AppDelegate.m └── ViewController.m ├── README.md ├── MMPrinterDemo.xcodeproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ │ ├── Mike.xcuserdatad │ │ └── UserInterfaceState.xcuserstate │ │ └── MikeZhao.xcuserdatad │ │ └── UserInterfaceState.xcuserstate ├── xcuserdata │ ├── Mike.xcuserdatad │ │ └── xcschemes │ │ │ ├── xcschememanagement.plist │ │ │ └── MMPrinterDemo.xcscheme │ └── MikeZhao.xcuserdatad │ │ └── xcschemes │ │ ├── xcschememanagement.plist │ │ └── MMPrinterDemo.xcscheme └── project.pbxproj ├── MMPrinterDemoTests ├── Info.plist └── MMPrinterDemoTests.m └── MMPrinterDemoUITests ├── Info.plist └── MMPrinterDemoUITests.m /MMPrinterDemo/kfc.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/songxiaam/MMPrinterDemo/HEAD/MMPrinterDemo/kfc.gif -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MMPrinterDemo 2 | 使用socket连接小票打印机打印小票的Demo,使用ESC/POS指令. 3 | http://www.jianshu.com/p/52bdd2e41b11 4 | 这是我在简书写的使用方法,可以参考下 5 | -------------------------------------------------------------------------------- /MMPrinterDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /MMPrinterDemo.xcodeproj/project.xcworkspace/xcuserdata/Mike.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/songxiaam/MMPrinterDemo/HEAD/MMPrinterDemo.xcodeproj/project.xcworkspace/xcuserdata/Mike.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /MMPrinterDemo.xcodeproj/project.xcworkspace/xcuserdata/MikeZhao.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/songxiaam/MMPrinterDemo/HEAD/MMPrinterDemo.xcodeproj/project.xcworkspace/xcuserdata/MikeZhao.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /MMPrinterDemo/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // MMPrinterDemo 4 | // 5 | // Created by Zhaomike on 16/3/17. 6 | // Copyright © 2016年 mikezhao. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /MMPrinterDemo/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // MMPrinterDemo 4 | // 5 | // Created by Zhaomike on 16/3/17. 6 | // Copyright © 2016年 mikezhao. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /MMPrinterDemo/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // MMPrinterDemo 4 | // 5 | // Created by Zhaomike on 16/3/17. 6 | // Copyright © 2016年 mikezhao. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /MMPrinterDemo/PrinterManager/MMQRCode.h: -------------------------------------------------------------------------------- 1 | // 2 | // MMQRCode.h 3 | // RevoSysAuto 4 | // 5 | // Created by Zhaomike on 16/1/20. 6 | // Copyright © 2016年 leyutech. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface MMQRCode : NSObject 13 | 14 | + (UIImage *)qrCodeWithString:(NSString *)string logoName:(NSString *)name size:(CGFloat)width; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /MMPrinterDemo/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /MMPrinterDemoTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /MMPrinterDemoUITests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /MMPrinterDemo.xcodeproj/xcuserdata/Mike.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | MMPrinterDemo.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | C8066CC61C9A4A1600DE1D90 16 | 17 | primary 18 | 19 | 20 | C8066CDF1C9A4A1600DE1D90 21 | 22 | primary 23 | 24 | 25 | C8066CEA1C9A4A1600DE1D90 26 | 27 | primary 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /MMPrinterDemo.xcodeproj/xcuserdata/MikeZhao.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | MMPrinterDemo.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | C8066CC61C9A4A1600DE1D90 16 | 17 | primary 18 | 19 | 20 | C8066CDF1C9A4A1600DE1D90 21 | 22 | primary 23 | 24 | 25 | C8066CEA1C9A4A1600DE1D90 26 | 27 | primary 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /MMPrinterDemo/PrinterManager/MMSocketManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // MMSocketManager.h 3 | // MMPrinterDemo 4 | // 5 | // Created by Zhaomike on 16/3/17. 6 | // Copyright © 2016年 mikezhao. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AsyncSocket.h" 11 | 12 | @interface MMSocketManager : NSObject 13 | 14 | //打印 15 | @property (strong, nonatomic) void (^blockPrintData)(); 16 | //检查缓存数据(连接断开时,检查缓存数据) 17 | //可能遇到的问题 18 | //打印机只能同时连接一个socket 19 | //1.wifi打印机:当wifi打印机一直连接着一个socket01,这时如果另一个socket02想要连接时,会将socket01会断开,连上socket02,可以正常打印 20 | //2.有线打印机:当wifi打印机一直连接着一个socket01,这时如果另一个socket02想要连接时,会将socket01不会断开,因此socket02不能正常打印 21 | //对于问题2,将timeout设置为10,连接10秒连不上断开,检查数据,如果有数据,再次连接.,同时设置[sock disconnectAfterWriting];(写入数据后连接断开) 22 | @property (strong, nonatomic) void (^blockCheckData)(); 23 | 24 | //连接打印机 25 | - (void)socketConnectToPrint:(NSString *)host port:(UInt16)port timeout:(NSTimeInterval)timeout; 26 | //发送数据 27 | - (void)socketWriteData:(NSData *)data; 28 | //检查是否连接 29 | - (BOOL)socketIsConnect; 30 | //断开连接 31 | - (void)socketDisconnectSocket; 32 | 33 | @end 34 | -------------------------------------------------------------------------------- /MMPrinterDemoTests/MMPrinterDemoTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // MMPrinterDemoTests.m 3 | // MMPrinterDemoTests 4 | // 5 | // Created by Zhaomike on 16/3/17. 6 | // Copyright © 2016年 mikezhao. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface MMPrinterDemoTests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation MMPrinterDemoTests 16 | 17 | - (void)setUp { 18 | [super setUp]; 19 | // Put setup code here. This method is called before the invocation of each test method in the class. 20 | } 21 | 22 | - (void)tearDown { 23 | // Put teardown code here. This method is called after the invocation of each test method in the class. 24 | [super tearDown]; 25 | } 26 | 27 | - (void)testExample { 28 | // This is an example of a functional test case. 29 | // Use XCTAssert and related functions to verify your tests produce the correct results. 30 | } 31 | 32 | - (void)testPerformanceExample { 33 | // This is an example of a performance test case. 34 | [self measureBlock:^{ 35 | // Put the code you want to measure the time of here. 36 | }]; 37 | } 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /MMPrinterDemo/PrinterManager/MMReceiptManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // MMReceiptManager.h 3 | // MMPrinterDemo 4 | // 5 | // Created by Zhaomike on 16/3/18. 6 | // Copyright © 2016年 mikezhao. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "MMPrinterManager.h" 11 | #import "MMSocketManager.h" 12 | 13 | @interface MMReceiptManager : NSObject 14 | 15 | @property (nonatomic, strong) MMSocketManager *asynaSocket; 16 | @property (nonatomic, strong) MMPrinterManager *printerManager; 17 | 18 | - (instancetype)initWithHost:(NSString *)host port:(UInt16)port timeout:(NSTimeInterval)timeout; 19 | - (void)connectWithHost:(NSString *)host port:(UInt16)port timeout:(NSTimeInterval)timeout; 20 | //基础设置 21 | - (void)basicSetting; 22 | //清空缓存数据 23 | - (void)clearData; 24 | //写入单行文字 25 | - (void)writeData_title:(NSString *)title Scale:(kCharScale)scale Type:(kAlignmentType)type; 26 | //写入多行文字 27 | - (void)writeData_items:(NSArray *)items; 28 | //打印图片 29 | - (void)writeData_image:(UIImage *)image alignment:(kAlignmentType)alignment maxWidth:(CGFloat)maxWidth; 30 | //条目,菜单,有间隔 31 | - (void)writeData_content:(NSArray *)items; 32 | //打印分割线 33 | - (void)writeData_line; 34 | //打开钱箱 35 | - (void)openCashDrawer; 36 | //打印小票 37 | - (void)printReceipt; 38 | @end 39 | -------------------------------------------------------------------------------- /MMPrinterDemo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /MMPrinterDemoUITests/MMPrinterDemoUITests.m: -------------------------------------------------------------------------------- 1 | // 2 | // MMPrinterDemoUITests.m 3 | // MMPrinterDemoUITests 4 | // 5 | // Created by Zhaomike on 16/3/17. 6 | // Copyright © 2016年 mikezhao. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface MMPrinterDemoUITests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation MMPrinterDemoUITests 16 | 17 | - (void)setUp { 18 | [super setUp]; 19 | 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | 22 | // In UI tests it is usually best to stop immediately when a failure occurs. 23 | self.continueAfterFailure = NO; 24 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method. 25 | [[[XCUIApplication alloc] init] launch]; 26 | 27 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. 28 | } 29 | 30 | - (void)tearDown { 31 | // Put teardown code here. This method is called after the invocation of each test method in the class. 32 | [super tearDown]; 33 | } 34 | 35 | - (void)testExample { 36 | // Use recording to get started writing UI tests. 37 | // Use XCTAssert and related functions to verify your tests produce the correct results. 38 | } 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /MMPrinterDemo/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /MMPrinterDemo/PrinterManager/IGThermalSupport.h: -------------------------------------------------------------------------------- 1 | // 2 | // IGThermalSupport.h 3 | // 4 | // This class is released in the MIT license. 5 | // Created by Chris Chan in 12 Aug 2012. 6 | // Copyright (c) 2012 IGPSD Ltd. 7 | // 8 | // https://github.com/moming2k/ThermalPrinterKit.git 9 | // 10 | // Version 1.0.3 11 | 12 | #import 13 | #import 14 | 15 | typedef enum { 16 | ALPHA = 0, 17 | BLUE = 1, 18 | GREEN = 2, 19 | RED = 3 20 | } PIXELS; 21 | 22 | @interface IGThermalSupport : NSObject 23 | 24 | + (NSData *) imageToThermalData:(UIImage*)image; 25 | + (CGContextRef) newBitmapRGBA8ContextFromImage:(CGImageRef) image; 26 | + (NSData *)cutLine; 27 | + (NSData *)feedLines:(int)lines; 28 | + (UIImage*)mergeImage:(UIImage*)first withShopLogo:(UIImage*)shopLogo withColorType:(NSString*)colorType withNumber:(int)number; 29 | + (UIImage*)mergeImageQrcode:(UIImage*)first withShopLogo:(UIImage*)shopLogo withImageInfo:(UIImage*)imageInfo withQRCode:(NSString*)qrcode withColorType:(NSString*)colorType withNumber:(int)number withShopName:(NSString*)shopName withShopInfo:(NSString*)shopInfo withTicketTime:(NSString*)ticketTime withTicketDetail:(NSString*)ticketDetail; 30 | + (UIImage*)mergeImageStore:(UIImage*)first withImageInfo:(UIImage*)imageInfo withQRCode:(NSString*)qrcode withNumber:(int)number withShopName:(NSString*)shopName withShopInfo:(NSString*)shopInfo withTicketTime:(NSString*)ticketTime withTicketDetail:(NSString*)ticketDetail; 31 | + (UIImage*)drawText:(NSString*)text inImage:(UIImage*)image atPoint:(CGPoint)point withFont:(UIFont *)font; 32 | + (UIImage*)mergeImage2:(UIImage*)first withQRCode:(NSString*)qrcode withNumber:(int)number; 33 | + (UIImage *) receiptImage:(UIImage*)image withNumber:(int)number; 34 | + (CGFloat)widthOfString:(NSString *)string withFont:(UIFont *)font; 35 | 36 | @end 37 | -------------------------------------------------------------------------------- /MMPrinterDemo/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // MMPrinterDemo 4 | // 5 | // Created by Zhaomike on 16/3/17. 6 | // Copyright © 2016年 mikezhao. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 19 | // Override point for customization after application launch. 20 | return YES; 21 | } 22 | 23 | - (void)applicationWillResignActive:(UIApplication *)application { 24 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 25 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 26 | } 27 | 28 | - (void)applicationDidEnterBackground:(UIApplication *)application { 29 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 30 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 31 | } 32 | 33 | - (void)applicationWillEnterForeground:(UIApplication *)application { 34 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 35 | } 36 | 37 | - (void)applicationDidBecomeActive:(UIApplication *)application { 38 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 39 | } 40 | 41 | - (void)applicationWillTerminate:(UIApplication *)application { 42 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 43 | } 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /MMPrinterDemo/PrinterManager/MMSocketManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // MMSocketManager.m 3 | // MMPrinterDemo 4 | // 5 | // Created by Zhaomike on 16/3/17. 6 | // Copyright © 2016年 mikezhao. All rights reserved. 7 | // 8 | 9 | #import "MMSocketManager.h" 10 | 11 | @interface MMSocketManager() 12 | 13 | @property (nonatomic, strong) AsyncSocket *asyncSocket; 14 | 15 | @end 16 | 17 | @implementation MMSocketManager 18 | 19 | -(instancetype)init { 20 | if (self = [super init]) { 21 | self.asyncSocket = [[AsyncSocket alloc] initWithDelegate:self]; 22 | [self.asyncSocket setRunLoopModes:@[NSRunLoopCommonModes]]; 23 | } 24 | return self; 25 | } 26 | 27 | //连接打印机 28 | -(void)socketConnectToPrint:(NSString *)host port:(UInt16)port timeout:(NSTimeInterval)timeout { 29 | NSError *error = nil; 30 | [self.asyncSocket connectToHost:host onPort:port withTimeout:timeout error:&error]; 31 | } 32 | //检查连接状态 33 | -(BOOL)socketIsConnect 34 | { 35 | BOOL isConn = [self.asyncSocket isConnected]; 36 | if (isConn) { 37 | NSLog(@"host=%@\nport=%hu\nlocalHost=%@\nlocalPort=%hu",self.asyncSocket.connectedHost,self.asyncSocket.connectedPort,self.asyncSocket.localHost,self.asyncSocket.localPort); 38 | } 39 | return isConn; 40 | } 41 | //发送数据 42 | - (void)socketWriteData:(NSData *)data { 43 | [self.asyncSocket writeData:data withTimeout:-1 tag:0]; 44 | } 45 | //手动断开连接 46 | - (void)socketDisconnectSocket { 47 | [self.asyncSocket disconnect]; 48 | } 49 | 50 | #pragma mark - Delegate 51 | - (void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port { 52 | if (_blockCheckData) { 53 | _blockPrintData(); 54 | } 55 | [sock disconnectAfterWriting]; 56 | } 57 | 58 | - (void)onSocketDidDisconnect:(AsyncSocket *)sock { 59 | if (_blockCheckData) { 60 | _blockCheckData(); 61 | } 62 | } 63 | // 64 | - (BOOL)onSocketWillConnect:(AsyncSocket *)sock { 65 | return YES; 66 | } 67 | 68 | - (void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag { 69 | NSLog(@"读取完成"); 70 | } 71 | 72 | - (void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag { 73 | NSLog(@"写入完成"); 74 | } 75 | 76 | - (void)onSocket:(AsyncSocket *)sock willDisconnectWithError:(NSError *)err { 77 | NSLog(@"即将断开"); 78 | } 79 | @end 80 | -------------------------------------------------------------------------------- /MMPrinterDemo/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // MMPrinterDemo 4 | // 5 | // Created by Zhaomike on 16/3/17. 6 | // Copyright © 2016年 mikezhao. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import "MMReceiptManager.h" 11 | #import "MMQRCode.h" 12 | 13 | @interface ViewController () 14 | 15 | @property (strong, nonatomic) MMReceiptManager *manager; 16 | 17 | @property (weak, nonatomic) IBOutlet UITextField *ipTextField; 18 | @property (weak, nonatomic) IBOutlet UITextField *portTextField; 19 | 20 | 21 | @end 22 | 23 | @implementation ViewController 24 | 25 | - (void)viewDidLoad { 26 | [super viewDidLoad]; 27 | // Do any additional setup after loading the view, typically from a nib. 28 | } 29 | 30 | - (IBAction)printReceipt:(id)sender { 31 | 32 | NSString *host = @"192.168.1.241"; 33 | UInt16 port = 9100; 34 | // NSString *host = _ipTextField.text; 35 | // UInt16 port = (UInt16)[_portTextField.text integerValue]; 36 | NSTimeInterval timeout = 10; 37 | MMReceiptManager *manager = [[MMReceiptManager alloc] initWithHost:host port:port timeout:timeout]; 38 | [manager basicSetting]; 39 | [manager writeData_title:@"肯德基" Scale:scale_2 Type:MiddleAlignment]; 40 | [manager writeData_items:@[@"收银员:001", @"交易时间:2016-03-17", @"交易号:201603170001"]]; 41 | [manager writeData_line]; 42 | [manager writeData_content:@[@{@"key01":@"名称", @"key02":@"单价", @"key03":@"数量", @"key04":@"总价"}]]; 43 | [manager writeData_line]; 44 | [manager writeData_content:@[@{@"key01":@"汉堡", @"key02":@"10.00", @"key03":@"2", @"key04":@"20.00"}, @{@"key01":@"炸鸡", @"key02":@"8.00", @"key03":@"1", @"key04":@"8.00"}]]; 45 | [manager writeData_line]; 46 | [manager writeData_items:@[@"支付方式:现金", @"应收:28.00", @"实际:30.00", @"找零:2.00"]]; 47 | UIImage *qrImage = [MMQRCode qrCodeWithString:@"www.google.cn" logoName:@"kfc.gif" size:400]; 48 | [manager writeData_image:qrImage alignment:MiddleAlignment maxWidth:400]; 49 | [manager openCashDrawer]; 50 | [manager printReceipt]; 51 | 52 | } 53 | 54 | 55 | 56 | - (void)didReceiveMemoryWarning { 57 | [super didReceiveMemoryWarning]; 58 | // Dispose of any resources that can be recreated. 59 | } 60 | 61 | @end 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /MMPrinterDemo/PrinterManager/MMPrinterManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // MMPrinterManager.h 3 | // MMPrinterDemo 4 | // 5 | // Created by Zhaomike on 16/3/17. 6 | // Copyright © 2016年 mikezhao. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | //横向或纵向移动单位 13 | #define DotSpace 0.1 14 | @interface MMPrinterManager : NSObject 15 | 16 | //对齐方式 17 | typedef enum :UInt8 { 18 | LeftAlignment = 0x30, 19 | MiddleAlignment = 0x31, 20 | RightAlignment = 0x32, 21 | }kAlignmentType; 22 | 23 | //页模式下打印区域方向 24 | typedef enum { 25 | LeftToRight = 0x30, 26 | DownToUP = 0x31, 27 | RightToLeft = 0x32, 28 | UpToDown = 0x33, 29 | }kPrintOrientation; 30 | 31 | //字符放大倍数 32 | typedef enum: UInt8 { 33 | scale_1 = 0x00, 34 | scale_2 = 0x11, 35 | scale_3 = 0x22, 36 | scale_4 = 0x33, 37 | scale_5 = 0x44, 38 | scale_6 = 0x55, 39 | scale_7 = 0x66, 40 | scale_8 = 0x77, 41 | }kCharScale; 42 | 43 | //选择字体 44 | typedef enum: UInt8 { 45 | standardFont = 0x30, 46 | smallerFont = 0x31, 47 | }kCharFont; 48 | 49 | //切纸模式 50 | typedef enum :UInt8 { 51 | fullCut = 0x30, 52 | halfCut = 0x31, 53 | feedPaperHalfCut = 0x42, 54 | }kCutPaperModel; 55 | 56 | //打印数据(文字图片信息) 57 | @property (nonatomic, strong) NSMutableData *sendData; 58 | 59 | //0.录入文字 60 | -(void)printAddText:(NSString *)text; 61 | 62 | //2.打印并换行 63 | -(void)printAndGotoNextLine; 64 | 65 | //11.设置绝对打印位置 66 | -(void)printAbsolutePosition:(NSInteger)location; 67 | 68 | //14.选择位图模式 69 | - (void)printBitmapModel:(UIImage *)bitmap; 70 | 71 | //16.设置默认行间距(约3.75mm) 72 | - (void)printDefaultLineSpace; 73 | 74 | //20.初始化打印机 75 | - (void)printInitialize; 76 | 77 | //24.打印并走纸 78 | - (void)printPrintAndFeedPaper:(CGFloat)space; 79 | 80 | //26.设置字号 81 | - (void)printSelectFont:(kCharFont)size; 82 | 83 | //28.设置成标准模式 84 | - (void)printSetStanderModel; 85 | 86 | //33.设置对齐方式 87 | -(void)printAlignmentType:(kAlignmentType)type; 88 | 89 | //38.产生钱箱控制脉冲 90 | -(void)printOpenCashDrawer; 91 | 92 | //43.选择字符大小 93 | -(void)printCharSize:(kCharScale)scale; 94 | 95 | //51.设置左边距 96 | - (void)printLeftMargin:(CGFloat)left; 97 | 98 | //52.设置横向和纵向移动单位 99 | - (void)printDotDistanceW:(CGFloat)w h:(CGFloat)h; 100 | 101 | //53.选择切纸模式并切纸 102 | -(void)printCutPaper:(kCutPaperModel)model Num:(UInt8)n; 103 | 104 | //54.设置每行打印宽度 105 | - (void)printAreaWidth:(CGFloat)width; 106 | 107 | @end 108 | -------------------------------------------------------------------------------- /MMPrinterDemo/PrinterManager/MMQRCode.m: -------------------------------------------------------------------------------- 1 | // 2 | // MMQRCode.m 3 | // RevoSysAuto 4 | // 5 | // Created by Zhaomike on 16/1/20. 6 | // Copyright © 2016年 leyutech. All rights reserved. 7 | // 8 | 9 | #import "MMQRCode.h" 10 | 11 | @implementation MMQRCode 12 | 13 | + (UIImage *)qrCodeWithString:(NSString *)string logoName:(NSString *)name size:(CGFloat)width { 14 | if (string) { 15 | NSData *strData = [string dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:NO]; 16 | //创建二维码滤镜 17 | CIFilter *qrFilter = [CIFilter filterWithName:@"CIQRCodeGenerator"]; 18 | [qrFilter setValue:strData forKey:@"inputMessage"]; 19 | [qrFilter setValue:@"H" forKey:@"inputCorrectionLevel"]; 20 | CIImage *qrImage = qrFilter.outputImage; 21 | //颜色滤镜 22 | CIFilter *colorFilter = [CIFilter filterWithName:@"CIFalseColor"]; 23 | [colorFilter setDefaults]; 24 | [colorFilter setValue:qrImage forKey:kCIInputImageKey]; 25 | [colorFilter setValue:[CIColor colorWithRed:0 green:0 blue:0] forKey:@"inputColor0"]; 26 | [colorFilter setValue:[CIColor colorWithRed:0.3 green:0.8 blue:0.2] forKey:@"inputColor1"]; 27 | CIImage *colorImage = colorFilter.outputImage; 28 | //返回二维码 29 | CGFloat scale = width/31; 30 | UIImage *codeImage = [UIImage imageWithCIImage:[colorImage imageByApplyingTransform:CGAffineTransformMakeScale(scale, scale)]]; 31 | //定制logo 32 | if (name) { 33 | UIImage *logo = [UIImage imageNamed:name]; 34 | //二维码rect 35 | CGRect rect = CGRectMake(0, 0, codeImage.size.width, codeImage.size.height); 36 | UIGraphicsBeginImageContext(rect.size); 37 | [codeImage drawInRect:rect]; 38 | //icon尺寸,UIBezierPath 39 | CGSize logoSize = CGSizeMake(rect.size.width*0.2, rect.size.height*0.2); 40 | CGFloat x = CGRectGetMidX(rect) - logoSize.width*0.5; 41 | CGFloat y = CGRectGetMidY(rect) - logoSize.height*0.5; 42 | CGRect logoFrame = CGRectMake(x, y, logoSize.width, logoSize.height); 43 | [[UIBezierPath bezierPathWithRoundedRect:logoFrame cornerRadius:10] addClip]; 44 | 45 | [logo drawInRect:logoFrame]; 46 | UIImage *resultImage = UIGraphicsGetImageFromCurrentImageContext(); 47 | UIGraphicsEndImageContext(); 48 | return resultImage; 49 | } 50 | return codeImage; 51 | } 52 | return nil; 53 | } 54 | 55 | @end 56 | -------------------------------------------------------------------------------- /MMPrinterDemo/PrinterManager/MMPrinterManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // MMPrinterManager.m 3 | // MMPrinterDemo 4 | // 5 | // Created by Zhaomike on 16/3/17. 6 | // Copyright © 2016年 mikezhao. All rights reserved. 7 | // 8 | 9 | #import "MMPrinterManager.h" 10 | #import "IGThermalSupport.h" 11 | 12 | @implementation MMPrinterManager 13 | 14 | -(instancetype)init { 15 | if (self = [super init]) { 16 | _sendData = [NSMutableData dataWithCapacity:0]; 17 | } 18 | return self; 19 | } 20 | 21 | - (void)addBytesCommand:(const void *)command Length:(NSUInteger)length { 22 | [self.sendData appendBytes:command length:length]; 23 | } 24 | 25 | //0.录入文字 26 | -(void)printAddText:(NSString *)text { 27 | NSStringEncoding enc = CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000); 28 | NSData *data = [text dataUsingEncoding:enc]; 29 | NSUInteger size = data.length; 30 | void *textdata = malloc(size); 31 | [data getBytes:textdata length:size]; 32 | [self addBytesCommand:textdata Length:size]; 33 | free(textdata); 34 | } 35 | 36 | //2.打印并换行 37 | -(void)printAndGotoNextLine { 38 | unsigned char data[] = {0x0A}; 39 | [self addBytesCommand:data Length:1]; 40 | } 41 | 42 | //11.设置绝对打印位置 43 | -(void)printAbsolutePosition:(NSInteger)location { 44 | unsigned char nL = location % 256; 45 | unsigned char nH = location / 256; 46 | unsigned char data[] = {0x1B, 0x24, nL, nH}; 47 | [self addBytesCommand:data Length:4]; 48 | } 49 | 50 | //14.选择位图模式 51 | - (void)printBitmapModel:(UIImage *)bitmap { 52 | NSData *data = [IGThermalSupport imageToThermalData:bitmap]; 53 | NSUInteger size = data.length; 54 | void *picSize = malloc(size); 55 | [data getBytes:picSize length:size]; 56 | [self addBytesCommand:picSize Length:size]; 57 | free(picSize); 58 | } 59 | 60 | //16.设置默认行间距(约3.75mm) 61 | - (void)printDefaultLineSpace { 62 | unsigned char data[] = {0x1B,0x32}; 63 | [self addBytesCommand:data Length:2]; 64 | } 65 | 66 | //20.初始化打印机 67 | - (void)printInitialize { 68 | unsigned char data[] = {0x1B, 0x40}; 69 | [self addBytesCommand:data Length:2]; 70 | } 71 | 72 | //24.打印并走纸 73 | - (void)printPrintAndFeedPaper:(CGFloat)space { 74 | unsigned char n = (UInt8)(space/DotSpace); 75 | unsigned char data[] = {0x1B, 0x4A, n}; 76 | [self addBytesCommand:data Length:3]; 77 | } 78 | 79 | //26.设置字号 80 | - (void)printSelectFont:(kCharFont)size { 81 | unsigned char data[] = {0x1B,0x4D,size}; 82 | [self addBytesCommand:data Length:3]; 83 | } 84 | 85 | //28.设置成标准模式 86 | - (void)printSetStanderModel { 87 | unsigned char data[] = {0x1B,0x53}; 88 | [self addBytesCommand:data Length:2]; 89 | } 90 | 91 | //33.设置对齐方式 92 | -(void)printAlignmentType:(kAlignmentType)type { 93 | unsigned char data[] = {0x1B,0x61,type}; 94 | [self addBytesCommand:data Length:3]; 95 | } 96 | 97 | //38.产生钱箱控制脉冲 98 | -(void)printOpenCashDrawer { 99 | unsigned char data[5] = {0x1B, 0x70, 0x00, 0x80, 0xFF}; 100 | [self addBytesCommand:data Length:5]; 101 | } 102 | 103 | //43.选择字符大小 104 | -(void)printCharSize:(kCharScale)scale { 105 | unsigned char data[] = {0x0A,0x1D,0x21,scale}; 106 | [self addBytesCommand:data Length:4]; 107 | } 108 | 109 | //51.设置左边距 110 | - (void)printLeftMargin:(CGFloat)left { 111 | NSInteger t = left/DotSpace; 112 | unsigned char nL = t%256; 113 | unsigned char nH = t/256; 114 | unsigned char data[] = {0x1D,0x4C,nL,nH}; 115 | [self addBytesCommand:data Length:4]; 116 | } 117 | 118 | //52.设置横向和纵向移动单位 119 | - (void)printDotDistanceW:(CGFloat)w h:(CGFloat)h { 120 | unsigned char width = (unsigned char)(25.4/w); 121 | unsigned char height = (unsigned char)(25.4/h); 122 | unsigned char data[] = {0x1D,0x50,width,height}; 123 | [self addBytesCommand:data Length:4]; 124 | } 125 | 126 | //53.选择切纸模式并切纸 127 | -(void)printCutPaper:(kCutPaperModel)model Num:(UInt8)n { 128 | unsigned char m = 0; 129 | if (model == feedPaperHalfCut) { 130 | m = n; 131 | } 132 | unsigned char data[] = {0x1D, 0x56, model, m}; 133 | [self addBytesCommand:data Length:4]; 134 | } 135 | 136 | //54.设置每行打印宽度 137 | - (void)printAreaWidth:(CGFloat)width { 138 | unsigned char nL = (int)(width / DotSpace) % 256; 139 | unsigned char nH = (int)(width / DotSpace) / 256; 140 | unsigned char data[] = {0x1D,0x57,nL,nH}; 141 | [self addBytesCommand:data Length:4]; 142 | } 143 | 144 | @end 145 | -------------------------------------------------------------------------------- /MMPrinterDemo.xcodeproj/xcuserdata/Mike.xcuserdatad/xcschemes/MMPrinterDemo.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 43 | 49 | 50 | 51 | 52 | 53 | 59 | 60 | 61 | 62 | 63 | 64 | 74 | 76 | 82 | 83 | 84 | 85 | 86 | 87 | 93 | 95 | 101 | 102 | 103 | 104 | 106 | 107 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /MMPrinterDemo.xcodeproj/xcuserdata/MikeZhao.xcuserdatad/xcschemes/MMPrinterDemo.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 43 | 49 | 50 | 51 | 52 | 53 | 59 | 60 | 61 | 62 | 63 | 64 | 74 | 76 | 82 | 83 | 84 | 85 | 86 | 87 | 93 | 95 | 101 | 102 | 103 | 104 | 106 | 107 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /MMPrinterDemo/PrinterManager/MMReceiptManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // MMReceiptManager.m 3 | // MMPrinterDemo 4 | // 5 | // Created by Zhaomike on 16/3/18. 6 | // Copyright © 2016年 mikezhao. All rights reserved. 7 | // 8 | 9 | //小票管理类,根据需求自行定制 10 | #import "MMReceiptManager.h" 11 | 12 | @implementation MMReceiptManager 13 | 14 | - (instancetype)initWithHost:(NSString *)host port:(UInt16)port timeout:(NSTimeInterval)timeout { 15 | if (self = [super init]) 16 | { 17 | [self.asynaSocket socketConnectToPrint:host port:port timeout:timeout]; 18 | } 19 | return self; 20 | } 21 | - (void)connectWithHost:(NSString *)host port:(UInt16)port timeout:(NSTimeInterval)timeout { 22 | [self.asynaSocket socketConnectToPrint:host port:port timeout:timeout]; 23 | } 24 | - (MMSocketManager *)asynaSocket { 25 | if (!_asynaSocket) { 26 | _asynaSocket = [[MMSocketManager alloc] init]; 27 | } 28 | return _asynaSocket; 29 | } 30 | - (MMPrinterManager *)printerManager { 31 | if (!_printerManager) { 32 | _printerManager = [[MMPrinterManager alloc] init]; 33 | } 34 | return _printerManager; 35 | } 36 | //基础设置 37 | - (void)basicSetting { 38 | [self.printerManager printInitialize]; 39 | [self.printerManager printSetStanderModel]; 40 | [self.printerManager printDotDistanceW:DotSpace h:DotSpace]; 41 | // [self.printerManager printLeftMargin:5.0]; 42 | [self.printerManager printDefaultLineSpace]; 43 | // [self.printerManager printAreaWidth:70]; 44 | [self.printerManager printSelectFont:standardFont]; 45 | } 46 | //清空缓存数据 47 | - (void)clearData { 48 | self.printerManager.sendData.length = 0; 49 | } 50 | //写入单行文字 51 | - (void)writeData_title:(NSString *)title Scale:(kCharScale)scale Type:(kAlignmentType)type { 52 | [_printerManager printCharSize:scale]; 53 | [_printerManager printAlignmentType:type]; 54 | [_printerManager printAddText:title]; 55 | [_printerManager printAndGotoNextLine]; 56 | } 57 | //写入多行文字 58 | - (void)writeData_items:(NSArray *)items { 59 | [self.printerManager printCharSize:scale_1]; 60 | [_printerManager printAlignmentType:LeftAlignment]; 61 | for (NSString *item in items) { 62 | [_printerManager printAddText:item]; 63 | [_printerManager printAndGotoNextLine]; 64 | } 65 | } 66 | //打印图片 67 | - (void)writeData_image:(UIImage *)image alignment:(kAlignmentType)alignment maxWidth:(CGFloat)maxWidth { 68 | [self.printerManager printAlignmentType:alignment]; 69 | // UIImage *inImage = image; 70 | CGFloat width = image.size.width; 71 | if (width > maxWidth) { 72 | CGFloat height = image.size.height; 73 | CGFloat maxHeight = maxWidth * height / width; 74 | image = [self createCurrentImage:image width:maxWidth height:maxHeight]; 75 | } 76 | [self.printerManager printBitmapModel:image]; 77 | [self.printerManager printAndGotoNextLine]; 78 | } 79 | // 缩放图片 80 | - (UIImage *)createCurrentImage:(UIImage *)inImage width:(CGFloat)width height:(CGFloat)height { 81 | CGSize size = CGSizeMake(width, height); 82 | UIGraphicsBeginImageContext(size); 83 | [inImage drawInRect:CGRectMake(0, 0, width, height)]; 84 | UIImage *resultImage = UIGraphicsGetImageFromCurrentImageContext(); 85 | UIGraphicsEndImageContext(); 86 | return resultImage; 87 | } 88 | 89 | //func createCurrentImage(inImage:UIImage, width:CGFloat, height:CGFloat)->UIImage{ 90 | // // let w = CGFloat(width) 91 | // // let h = CGFloat(height) 92 | // let size = CGSizeMake(width, height) 93 | // UIGraphicsBeginImageContext(size) 94 | // inImage.drawInRect(CGRectMake(0, 0, width, height)) 95 | // let image = UIGraphicsGetImageFromCurrentImageContext() 96 | // UIGraphicsEndImageContext() 97 | // return image 98 | //} 99 | 100 | //条目,菜单,有间隔,如: 101 | // 炸鸡排 2 12.50 25.00 102 | - (void)writeData_content:(NSArray *)items { 103 | [self.printerManager printCharSize:scale_1]; 104 | [_printerManager printAlignmentType:LeftAlignment]; 105 | for (NSDictionary *dict in items) { 106 | [self writeData_spaceItem:dict]; 107 | } 108 | } 109 | - (void)writeData_spaceItem:(NSDictionary *)item { 110 | [_printerManager printAddText:[item objectForKey:@"key01"]]; 111 | [_printerManager printAbsolutePosition:350]; 112 | [_printerManager printAddText:[item objectForKey:@"key02"]]; 113 | [_printerManager printAbsolutePosition:500]; 114 | [_printerManager printAddText:[item objectForKey:@"key03"]]; 115 | [_printerManager printAbsolutePosition:640]; 116 | [_printerManager printAddText:[item objectForKey:@"key04"]]; 117 | [_printerManager printAndGotoNextLine]; 118 | } 119 | //打印分割线 120 | - (void)writeData_line { 121 | [self.printerManager printAlignmentType:MiddleAlignment]; 122 | [self.printerManager printAddText:@"------------------------------------------"]; 123 | [self.printerManager printAndGotoNextLine]; 124 | } 125 | //打开钱箱 126 | - (void)openCashDrawer { 127 | [self.printerManager printOpenCashDrawer]; 128 | } 129 | //打印小票 130 | - (void)printReceipt { 131 | [self.printerManager printCutPaper:feedPaperHalfCut Num:12]; 132 | [_asynaSocket socketWriteData:[self.printerManager sendData]]; 133 | } 134 | 135 | @end 136 | -------------------------------------------------------------------------------- /MMPrinterDemo/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 25 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /MMPrinterDemo/PrinterManager/IGThermalSupport.m: -------------------------------------------------------------------------------- 1 | // 2 | // IGThermalSupport.m 3 | // 4 | // This class is released in the MIT license. 5 | // Created by Chris Chan in 12 Aug 2012. 6 | // Copyright (c) 2012 IGPSD Ltd. 7 | // 8 | // https://github.com/moming2k/ThermalPrinterKit.git 9 | // 10 | // Version 1.0.3 11 | 12 | #import "IGThermalSupport.h" 13 | //#import "FileManager.h" 14 | //#import "Barcode.h" 15 | 16 | @implementation IGThermalSupport 17 | 18 | + (NSData *) imageToThermalData:(UIImage*)image 19 | { 20 | CGImageRef imageRef = image.CGImage; 21 | 22 | // Create a bitmap context to draw the uiimage into 23 | CGContextRef context = [self newBitmapRGBA8ContextFromImage:imageRef]; 24 | 25 | if(!context) { 26 | return NULL; 27 | } 28 | 29 | size_t width = CGImageGetWidth(imageRef); 30 | size_t height = CGImageGetHeight(imageRef); 31 | 32 | CGRect rect = CGRectMake(0, 0, width, height); 33 | 34 | // Draw image into the context to get the raw image data 35 | CGContextDrawImage(context, rect, imageRef); 36 | 37 | // Get a pointer to the data 38 | uint32_t *bitmapData = (uint32_t *)CGBitmapContextGetData(context); 39 | 40 | if(bitmapData) { 41 | 42 | uint8_t *m_imageData = (uint8_t *) malloc(width * height/8 + 8*height/8); 43 | memset(m_imageData, 0, width * height/8 + 8*height/8); 44 | int result_index = 0; 45 | 46 | for(int y = 0; (y + 24) < height; ) { 47 | m_imageData[result_index++] = 27; 48 | m_imageData[result_index++] = 51; 49 | m_imageData[result_index++] = 0; 50 | 51 | m_imageData[result_index++] = 27; 52 | m_imageData[result_index++] = 42; 53 | m_imageData[result_index++] = 33; 54 | 55 | m_imageData[result_index++] = width%256; 56 | m_imageData[result_index++] = width/256; 57 | for(int x = 0; x < width; x++) { 58 | int value = 0; 59 | for (int temp_y = 0 ; temp_y < 8; ++temp_y) 60 | { 61 | uint8_t *rgbaPixel = (uint8_t *) &bitmapData[(y+temp_y) * width + x]; 62 | uint32_t gray = 0.3 * rgbaPixel[RED] + 0.59 * rgbaPixel[GREEN] + 0.11 * rgbaPixel[BLUE]; 63 | 64 | if (gray < 127) 65 | { 66 | value += 1<<(7-temp_y)&255; 67 | } 68 | 69 | } 70 | m_imageData[result_index++] = value; 71 | 72 | value = 0; 73 | for (int temp_y = 8 ; temp_y < 16; ++temp_y) 74 | { 75 | uint8_t *rgbaPixel = (uint8_t *) &bitmapData[(y+temp_y) * width + x]; 76 | uint32_t gray = 0.3 * rgbaPixel[RED] + 0.59 * rgbaPixel[GREEN] + 0.11 * rgbaPixel[BLUE]; 77 | 78 | if (gray < 127) 79 | { 80 | value += 1<<(7-temp_y%8)&255; 81 | } 82 | 83 | } 84 | m_imageData[result_index++] = value; 85 | 86 | value = 0; 87 | for (int temp_y = 16 ; temp_y < 24; ++temp_y) 88 | { 89 | uint8_t *rgbaPixel = (uint8_t *) &bitmapData[(y+temp_y) * width + x]; 90 | uint32_t gray = 0.3 * rgbaPixel[RED] + 0.59 * rgbaPixel[GREEN] + 0.11 * rgbaPixel[BLUE]; 91 | 92 | if (gray < 127) 93 | { 94 | value += 1<<(7-temp_y%8)&255; 95 | } 96 | 97 | } 98 | m_imageData[result_index++] = value; 99 | } 100 | m_imageData[result_index++] = 13; 101 | m_imageData[result_index++] = 10; 102 | y += 24; 103 | } 104 | 105 | NSMutableData *data = [[NSMutableData alloc] initWithCapacity:0]; 106 | [data appendBytes:m_imageData length:result_index]; 107 | 108 | free(bitmapData); 109 | return data; 110 | 111 | } else { 112 | NSLog(@"Error getting bitmap pixel data\n"); 113 | } 114 | 115 | CGContextRelease(context); 116 | 117 | return nil ; 118 | } 119 | 120 | 121 | + (CGContextRef) newBitmapRGBA8ContextFromImage:(CGImageRef) image { 122 | CGContextRef context = NULL; 123 | CGColorSpaceRef colorSpace; 124 | uint32_t *bitmapData; 125 | 126 | size_t bitsPerPixel = 32; 127 | size_t bitsPerComponent = 8; 128 | size_t bytesPerPixel = bitsPerPixel / bitsPerComponent; 129 | 130 | size_t width = CGImageGetWidth(image); 131 | size_t height = CGImageGetHeight(image); 132 | 133 | size_t bytesPerRow = width * bytesPerPixel; 134 | size_t bufferLength = bytesPerRow * height; 135 | 136 | colorSpace = CGColorSpaceCreateDeviceRGB(); 137 | 138 | if(!colorSpace) { 139 | NSLog(@"Error allocating color space RGB\n"); 140 | return NULL; 141 | } 142 | 143 | // Allocate memory for image data 144 | bitmapData = (uint32_t *)malloc(bufferLength); 145 | 146 | if(!bitmapData) { 147 | NSLog(@"Error allocating memory for bitmap\n"); 148 | CGColorSpaceRelease(colorSpace); 149 | return NULL; 150 | } 151 | 152 | //Create bitmap context 153 | 154 | context = CGBitmapContextCreate(bitmapData, 155 | width, 156 | height, 157 | bitsPerComponent, 158 | bytesPerRow, 159 | colorSpace, 160 | kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedLast); // RGBA 161 | if(!context) { 162 | free(bitmapData); 163 | NSLog(@"Bitmap context not created"); 164 | } 165 | 166 | CGColorSpaceRelease(colorSpace); 167 | 168 | return context; 169 | } 170 | 171 | + (UIImage*)mergeImage:(UIImage*)first withShopLogo:(UIImage*)shopLogo withColorType:(NSString*)colorType withNumber:(int)number 172 | { 173 | // get size of the first image 174 | CGImageRef firstImageRef = first.CGImage; 175 | CGFloat firstWidth = CGImageGetWidth(firstImageRef); 176 | CGFloat firstHeight = CGImageGetHeight(firstImageRef); 177 | 178 | // get size of the logo image 179 | CGImageRef shopLogoImageRef = shopLogo.CGImage; 180 | CGFloat shopLogoWidth = CGImageGetWidth(shopLogoImageRef); 181 | CGFloat shopLogoHeight = CGImageGetHeight(shopLogoImageRef); 182 | 183 | // get size of the number image 184 | int first_num = number/100; 185 | int secord_num = (number - first_num*100)/10; 186 | int third_num = number - first_num*100 - secord_num*10; 187 | 188 | UIImage *ticket_type = [UIImage imageNamed:[NSString stringWithFormat:@"char-%@",colorType]]; 189 | UIImage *first_number = [UIImage imageNamed:[NSString stringWithFormat:@"char-%i",first_num]]; 190 | UIImage *secord_number = [UIImage imageNamed:[NSString stringWithFormat:@"char-%i",secord_num]]; 191 | UIImage *third_number = [UIImage imageNamed:[NSString stringWithFormat:@"char-%i",third_num]]; 192 | 193 | CGImageRef secondImageRef = first_number.CGImage; 194 | CGFloat secondWidth = CGImageGetWidth(secondImageRef); 195 | CGFloat secondHeight = CGImageGetHeight(secondImageRef); 196 | 197 | // build merged size 198 | CGSize mergedSize = CGSizeMake(530, firstHeight + shopLogoHeight); 199 | // CGSize mergedSize = CGSizeMake(MAX(firstWidth, shopLogoWidth), MAX(firstHeight, shopLogoHeight)); 200 | 201 | // capture image context ref 202 | UIGraphicsBeginImageContext(mergedSize); 203 | 204 | //Draw images onto the context 205 | [first drawInRect:CGRectMake(0, 0, firstWidth, firstHeight)]; 206 | [shopLogo drawInRect:CGRectMake(0, firstHeight, shopLogoWidth, shopLogoHeight)]; 207 | [ticket_type drawInRect:CGRectMake(220, 280, secondWidth, secondHeight)]; 208 | [first_number drawInRect:CGRectMake(280, 280, secondWidth, secondHeight)]; 209 | [secord_number drawInRect:CGRectMake(340, 280, secondWidth, secondHeight)]; 210 | [third_number drawInRect:CGRectMake(400, 280, secondWidth, secondHeight)]; 211 | 212 | // assign context to new UIImage 213 | UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext(); 214 | 215 | // end context 216 | UIGraphicsEndImageContext(); 217 | 218 | return newImage; 219 | } 220 | 221 | /* 222 | + (UIImage*)mergeImageQrcode:(UIImage*)first withShopLogo:(UIImage*)shopLogo withImageInfo:(UIImage*)imageInfo withQRCode:(NSString*)qrcode withColorType:(NSString*)colorType withNumber:(int)number withShopName:(NSString*)shopName withShopInfo:(NSString*)shopInfo withTicketTime:(NSString*)ticketTime withTicketDetail:(NSString*)ticketDetail 223 | { 224 | // get size of the first image 225 | CGImageRef firstImageRef = first.CGImage; 226 | CGFloat firstWidth = CGImageGetWidth(firstImageRef); 227 | CGFloat firstHeight = CGImageGetHeight(firstImageRef); 228 | 229 | // get size of the logo image 230 | CGImageRef shopLogoImageRef = shopLogo.CGImage; 231 | CGFloat shopLogoWidth = CGImageGetWidth(shopLogoImageRef); 232 | CGFloat shopLogoHeight = CGImageGetHeight(shopLogoImageRef); 233 | 234 | // get size of the number image 235 | int first_num = number/100; 236 | int secord_num = (number - first_num*100)/10; 237 | int third_num = number - first_num*100 - secord_num*10; 238 | 239 | UIImage *ticket_bg = [UIImage imageNamed:[NSString stringWithFormat:@"ticket_white_bg"]]; 240 | UIImage *ticket_type = [UIImage imageNamed:[NSString stringWithFormat:@"char-%@",colorType]]; 241 | UIImage *first_number = [UIImage imageNamed:[NSString stringWithFormat:@"char-%i",first_num]]; 242 | UIImage *secord_number = [UIImage imageNamed:[NSString stringWithFormat:@"char-%i",secord_num]]; 243 | UIImage *third_number = [UIImage imageNamed:[NSString stringWithFormat:@"char-%i",third_num]]; 244 | 245 | CGImageRef secondImageRef = first_number.CGImage; 246 | CGFloat secondWidth = CGImageGetWidth(secondImageRef); 247 | CGFloat secondHeight = CGImageGetHeight(secondImageRef); 248 | 249 | // get size of the info image 250 | CGImageRef infoImageRef = imageInfo.CGImage; 251 | CGFloat infoWidth = CGImageGetWidth(infoImageRef); 252 | CGFloat infoHeight = CGImageGetHeight(infoImageRef); 253 | CGFloat info_y = firstHeight + shopLogoHeight + 100; 254 | 255 | // gen qr code 256 | Barcode *barcode = [[Barcode alloc] init]; 257 | [barcode setupQRCode:qrcode]; 258 | UIImage *image_qrcode = barcode.qRBarcode; 259 | CGFloat qrcode_y = info_y + infoHeight + 20; 260 | 261 | // build merged size 262 | CGSize mergedSize = CGSizeMake(520, qrcode_y + 200); 263 | // CGSize mergedSize = CGSizeMake(MAX(firstWidth, secondWidth), MAX(firstHeight, secondHeight)); 264 | 265 | // capture image context ref 266 | UIGraphicsBeginImageContext(mergedSize); 267 | 268 | //Draw images onto the context 269 | [ticket_bg drawInRect:CGRectMake(0, 0, firstWidth, qrcode_y + 200)]; 270 | [first drawInRect:CGRectMake(0, 0, firstWidth, firstHeight)]; 271 | [shopLogo drawInRect:CGRectMake(0, firstHeight, shopLogoWidth, shopLogoHeight)]; 272 | [ticket_type drawInRect:CGRectMake(220, 280, secondWidth, secondHeight)]; 273 | [first_number drawInRect:CGRectMake(280, 280, secondWidth, secondHeight)]; 274 | [secord_number drawInRect:CGRectMake(340, 280, secondWidth, secondHeight)]; 275 | [third_number drawInRect:CGRectMake(400, 280, secondWidth, secondHeight)]; 276 | [imageInfo drawInRect:CGRectMake(0, info_y, infoWidth, infoHeight)]; 277 | [image_qrcode drawInRect:CGRectMake(25, qrcode_y, 200, 200)]; 278 | 279 | 280 | // assign context to new UIImage 281 | UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext(); 282 | 283 | UIFont *font = [UIFont boldSystemFontOfSize:18]; 284 | CGFloat textwidth = [IGThermalSupport widthOfString:shopName withFont:font]; 285 | UIImage *newImageWithText = [IGThermalSupport drawText:shopName inImage:newImage atPoint:CGPointMake((530 - textwidth)/2, firstHeight + shopLogoHeight + 20) withFont:(UIFont *)font]; 286 | textwidth = [IGThermalSupport widthOfString:shopInfo withFont:font]; 287 | UIImage *newImageWithText1 = [IGThermalSupport drawText:shopInfo inImage:newImageWithText atPoint:CGPointMake((530 - textwidth)/2, firstHeight + shopLogoHeight + 40) withFont:(UIFont *)font]; 288 | textwidth = [IGThermalSupport widthOfString:ticketTime withFont:font]; 289 | UIImage *newImageWithText2 = [IGThermalSupport drawText:ticketTime inImage:newImageWithText1 atPoint:CGPointMake((530 - textwidth)/2, firstHeight + shopLogoHeight + 60) withFont:(UIFont *)font]; 290 | textwidth = [IGThermalSupport widthOfString:ticketDetail withFont:font]; 291 | UIImage *newImageWithText3 = [IGThermalSupport drawText:ticketDetail inImage:newImageWithText2 atPoint:CGPointMake(230, qrcode_y + 10) withFont:(UIFont *)font]; 292 | 293 | // end context 294 | UIGraphicsEndImageContext(); 295 | 296 | return newImageWithText3; 297 | } 298 | */ 299 | /* 300 | + (UIImage*)mergeImageStore:(UIImage*)first withImageInfo:(UIImage*)imageInfo withQRCode:(NSString*)qrcode withNumber:(int)number withShopName:(NSString*)shopName withShopInfo:(NSString*)shopInfo withTicketTime:(NSString*)ticketTime withTicketDetail:(NSString*)ticketDetail 301 | { 302 | // get size of the first image 303 | CGImageRef firstImageRef = first.CGImage; 304 | CGFloat firstWidth = CGImageGetWidth(firstImageRef); 305 | CGFloat firstHeight = CGImageGetHeight(firstImageRef); 306 | 307 | // get size of the number image 308 | int first_num = number/100; 309 | int secord_num = (number - first_num*100)/10; 310 | int third_num = number - first_num*100 - secord_num*10; 311 | 312 | UIImage *ticket_bg = [UIImage imageNamed:[NSString stringWithFormat:@"ticket_white_bg"]]; 313 | UIImage *first_number = [UIImage imageNamed:[NSString stringWithFormat:@"ticket_%i",first_num]]; 314 | UIImage *secord_number = [UIImage imageNamed:[NSString stringWithFormat:@"ticket_%i",secord_num]]; 315 | UIImage *third_number = [UIImage imageNamed:[NSString stringWithFormat:@"ticket_%i",third_num]]; 316 | 317 | CGImageRef secondImageRef = first_number.CGImage; 318 | CGFloat secondWidth = CGImageGetWidth(secondImageRef); 319 | CGFloat secondHeight = CGImageGetHeight(secondImageRef); 320 | 321 | // get size of the info image 322 | CGImageRef infoImageRef = imageInfo.CGImage; 323 | CGFloat infoWidth = CGImageGetWidth(infoImageRef); 324 | CGFloat infoHeight = CGImageGetHeight(infoImageRef); 325 | CGFloat info_y = firstHeight + 100; 326 | 327 | // gen qr code 328 | Barcode *barcode = [[Barcode alloc] init]; 329 | [barcode setupQRCode:qrcode]; 330 | UIImage *image_qrcode = barcode.qRBarcode; 331 | CGFloat qrcode_y = info_y + infoHeight + 20; 332 | 333 | // build merged size 334 | CGSize mergedSize = CGSizeMake(520, qrcode_y + 200); 335 | // CGSize mergedSize = CGSizeMake(MAX(firstWidth, secondWidth), MAX(firstHeight, secondHeight)); 336 | 337 | // capture image context ref 338 | UIGraphicsBeginImageContext(mergedSize); 339 | 340 | //Draw images onto the context 341 | [ticket_bg drawInRect:CGRectMake(0, 0, firstWidth, qrcode_y + 200)]; 342 | [first drawInRect:CGRectMake(0, 0, firstWidth, firstHeight)]; 343 | [first_number drawInRect:CGRectMake(270, 230, secondWidth, secondHeight)]; 344 | [secord_number drawInRect:CGRectMake(340, 230, secondWidth, secondHeight)]; 345 | [third_number drawInRect:CGRectMake(410, 230, secondWidth, secondHeight)]; 346 | [imageInfo drawInRect:CGRectMake(0, info_y, infoWidth, infoHeight)]; 347 | [image_qrcode drawInRect:CGRectMake(25, qrcode_y, 200, 200)]; 348 | 349 | 350 | // assign context to new UIImage 351 | UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext(); 352 | 353 | UIFont *font = [UIFont boldSystemFontOfSize:18]; 354 | CGFloat textwidth = [IGThermalSupport widthOfString:shopName withFont:font]; 355 | UIImage *newImageWithText = [IGThermalSupport drawText:shopName inImage:newImage atPoint:CGPointMake((530 - textwidth)/2, firstHeight + 20) withFont:(UIFont *)font]; 356 | textwidth = [IGThermalSupport widthOfString:shopInfo withFont:font]; 357 | UIImage *newImageWithText1 = [IGThermalSupport drawText:shopInfo inImage:newImageWithText atPoint:CGPointMake((530 - textwidth)/2, firstHeight + 40) withFont:(UIFont *)font]; 358 | textwidth = [IGThermalSupport widthOfString:ticketTime withFont:font]; 359 | UIImage *newImageWithText2 = [IGThermalSupport drawText:ticketTime inImage:newImageWithText1 atPoint:CGPointMake((530 - textwidth)/2, firstHeight + 60) withFont:(UIFont *)font]; 360 | textwidth = [IGThermalSupport widthOfString:ticketDetail withFont:font]; 361 | UIImage *newImageWithText3 = [IGThermalSupport drawText:ticketDetail inImage:newImageWithText2 atPoint:CGPointMake(230, qrcode_y + 10) withFont:(UIFont *)font]; 362 | 363 | // end context 364 | UIGraphicsEndImageContext(); 365 | 366 | return newImageWithText3; 367 | } 368 | */ 369 | 370 | + (CGFloat)widthOfString:(NSString *)string withFont:(UIFont *)font 371 | { 372 | NSDictionary *attributes = [NSDictionary dictionaryWithObjectsAndKeys:font, NSFontAttributeName, nil]; 373 | return [[[NSAttributedString alloc] initWithString:string attributes:attributes] size].width; 374 | } 375 | 376 | + (UIImage*)drawText:(NSString*)text inImage:(UIImage*)image atPoint:(CGPoint)point withFont:(UIFont *)font 377 | { 378 | UIGraphicsBeginImageContext(image.size); 379 | [image drawInRect:CGRectMake(0,0,image.size.width,image.size.height)]; 380 | CGRect rect = CGRectMake(point.x, point.y, image.size.width, image.size.height); 381 | [[UIColor blackColor] set]; 382 | [text drawInRect:CGRectIntegral(rect) withAttributes:@{NSFontAttributeName:font}]; 383 | UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext(); 384 | UIGraphicsEndImageContext(); 385 | 386 | return newImage; 387 | } 388 | 389 | + (UIImage*)mergeImage2:(UIImage*)first withNumber:(int)number 390 | { 391 | // get size of the first image 392 | 393 | CGImageRef firstImageRef = first.CGImage; 394 | CGFloat firstWidth = CGImageGetWidth(firstImageRef); 395 | CGFloat firstHeight = CGImageGetHeight(firstImageRef); 396 | 397 | // get size of the second image 398 | 399 | int first_num = number/100; 400 | int secord_num = (number - first_num*100)/10; 401 | int third_num = number - first_num*100 - secord_num*10; 402 | 403 | UIImage *first_number = [UIImage imageNamed:[NSString stringWithFormat:@"ticket_%i",first_num]]; 404 | UIImage *secord_number = [UIImage imageNamed:[NSString stringWithFormat:@"ticket_%i",secord_num]]; 405 | UIImage *third_number = [UIImage imageNamed:[NSString stringWithFormat:@"ticket_%i",third_num]]; 406 | 407 | CGImageRef secondImageRef = first_number.CGImage ; 408 | CGFloat secondWidth = CGImageGetWidth(secondImageRef); 409 | CGFloat secondHeight = CGImageGetHeight(secondImageRef); 410 | 411 | // build merged size 412 | CGSize mergedSize = CGSizeMake(MAX(firstWidth, secondWidth), MAX(firstHeight, secondHeight)); 413 | 414 | // capture image context ref 415 | UIGraphicsBeginImageContext(mergedSize); 416 | 417 | //Draw images onto the context 418 | [first drawInRect:CGRectMake(0, 0, firstWidth, firstHeight)]; 419 | [first_number drawInRect:CGRectMake(270, 230, secondWidth, secondHeight)]; 420 | [secord_number drawInRect:CGRectMake(340, 230, secondWidth, secondHeight)]; 421 | [third_number drawInRect:CGRectMake(410, 230, secondWidth, secondHeight)]; 422 | 423 | // assign context to new UIImage 424 | UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext(); 425 | 426 | // end context 427 | UIGraphicsEndImageContext(); 428 | 429 | return newImage; 430 | } 431 | 432 | + (NSData *)cutLine 433 | { 434 | int index = 0; 435 | NSMutableData *data = [[NSMutableData alloc] initWithCapacity:0]; 436 | uint8_t *m_imageData = (uint8_t *) malloc(4); 437 | m_imageData[index++] = 29; 438 | m_imageData[index++] = 86; 439 | m_imageData[index++] = 65; 440 | m_imageData[index++] = 10; 441 | [data appendBytes:m_imageData length:4]; 442 | return data; 443 | 444 | } 445 | 446 | + (NSData *)feedLines:(int)lines 447 | { 448 | int index = 0; 449 | NSMutableData *data = [[NSMutableData alloc] initWithCapacity:0]; 450 | uint8_t *m_imageData = (uint8_t *) malloc(3); 451 | m_imageData[index++] = 27; 452 | m_imageData[index++] = 100; 453 | m_imageData[index++] = lines; 454 | [data appendBytes:m_imageData length:3]; 455 | return data; 456 | } 457 | 458 | + (UIImage *) receiptImage:(UIImage*)image withNumber:(int)number 459 | { 460 | UIImage *result = image; 461 | return result; 462 | 463 | // UIImage *bottomImage = [UIImage imageNamed:@"bottom.png"]; //background image 464 | // UIImage *image = [UIImage imageNamed:@"top.png"]; //foreground image 465 | // 466 | // CGSize newSize = CGSizeMake(width, height); 467 | // UIGraphicsBeginImageContext( newSize ); 468 | // 469 | // // Use existing opacity as is 470 | // [bottomImage drawInRect:CGRectMake(0,0,newSize.width,newSize.height)]; 471 | // 472 | // // Apply supplied opacity if applicable 473 | // [image drawInRect:CGRectMake(0,0,newSize.width,newSize.height) blendMode:kCGBlendModeNormal alpha:0.8]; 474 | // 475 | // UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext(); 476 | // 477 | // UIGraphicsEndImageContext(); 478 | } 479 | 480 | 481 | @end 482 | -------------------------------------------------------------------------------- /MMPrinterDemo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 279DD8971C9DA71B00CEA250 /* IGThermalSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = 279DD8961C9DA71B00CEA250 /* IGThermalSupport.m */; }; 11 | 279DD89A1C9DA97900CEA250 /* MMQRCode.m in Sources */ = {isa = PBXBuildFile; fileRef = 279DD8991C9DA97900CEA250 /* MMQRCode.m */; }; 12 | 279DD89E1C9DC05F00CEA250 /* kfc.gif in Resources */ = {isa = PBXBuildFile; fileRef = 279DD89D1C9DC05F00CEA250 /* kfc.gif */; }; 13 | C8066CCC1C9A4A1600DE1D90 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = C8066CCB1C9A4A1600DE1D90 /* main.m */; }; 14 | C8066CCF1C9A4A1600DE1D90 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = C8066CCE1C9A4A1600DE1D90 /* AppDelegate.m */; }; 15 | C8066CD21C9A4A1600DE1D90 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C8066CD11C9A4A1600DE1D90 /* ViewController.m */; }; 16 | C8066CD51C9A4A1600DE1D90 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C8066CD31C9A4A1600DE1D90 /* Main.storyboard */; }; 17 | C8066CD71C9A4A1600DE1D90 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C8066CD61C9A4A1600DE1D90 /* Assets.xcassets */; }; 18 | C8066CDA1C9A4A1600DE1D90 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C8066CD81C9A4A1600DE1D90 /* LaunchScreen.storyboard */; }; 19 | C8066CE51C9A4A1600DE1D90 /* MMPrinterDemoTests.m in Sources */ = {isa = PBXBuildFile; fileRef = C8066CE41C9A4A1600DE1D90 /* MMPrinterDemoTests.m */; }; 20 | C8066CF01C9A4A1600DE1D90 /* MMPrinterDemoUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = C8066CEF1C9A4A1600DE1D90 /* MMPrinterDemoUITests.m */; }; 21 | C8066D001C9A4B4300DE1D90 /* AsyncSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = C8066CFF1C9A4B4300DE1D90 /* AsyncSocket.m */; }; 22 | C8066D061C9A4BBF00DE1D90 /* MMPrinterManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C8066D051C9A4BBF00DE1D90 /* MMPrinterManager.m */; }; 23 | C8066D091C9A86D600DE1D90 /* MMSocketManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C8066D081C9A86D600DE1D90 /* MMSocketManager.m */; }; 24 | C8AD0B7F1C9BA33100FFFAB6 /* MMReceiptManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C8AD0B7E1C9BA33100FFFAB6 /* MMReceiptManager.m */; }; 25 | /* End PBXBuildFile section */ 26 | 27 | /* Begin PBXContainerItemProxy section */ 28 | C8066CE11C9A4A1600DE1D90 /* PBXContainerItemProxy */ = { 29 | isa = PBXContainerItemProxy; 30 | containerPortal = C8066CBF1C9A4A1600DE1D90 /* Project object */; 31 | proxyType = 1; 32 | remoteGlobalIDString = C8066CC61C9A4A1600DE1D90; 33 | remoteInfo = MMPrinterDemo; 34 | }; 35 | C8066CEC1C9A4A1600DE1D90 /* PBXContainerItemProxy */ = { 36 | isa = PBXContainerItemProxy; 37 | containerPortal = C8066CBF1C9A4A1600DE1D90 /* Project object */; 38 | proxyType = 1; 39 | remoteGlobalIDString = C8066CC61C9A4A1600DE1D90; 40 | remoteInfo = MMPrinterDemo; 41 | }; 42 | /* End PBXContainerItemProxy section */ 43 | 44 | /* Begin PBXFileReference section */ 45 | 279DD8951C9DA71B00CEA250 /* IGThermalSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IGThermalSupport.h; sourceTree = ""; }; 46 | 279DD8961C9DA71B00CEA250 /* IGThermalSupport.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IGThermalSupport.m; sourceTree = ""; }; 47 | 279DD8981C9DA97900CEA250 /* MMQRCode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MMQRCode.h; sourceTree = ""; }; 48 | 279DD8991C9DA97900CEA250 /* MMQRCode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MMQRCode.m; sourceTree = ""; }; 49 | 279DD89D1C9DC05F00CEA250 /* kfc.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = kfc.gif; sourceTree = ""; }; 50 | C8066CC71C9A4A1600DE1D90 /* MMPrinterDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MMPrinterDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 51 | C8066CCB1C9A4A1600DE1D90 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 52 | C8066CCD1C9A4A1600DE1D90 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 53 | C8066CCE1C9A4A1600DE1D90 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 54 | C8066CD01C9A4A1600DE1D90 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 55 | C8066CD11C9A4A1600DE1D90 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 56 | C8066CD41C9A4A1600DE1D90 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 57 | C8066CD61C9A4A1600DE1D90 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 58 | C8066CD91C9A4A1600DE1D90 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 59 | C8066CDB1C9A4A1600DE1D90 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 60 | C8066CE01C9A4A1600DE1D90 /* MMPrinterDemoTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MMPrinterDemoTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 61 | C8066CE41C9A4A1600DE1D90 /* MMPrinterDemoTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MMPrinterDemoTests.m; sourceTree = ""; }; 62 | C8066CE61C9A4A1600DE1D90 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 63 | C8066CEB1C9A4A1600DE1D90 /* MMPrinterDemoUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MMPrinterDemoUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 64 | C8066CEF1C9A4A1600DE1D90 /* MMPrinterDemoUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MMPrinterDemoUITests.m; sourceTree = ""; }; 65 | C8066CF11C9A4A1600DE1D90 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 66 | C8066CFE1C9A4B4300DE1D90 /* AsyncSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AsyncSocket.h; sourceTree = ""; }; 67 | C8066CFF1C9A4B4300DE1D90 /* AsyncSocket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AsyncSocket.m; sourceTree = ""; }; 68 | C8066D041C9A4BBF00DE1D90 /* MMPrinterManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MMPrinterManager.h; sourceTree = ""; }; 69 | C8066D051C9A4BBF00DE1D90 /* MMPrinterManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MMPrinterManager.m; sourceTree = ""; }; 70 | C8066D071C9A86D600DE1D90 /* MMSocketManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MMSocketManager.h; sourceTree = ""; }; 71 | C8066D081C9A86D600DE1D90 /* MMSocketManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MMSocketManager.m; sourceTree = ""; }; 72 | C8AD0B7D1C9BA33100FFFAB6 /* MMReceiptManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MMReceiptManager.h; sourceTree = ""; }; 73 | C8AD0B7E1C9BA33100FFFAB6 /* MMReceiptManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MMReceiptManager.m; sourceTree = ""; }; 74 | /* End PBXFileReference section */ 75 | 76 | /* Begin PBXFrameworksBuildPhase section */ 77 | C8066CC41C9A4A1600DE1D90 /* Frameworks */ = { 78 | isa = PBXFrameworksBuildPhase; 79 | buildActionMask = 2147483647; 80 | files = ( 81 | ); 82 | runOnlyForDeploymentPostprocessing = 0; 83 | }; 84 | C8066CDD1C9A4A1600DE1D90 /* Frameworks */ = { 85 | isa = PBXFrameworksBuildPhase; 86 | buildActionMask = 2147483647; 87 | files = ( 88 | ); 89 | runOnlyForDeploymentPostprocessing = 0; 90 | }; 91 | C8066CE81C9A4A1600DE1D90 /* Frameworks */ = { 92 | isa = PBXFrameworksBuildPhase; 93 | buildActionMask = 2147483647; 94 | files = ( 95 | ); 96 | runOnlyForDeploymentPostprocessing = 0; 97 | }; 98 | /* End PBXFrameworksBuildPhase section */ 99 | 100 | /* Begin PBXGroup section */ 101 | C8066CBE1C9A4A1600DE1D90 = { 102 | isa = PBXGroup; 103 | children = ( 104 | C8066CC91C9A4A1600DE1D90 /* MMPrinterDemo */, 105 | C8066CE31C9A4A1600DE1D90 /* MMPrinterDemoTests */, 106 | C8066CEE1C9A4A1600DE1D90 /* MMPrinterDemoUITests */, 107 | C8066CC81C9A4A1600DE1D90 /* Products */, 108 | ); 109 | sourceTree = ""; 110 | }; 111 | C8066CC81C9A4A1600DE1D90 /* Products */ = { 112 | isa = PBXGroup; 113 | children = ( 114 | C8066CC71C9A4A1600DE1D90 /* MMPrinterDemo.app */, 115 | C8066CE01C9A4A1600DE1D90 /* MMPrinterDemoTests.xctest */, 116 | C8066CEB1C9A4A1600DE1D90 /* MMPrinterDemoUITests.xctest */, 117 | ); 118 | name = Products; 119 | sourceTree = ""; 120 | }; 121 | C8066CC91C9A4A1600DE1D90 /* MMPrinterDemo */ = { 122 | isa = PBXGroup; 123 | children = ( 124 | C8066CCD1C9A4A1600DE1D90 /* AppDelegate.h */, 125 | C8066CCE1C9A4A1600DE1D90 /* AppDelegate.m */, 126 | C8066CD01C9A4A1600DE1D90 /* ViewController.h */, 127 | C8066CD11C9A4A1600DE1D90 /* ViewController.m */, 128 | 279DD89D1C9DC05F00CEA250 /* kfc.gif */, 129 | C8066CFD1C9A4A5400DE1D90 /* PrinterManager */, 130 | C8066CD31C9A4A1600DE1D90 /* Main.storyboard */, 131 | C8066CD61C9A4A1600DE1D90 /* Assets.xcassets */, 132 | C8066CD81C9A4A1600DE1D90 /* LaunchScreen.storyboard */, 133 | C8066CDB1C9A4A1600DE1D90 /* Info.plist */, 134 | C8066CCA1C9A4A1600DE1D90 /* Supporting Files */, 135 | ); 136 | path = MMPrinterDemo; 137 | sourceTree = ""; 138 | }; 139 | C8066CCA1C9A4A1600DE1D90 /* Supporting Files */ = { 140 | isa = PBXGroup; 141 | children = ( 142 | C8066CCB1C9A4A1600DE1D90 /* main.m */, 143 | ); 144 | name = "Supporting Files"; 145 | sourceTree = ""; 146 | }; 147 | C8066CE31C9A4A1600DE1D90 /* MMPrinterDemoTests */ = { 148 | isa = PBXGroup; 149 | children = ( 150 | C8066CE41C9A4A1600DE1D90 /* MMPrinterDemoTests.m */, 151 | C8066CE61C9A4A1600DE1D90 /* Info.plist */, 152 | ); 153 | path = MMPrinterDemoTests; 154 | sourceTree = ""; 155 | }; 156 | C8066CEE1C9A4A1600DE1D90 /* MMPrinterDemoUITests */ = { 157 | isa = PBXGroup; 158 | children = ( 159 | C8066CEF1C9A4A1600DE1D90 /* MMPrinterDemoUITests.m */, 160 | C8066CF11C9A4A1600DE1D90 /* Info.plist */, 161 | ); 162 | path = MMPrinterDemoUITests; 163 | sourceTree = ""; 164 | }; 165 | C8066CFD1C9A4A5400DE1D90 /* PrinterManager */ = { 166 | isa = PBXGroup; 167 | children = ( 168 | C8066CFE1C9A4B4300DE1D90 /* AsyncSocket.h */, 169 | C8066CFF1C9A4B4300DE1D90 /* AsyncSocket.m */, 170 | 279DD8951C9DA71B00CEA250 /* IGThermalSupport.h */, 171 | 279DD8961C9DA71B00CEA250 /* IGThermalSupport.m */, 172 | 279DD8981C9DA97900CEA250 /* MMQRCode.h */, 173 | 279DD8991C9DA97900CEA250 /* MMQRCode.m */, 174 | C8066D041C9A4BBF00DE1D90 /* MMPrinterManager.h */, 175 | C8066D051C9A4BBF00DE1D90 /* MMPrinterManager.m */, 176 | C8066D071C9A86D600DE1D90 /* MMSocketManager.h */, 177 | C8066D081C9A86D600DE1D90 /* MMSocketManager.m */, 178 | C8AD0B7D1C9BA33100FFFAB6 /* MMReceiptManager.h */, 179 | C8AD0B7E1C9BA33100FFFAB6 /* MMReceiptManager.m */, 180 | ); 181 | path = PrinterManager; 182 | sourceTree = ""; 183 | }; 184 | /* End PBXGroup section */ 185 | 186 | /* Begin PBXNativeTarget section */ 187 | C8066CC61C9A4A1600DE1D90 /* MMPrinterDemo */ = { 188 | isa = PBXNativeTarget; 189 | buildConfigurationList = C8066CF41C9A4A1600DE1D90 /* Build configuration list for PBXNativeTarget "MMPrinterDemo" */; 190 | buildPhases = ( 191 | C8066CC31C9A4A1600DE1D90 /* Sources */, 192 | C8066CC41C9A4A1600DE1D90 /* Frameworks */, 193 | C8066CC51C9A4A1600DE1D90 /* Resources */, 194 | ); 195 | buildRules = ( 196 | ); 197 | dependencies = ( 198 | ); 199 | name = MMPrinterDemo; 200 | productName = MMPrinterDemo; 201 | productReference = C8066CC71C9A4A1600DE1D90 /* MMPrinterDemo.app */; 202 | productType = "com.apple.product-type.application"; 203 | }; 204 | C8066CDF1C9A4A1600DE1D90 /* MMPrinterDemoTests */ = { 205 | isa = PBXNativeTarget; 206 | buildConfigurationList = C8066CF71C9A4A1600DE1D90 /* Build configuration list for PBXNativeTarget "MMPrinterDemoTests" */; 207 | buildPhases = ( 208 | C8066CDC1C9A4A1600DE1D90 /* Sources */, 209 | C8066CDD1C9A4A1600DE1D90 /* Frameworks */, 210 | C8066CDE1C9A4A1600DE1D90 /* Resources */, 211 | ); 212 | buildRules = ( 213 | ); 214 | dependencies = ( 215 | C8066CE21C9A4A1600DE1D90 /* PBXTargetDependency */, 216 | ); 217 | name = MMPrinterDemoTests; 218 | productName = MMPrinterDemoTests; 219 | productReference = C8066CE01C9A4A1600DE1D90 /* MMPrinterDemoTests.xctest */; 220 | productType = "com.apple.product-type.bundle.unit-test"; 221 | }; 222 | C8066CEA1C9A4A1600DE1D90 /* MMPrinterDemoUITests */ = { 223 | isa = PBXNativeTarget; 224 | buildConfigurationList = C8066CFA1C9A4A1600DE1D90 /* Build configuration list for PBXNativeTarget "MMPrinterDemoUITests" */; 225 | buildPhases = ( 226 | C8066CE71C9A4A1600DE1D90 /* Sources */, 227 | C8066CE81C9A4A1600DE1D90 /* Frameworks */, 228 | C8066CE91C9A4A1600DE1D90 /* Resources */, 229 | ); 230 | buildRules = ( 231 | ); 232 | dependencies = ( 233 | C8066CED1C9A4A1600DE1D90 /* PBXTargetDependency */, 234 | ); 235 | name = MMPrinterDemoUITests; 236 | productName = MMPrinterDemoUITests; 237 | productReference = C8066CEB1C9A4A1600DE1D90 /* MMPrinterDemoUITests.xctest */; 238 | productType = "com.apple.product-type.bundle.ui-testing"; 239 | }; 240 | /* End PBXNativeTarget section */ 241 | 242 | /* Begin PBXProject section */ 243 | C8066CBF1C9A4A1600DE1D90 /* Project object */ = { 244 | isa = PBXProject; 245 | attributes = { 246 | LastUpgradeCheck = 0720; 247 | ORGANIZATIONNAME = mikezhao; 248 | TargetAttributes = { 249 | C8066CC61C9A4A1600DE1D90 = { 250 | CreatedOnToolsVersion = 7.2.1; 251 | }; 252 | C8066CDF1C9A4A1600DE1D90 = { 253 | CreatedOnToolsVersion = 7.2.1; 254 | TestTargetID = C8066CC61C9A4A1600DE1D90; 255 | }; 256 | C8066CEA1C9A4A1600DE1D90 = { 257 | CreatedOnToolsVersion = 7.2.1; 258 | TestTargetID = C8066CC61C9A4A1600DE1D90; 259 | }; 260 | }; 261 | }; 262 | buildConfigurationList = C8066CC21C9A4A1600DE1D90 /* Build configuration list for PBXProject "MMPrinterDemo" */; 263 | compatibilityVersion = "Xcode 3.2"; 264 | developmentRegion = English; 265 | hasScannedForEncodings = 0; 266 | knownRegions = ( 267 | en, 268 | Base, 269 | ); 270 | mainGroup = C8066CBE1C9A4A1600DE1D90; 271 | productRefGroup = C8066CC81C9A4A1600DE1D90 /* Products */; 272 | projectDirPath = ""; 273 | projectRoot = ""; 274 | targets = ( 275 | C8066CC61C9A4A1600DE1D90 /* MMPrinterDemo */, 276 | C8066CDF1C9A4A1600DE1D90 /* MMPrinterDemoTests */, 277 | C8066CEA1C9A4A1600DE1D90 /* MMPrinterDemoUITests */, 278 | ); 279 | }; 280 | /* End PBXProject section */ 281 | 282 | /* Begin PBXResourcesBuildPhase section */ 283 | C8066CC51C9A4A1600DE1D90 /* Resources */ = { 284 | isa = PBXResourcesBuildPhase; 285 | buildActionMask = 2147483647; 286 | files = ( 287 | C8066CDA1C9A4A1600DE1D90 /* LaunchScreen.storyboard in Resources */, 288 | C8066CD71C9A4A1600DE1D90 /* Assets.xcassets in Resources */, 289 | C8066CD51C9A4A1600DE1D90 /* Main.storyboard in Resources */, 290 | 279DD89E1C9DC05F00CEA250 /* kfc.gif in Resources */, 291 | ); 292 | runOnlyForDeploymentPostprocessing = 0; 293 | }; 294 | C8066CDE1C9A4A1600DE1D90 /* Resources */ = { 295 | isa = PBXResourcesBuildPhase; 296 | buildActionMask = 2147483647; 297 | files = ( 298 | ); 299 | runOnlyForDeploymentPostprocessing = 0; 300 | }; 301 | C8066CE91C9A4A1600DE1D90 /* Resources */ = { 302 | isa = PBXResourcesBuildPhase; 303 | buildActionMask = 2147483647; 304 | files = ( 305 | ); 306 | runOnlyForDeploymentPostprocessing = 0; 307 | }; 308 | /* End PBXResourcesBuildPhase section */ 309 | 310 | /* Begin PBXSourcesBuildPhase section */ 311 | C8066CC31C9A4A1600DE1D90 /* Sources */ = { 312 | isa = PBXSourcesBuildPhase; 313 | buildActionMask = 2147483647; 314 | files = ( 315 | C8066CD21C9A4A1600DE1D90 /* ViewController.m in Sources */, 316 | 279DD89A1C9DA97900CEA250 /* MMQRCode.m in Sources */, 317 | C8066CCF1C9A4A1600DE1D90 /* AppDelegate.m in Sources */, 318 | C8066D091C9A86D600DE1D90 /* MMSocketManager.m in Sources */, 319 | C8066D061C9A4BBF00DE1D90 /* MMPrinterManager.m in Sources */, 320 | C8AD0B7F1C9BA33100FFFAB6 /* MMReceiptManager.m in Sources */, 321 | C8066CCC1C9A4A1600DE1D90 /* main.m in Sources */, 322 | C8066D001C9A4B4300DE1D90 /* AsyncSocket.m in Sources */, 323 | 279DD8971C9DA71B00CEA250 /* IGThermalSupport.m in Sources */, 324 | ); 325 | runOnlyForDeploymentPostprocessing = 0; 326 | }; 327 | C8066CDC1C9A4A1600DE1D90 /* Sources */ = { 328 | isa = PBXSourcesBuildPhase; 329 | buildActionMask = 2147483647; 330 | files = ( 331 | C8066CE51C9A4A1600DE1D90 /* MMPrinterDemoTests.m in Sources */, 332 | ); 333 | runOnlyForDeploymentPostprocessing = 0; 334 | }; 335 | C8066CE71C9A4A1600DE1D90 /* Sources */ = { 336 | isa = PBXSourcesBuildPhase; 337 | buildActionMask = 2147483647; 338 | files = ( 339 | C8066CF01C9A4A1600DE1D90 /* MMPrinterDemoUITests.m in Sources */, 340 | ); 341 | runOnlyForDeploymentPostprocessing = 0; 342 | }; 343 | /* End PBXSourcesBuildPhase section */ 344 | 345 | /* Begin PBXTargetDependency section */ 346 | C8066CE21C9A4A1600DE1D90 /* PBXTargetDependency */ = { 347 | isa = PBXTargetDependency; 348 | target = C8066CC61C9A4A1600DE1D90 /* MMPrinterDemo */; 349 | targetProxy = C8066CE11C9A4A1600DE1D90 /* PBXContainerItemProxy */; 350 | }; 351 | C8066CED1C9A4A1600DE1D90 /* PBXTargetDependency */ = { 352 | isa = PBXTargetDependency; 353 | target = C8066CC61C9A4A1600DE1D90 /* MMPrinterDemo */; 354 | targetProxy = C8066CEC1C9A4A1600DE1D90 /* PBXContainerItemProxy */; 355 | }; 356 | /* End PBXTargetDependency section */ 357 | 358 | /* Begin PBXVariantGroup section */ 359 | C8066CD31C9A4A1600DE1D90 /* Main.storyboard */ = { 360 | isa = PBXVariantGroup; 361 | children = ( 362 | C8066CD41C9A4A1600DE1D90 /* Base */, 363 | ); 364 | name = Main.storyboard; 365 | sourceTree = ""; 366 | }; 367 | C8066CD81C9A4A1600DE1D90 /* LaunchScreen.storyboard */ = { 368 | isa = PBXVariantGroup; 369 | children = ( 370 | C8066CD91C9A4A1600DE1D90 /* Base */, 371 | ); 372 | name = LaunchScreen.storyboard; 373 | sourceTree = ""; 374 | }; 375 | /* End PBXVariantGroup section */ 376 | 377 | /* Begin XCBuildConfiguration section */ 378 | C8066CF21C9A4A1600DE1D90 /* Debug */ = { 379 | isa = XCBuildConfiguration; 380 | buildSettings = { 381 | ALWAYS_SEARCH_USER_PATHS = NO; 382 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 383 | CLANG_CXX_LIBRARY = "libc++"; 384 | CLANG_ENABLE_MODULES = YES; 385 | CLANG_ENABLE_OBJC_ARC = YES; 386 | CLANG_WARN_BOOL_CONVERSION = YES; 387 | CLANG_WARN_CONSTANT_CONVERSION = YES; 388 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 389 | CLANG_WARN_EMPTY_BODY = YES; 390 | CLANG_WARN_ENUM_CONVERSION = YES; 391 | CLANG_WARN_INT_CONVERSION = YES; 392 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 393 | CLANG_WARN_UNREACHABLE_CODE = YES; 394 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 395 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 396 | COPY_PHASE_STRIP = NO; 397 | DEBUG_INFORMATION_FORMAT = dwarf; 398 | ENABLE_STRICT_OBJC_MSGSEND = YES; 399 | ENABLE_TESTABILITY = YES; 400 | GCC_C_LANGUAGE_STANDARD = gnu99; 401 | GCC_DYNAMIC_NO_PIC = NO; 402 | GCC_NO_COMMON_BLOCKS = YES; 403 | GCC_OPTIMIZATION_LEVEL = 0; 404 | GCC_PREPROCESSOR_DEFINITIONS = ( 405 | "DEBUG=1", 406 | "$(inherited)", 407 | ); 408 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 409 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 410 | GCC_WARN_UNDECLARED_SELECTOR = YES; 411 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 412 | GCC_WARN_UNUSED_FUNCTION = YES; 413 | GCC_WARN_UNUSED_VARIABLE = YES; 414 | IPHONEOS_DEPLOYMENT_TARGET = 9.2; 415 | MTL_ENABLE_DEBUG_INFO = YES; 416 | ONLY_ACTIVE_ARCH = YES; 417 | SDKROOT = iphoneos; 418 | }; 419 | name = Debug; 420 | }; 421 | C8066CF31C9A4A1600DE1D90 /* Release */ = { 422 | isa = XCBuildConfiguration; 423 | buildSettings = { 424 | ALWAYS_SEARCH_USER_PATHS = NO; 425 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 426 | CLANG_CXX_LIBRARY = "libc++"; 427 | CLANG_ENABLE_MODULES = YES; 428 | CLANG_ENABLE_OBJC_ARC = YES; 429 | CLANG_WARN_BOOL_CONVERSION = YES; 430 | CLANG_WARN_CONSTANT_CONVERSION = YES; 431 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 432 | CLANG_WARN_EMPTY_BODY = YES; 433 | CLANG_WARN_ENUM_CONVERSION = YES; 434 | CLANG_WARN_INT_CONVERSION = YES; 435 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 436 | CLANG_WARN_UNREACHABLE_CODE = YES; 437 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 438 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 439 | COPY_PHASE_STRIP = NO; 440 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 441 | ENABLE_NS_ASSERTIONS = NO; 442 | ENABLE_STRICT_OBJC_MSGSEND = YES; 443 | GCC_C_LANGUAGE_STANDARD = gnu99; 444 | GCC_NO_COMMON_BLOCKS = YES; 445 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 446 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 447 | GCC_WARN_UNDECLARED_SELECTOR = YES; 448 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 449 | GCC_WARN_UNUSED_FUNCTION = YES; 450 | GCC_WARN_UNUSED_VARIABLE = YES; 451 | IPHONEOS_DEPLOYMENT_TARGET = 9.2; 452 | MTL_ENABLE_DEBUG_INFO = NO; 453 | SDKROOT = iphoneos; 454 | VALIDATE_PRODUCT = YES; 455 | }; 456 | name = Release; 457 | }; 458 | C8066CF51C9A4A1600DE1D90 /* Debug */ = { 459 | isa = XCBuildConfiguration; 460 | buildSettings = { 461 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 462 | CODE_SIGN_IDENTITY = "iPhone Developer"; 463 | INFOPLIST_FILE = MMPrinterDemo/Info.plist; 464 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 465 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 466 | PRODUCT_BUNDLE_IDENTIFIER = com.mikezhao.MMPrinterDemo; 467 | PRODUCT_NAME = "$(TARGET_NAME)"; 468 | }; 469 | name = Debug; 470 | }; 471 | C8066CF61C9A4A1600DE1D90 /* Release */ = { 472 | isa = XCBuildConfiguration; 473 | buildSettings = { 474 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 475 | CODE_SIGN_IDENTITY = "iPhone Developer"; 476 | INFOPLIST_FILE = MMPrinterDemo/Info.plist; 477 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 478 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 479 | PRODUCT_BUNDLE_IDENTIFIER = com.mikezhao.MMPrinterDemo; 480 | PRODUCT_NAME = "$(TARGET_NAME)"; 481 | }; 482 | name = Release; 483 | }; 484 | C8066CF81C9A4A1600DE1D90 /* Debug */ = { 485 | isa = XCBuildConfiguration; 486 | buildSettings = { 487 | BUNDLE_LOADER = "$(TEST_HOST)"; 488 | INFOPLIST_FILE = MMPrinterDemoTests/Info.plist; 489 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 490 | PRODUCT_BUNDLE_IDENTIFIER = com.mikezhao.MMPrinterDemoTests; 491 | PRODUCT_NAME = "$(TARGET_NAME)"; 492 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/MMPrinterDemo.app/MMPrinterDemo"; 493 | }; 494 | name = Debug; 495 | }; 496 | C8066CF91C9A4A1600DE1D90 /* Release */ = { 497 | isa = XCBuildConfiguration; 498 | buildSettings = { 499 | BUNDLE_LOADER = "$(TEST_HOST)"; 500 | INFOPLIST_FILE = MMPrinterDemoTests/Info.plist; 501 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 502 | PRODUCT_BUNDLE_IDENTIFIER = com.mikezhao.MMPrinterDemoTests; 503 | PRODUCT_NAME = "$(TARGET_NAME)"; 504 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/MMPrinterDemo.app/MMPrinterDemo"; 505 | }; 506 | name = Release; 507 | }; 508 | C8066CFB1C9A4A1600DE1D90 /* Debug */ = { 509 | isa = XCBuildConfiguration; 510 | buildSettings = { 511 | CODE_SIGN_IDENTITY = "iPhone Developer"; 512 | INFOPLIST_FILE = MMPrinterDemoUITests/Info.plist; 513 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 514 | PRODUCT_BUNDLE_IDENTIFIER = com.mikezhao.MMPrinterDemoUITests; 515 | PRODUCT_NAME = "$(TARGET_NAME)"; 516 | TEST_TARGET_NAME = MMPrinterDemo; 517 | USES_XCTRUNNER = YES; 518 | }; 519 | name = Debug; 520 | }; 521 | C8066CFC1C9A4A1600DE1D90 /* Release */ = { 522 | isa = XCBuildConfiguration; 523 | buildSettings = { 524 | CODE_SIGN_IDENTITY = "iPhone Developer"; 525 | INFOPLIST_FILE = MMPrinterDemoUITests/Info.plist; 526 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 527 | PRODUCT_BUNDLE_IDENTIFIER = com.mikezhao.MMPrinterDemoUITests; 528 | PRODUCT_NAME = "$(TARGET_NAME)"; 529 | TEST_TARGET_NAME = MMPrinterDemo; 530 | USES_XCTRUNNER = YES; 531 | }; 532 | name = Release; 533 | }; 534 | /* End XCBuildConfiguration section */ 535 | 536 | /* Begin XCConfigurationList section */ 537 | C8066CC21C9A4A1600DE1D90 /* Build configuration list for PBXProject "MMPrinterDemo" */ = { 538 | isa = XCConfigurationList; 539 | buildConfigurations = ( 540 | C8066CF21C9A4A1600DE1D90 /* Debug */, 541 | C8066CF31C9A4A1600DE1D90 /* Release */, 542 | ); 543 | defaultConfigurationIsVisible = 0; 544 | defaultConfigurationName = Release; 545 | }; 546 | C8066CF41C9A4A1600DE1D90 /* Build configuration list for PBXNativeTarget "MMPrinterDemo" */ = { 547 | isa = XCConfigurationList; 548 | buildConfigurations = ( 549 | C8066CF51C9A4A1600DE1D90 /* Debug */, 550 | C8066CF61C9A4A1600DE1D90 /* Release */, 551 | ); 552 | defaultConfigurationIsVisible = 0; 553 | defaultConfigurationName = Release; 554 | }; 555 | C8066CF71C9A4A1600DE1D90 /* Build configuration list for PBXNativeTarget "MMPrinterDemoTests" */ = { 556 | isa = XCConfigurationList; 557 | buildConfigurations = ( 558 | C8066CF81C9A4A1600DE1D90 /* Debug */, 559 | C8066CF91C9A4A1600DE1D90 /* Release */, 560 | ); 561 | defaultConfigurationIsVisible = 0; 562 | defaultConfigurationName = Release; 563 | }; 564 | C8066CFA1C9A4A1600DE1D90 /* Build configuration list for PBXNativeTarget "MMPrinterDemoUITests" */ = { 565 | isa = XCConfigurationList; 566 | buildConfigurations = ( 567 | C8066CFB1C9A4A1600DE1D90 /* Debug */, 568 | C8066CFC1C9A4A1600DE1D90 /* Release */, 569 | ); 570 | defaultConfigurationIsVisible = 0; 571 | defaultConfigurationName = Release; 572 | }; 573 | /* End XCConfigurationList section */ 574 | }; 575 | rootObject = C8066CBF1C9A4A1600DE1D90 /* Project object */; 576 | } 577 | -------------------------------------------------------------------------------- /MMPrinterDemo/PrinterManager/AsyncSocket.h: -------------------------------------------------------------------------------- 1 | // 2 | // AsyncSocket.h 3 | // 4 | // This class is in the public domain. 5 | // Originally created by Dustin Voss on Wed Jan 29 2003. 6 | // Updated and maintained by Deusty Designs and the Mac development community. 7 | // 8 | // http://code.google.com/p/cocoaasyncsocket/ 9 | // 10 | 11 | #import 12 | 13 | @class AsyncSocket; 14 | @class AsyncReadPacket; 15 | @class AsyncWritePacket; 16 | 17 | extern NSString *const AsyncSocketException; 18 | extern NSString *const AsyncSocketErrorDomain; 19 | 20 | typedef NS_ENUM(NSInteger, AsyncSocketError) { 21 | AsyncSocketCFSocketError = kCFSocketError, // From CFSocketError enum. 22 | AsyncSocketNoError = 0, // Never used. 23 | AsyncSocketCanceledError, // onSocketWillConnect: returned NO. 24 | AsyncSocketConnectTimeoutError, 25 | AsyncSocketReadMaxedOutError, // Reached set maxLength without completing 26 | AsyncSocketReadTimeoutError, 27 | AsyncSocketWriteTimeoutError 28 | }; 29 | 30 | @protocol AsyncSocketDelegate 31 | @optional 32 | 33 | /** 34 | * In the event of an error, the socket is closed. 35 | * You may call "unreadData" during this call-back to get the last bit of data off the socket. 36 | * When connecting, this delegate method may be called 37 | * before"onSocket:didAcceptNewSocket:" or "onSocket:didConnectToHost:". 38 | **/ 39 | - (void)onSocket:(AsyncSocket *)sock willDisconnectWithError:(NSError *)err; 40 | 41 | /** 42 | * Called when a socket disconnects with or without error. If you want to release a socket after it disconnects, 43 | * do so here. It is not safe to do that during "onSocket:willDisconnectWithError:". 44 | * 45 | * If you call the disconnect method, and the socket wasn't already disconnected, 46 | * this delegate method will be called before the disconnect method returns. 47 | **/ 48 | - (void)onSocketDidDisconnect:(AsyncSocket *)sock; 49 | 50 | /** 51 | * Called when a socket accepts a connection. Another socket is spawned to handle it. The new socket will have 52 | * the same delegate and will call "onSocket:didConnectToHost:port:". 53 | **/ 54 | - (void)onSocket:(AsyncSocket *)sock didAcceptNewSocket:(AsyncSocket *)newSocket; 55 | 56 | /** 57 | * Called when a new socket is spawned to handle a connection. This method should return the run-loop of the 58 | * thread on which the new socket and its delegate should operate. If omitted, [NSRunLoop currentRunLoop] is used. 59 | **/ 60 | - (NSRunLoop *)onSocket:(AsyncSocket *)sock wantsRunLoopForNewSocket:(AsyncSocket *)newSocket; 61 | 62 | /** 63 | * Called when a socket is about to connect. This method should return YES to continue, or NO to abort. 64 | * If aborted, will result in AsyncSocketCanceledError. 65 | * 66 | * If the connectToHost:onPort:error: method was called, the delegate will be able to access and configure the 67 | * CFReadStream and CFWriteStream as desired prior to connection. 68 | * 69 | * If the connectToAddress:error: method was called, the delegate will be able to access and configure the 70 | * CFSocket and CFSocketNativeHandle (BSD socket) as desired prior to connection. You will be able to access and 71 | * configure the CFReadStream and CFWriteStream in the onSocket:didConnectToHost:port: method. 72 | **/ 73 | - (BOOL)onSocketWillConnect:(AsyncSocket *)sock; 74 | 75 | /** 76 | * Called when a socket connects and is ready for reading and writing. 77 | * The host parameter will be an IP address, not a DNS name. 78 | **/ 79 | - (void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port; 80 | 81 | /** 82 | * Called when a socket has completed reading the requested data into memory. 83 | * Not called if there is an error. 84 | **/ 85 | - (void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag; 86 | 87 | /** 88 | * Called when a socket has read in data, but has not yet completed the read. 89 | * This would occur if using readToData: or readToLength: methods. 90 | * It may be used to for things such as updating progress bars. 91 | **/ 92 | - (void)onSocket:(AsyncSocket *)sock didReadPartialDataOfLength:(NSUInteger)partialLength tag:(long)tag; 93 | 94 | /** 95 | * Called when a socket has completed writing the requested data. Not called if there is an error. 96 | **/ 97 | - (void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag; 98 | 99 | /** 100 | * Called when a socket has written some data, but has not yet completed the entire write. 101 | * It may be used to for things such as updating progress bars. 102 | **/ 103 | - (void)onSocket:(AsyncSocket *)sock didWritePartialDataOfLength:(NSUInteger)partialLength tag:(long)tag; 104 | 105 | /** 106 | * Called if a read operation has reached its timeout without completing. 107 | * This method allows you to optionally extend the timeout. 108 | * If you return a positive time interval (> 0) the read's timeout will be extended by the given amount. 109 | * If you don't implement this method, or return a non-positive time interval (<= 0) the read will timeout as usual. 110 | * 111 | * The elapsed parameter is the sum of the original timeout, plus any additions previously added via this method. 112 | * The length parameter is the number of bytes that have been read so far for the read operation. 113 | * 114 | * Note that this method may be called multiple times for a single read if you return positive numbers. 115 | **/ 116 | - (NSTimeInterval)onSocket:(AsyncSocket *)sock 117 | shouldTimeoutReadWithTag:(long)tag 118 | elapsed:(NSTimeInterval)elapsed 119 | bytesDone:(NSUInteger)length; 120 | 121 | /** 122 | * Called if a write operation has reached its timeout without completing. 123 | * This method allows you to optionally extend the timeout. 124 | * If you return a positive time interval (> 0) the write's timeout will be extended by the given amount. 125 | * If you don't implement this method, or return a non-positive time interval (<= 0) the write will timeout as usual. 126 | * 127 | * The elapsed parameter is the sum of the original timeout, plus any additions previously added via this method. 128 | * The length parameter is the number of bytes that have been written so far for the write operation. 129 | * 130 | * Note that this method may be called multiple times for a single write if you return positive numbers. 131 | **/ 132 | - (NSTimeInterval)onSocket:(AsyncSocket *)sock 133 | shouldTimeoutWriteWithTag:(long)tag 134 | elapsed:(NSTimeInterval)elapsed 135 | bytesDone:(NSUInteger)length; 136 | 137 | /** 138 | * Called after the socket has successfully completed SSL/TLS negotiation. 139 | * This method is not called unless you use the provided startTLS method. 140 | * 141 | * If a SSL/TLS negotiation fails (invalid certificate, etc) then the socket will immediately close, 142 | * and the onSocket:willDisconnectWithError: delegate method will be called with the specific SSL error code. 143 | **/ 144 | - (void)onSocketDidSecure:(AsyncSocket *)sock; 145 | 146 | @end 147 | 148 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 149 | #pragma mark - 150 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 151 | 152 | @interface AsyncSocket : NSObject 153 | { 154 | CFSocketNativeHandle theNativeSocket4; 155 | CFSocketNativeHandle theNativeSocket6; 156 | 157 | CFSocketRef theSocket4; // IPv4 accept or connect socket 158 | CFSocketRef theSocket6; // IPv6 accept or connect socket 159 | 160 | CFReadStreamRef theReadStream; 161 | CFWriteStreamRef theWriteStream; 162 | 163 | CFRunLoopSourceRef theSource4; // For theSocket4 164 | CFRunLoopSourceRef theSource6; // For theSocket6 165 | CFRunLoopRef theRunLoop; 166 | CFSocketContext theContext; 167 | NSArray *theRunLoopModes; 168 | 169 | NSTimer *theConnectTimer; 170 | 171 | NSMutableArray *theReadQueue; 172 | AsyncReadPacket *theCurrentRead; 173 | NSTimer *theReadTimer; 174 | NSMutableData *partialReadBuffer; 175 | 176 | NSMutableArray *theWriteQueue; 177 | AsyncWritePacket *theCurrentWrite; 178 | NSTimer *theWriteTimer; 179 | 180 | id theDelegate; 181 | UInt16 theFlags; 182 | 183 | long theUserData; 184 | } 185 | 186 | - (id)init; 187 | - (id)initWithDelegate:(id)delegate; 188 | - (id)initWithDelegate:(id)delegate userData:(long)userData; 189 | 190 | /* String representation is long but has no "\n". */ 191 | - (NSString *)description; 192 | 193 | /** 194 | * Use "canSafelySetDelegate" to see if there is any pending business (reads and writes) with the current delegate 195 | * before changing it. It is, of course, safe to change the delegate before connecting or accepting connections. 196 | **/ 197 | - (id)delegate; 198 | - (BOOL)canSafelySetDelegate; 199 | - (void)setDelegate:(id)delegate; 200 | 201 | /* User data can be a long, or an id or void * cast to a long. */ 202 | - (long)userData; 203 | - (void)setUserData:(long)userData; 204 | 205 | /* Don't use these to read or write. And don't close them either! */ 206 | - (CFSocketRef)getCFSocket; 207 | - (CFReadStreamRef)getCFReadStream; 208 | - (CFWriteStreamRef)getCFWriteStream; 209 | 210 | // Once one of the accept or connect methods are called, the AsyncSocket instance is locked in 211 | // and the other accept/connect methods can't be called without disconnecting the socket first. 212 | // If the attempt fails or times out, these methods either return NO or 213 | // call "onSocket:willDisconnectWithError:" and "onSockedDidDisconnect:". 214 | 215 | // When an incoming connection is accepted, AsyncSocket invokes several delegate methods. 216 | // These methods are (in chronological order): 217 | // 1. onSocket:didAcceptNewSocket: 218 | // 2. onSocket:wantsRunLoopForNewSocket: 219 | // 3. onSocketWillConnect: 220 | // 221 | // Your server code will need to retain the accepted socket (if you want to accept it). 222 | // The best place to do this is probably in the onSocket:didAcceptNewSocket: method. 223 | // 224 | // After the read and write streams have been setup for the newly accepted socket, 225 | // the onSocket:didConnectToHost:port: method will be called on the proper run loop. 226 | // 227 | // Multithreading Note: If you're going to be moving the newly accepted socket to another run 228 | // loop by implementing onSocket:wantsRunLoopForNewSocket:, then you should wait until the 229 | // onSocket:didConnectToHost:port: method before calling read, write, or startTLS methods. 230 | // Otherwise read/write events are scheduled on the incorrect runloop, and chaos may ensue. 231 | 232 | /** 233 | * Tells the socket to begin listening and accepting connections on the given port. 234 | * When a connection comes in, the AsyncSocket instance will call the various delegate methods (see above). 235 | * The socket will listen on all available interfaces (e.g. wifi, ethernet, etc) 236 | **/ 237 | - (BOOL)acceptOnPort:(UInt16)port error:(NSError **)errPtr; 238 | 239 | /** 240 | * This method is the same as acceptOnPort:error: with the additional option 241 | * of specifying which interface to listen on. So, for example, if you were writing code for a server that 242 | * has multiple IP addresses, you could specify which address you wanted to listen on. Or you could use it 243 | * to specify that the socket should only accept connections over ethernet, and not other interfaces such as wifi. 244 | * You may also use the special strings "localhost" or "loopback" to specify that 245 | * the socket only accept connections from the local machine. 246 | * 247 | * To accept connections on any interface pass nil, or simply use the acceptOnPort:error: method. 248 | **/ 249 | - (BOOL)acceptOnInterface:(NSString *)interface port:(UInt16)port error:(NSError **)errPtr; 250 | 251 | /** 252 | * Connects to the given host and port. 253 | * The host may be a domain name (e.g. "deusty.com") or an IP address string (e.g. "192.168.0.2") 254 | **/ 255 | - (BOOL)connectToHost:(NSString *)hostname onPort:(UInt16)port error:(NSError **)errPtr; 256 | 257 | /** 258 | * This method is the same as connectToHost:onPort:error: with an additional timeout option. 259 | * To not time out use a negative time interval, or simply use the connectToHost:onPort:error: method. 260 | **/ 261 | - (BOOL)connectToHost:(NSString *)hostname 262 | onPort:(UInt16)port 263 | withTimeout:(NSTimeInterval)timeout 264 | error:(NSError **)errPtr; 265 | 266 | /** 267 | * Connects to the given address, specified as a sockaddr structure wrapped in a NSData object. 268 | * For example, a NSData object returned from NSNetService's addresses method. 269 | * 270 | * If you have an existing struct sockaddr you can convert it to a NSData object like so: 271 | * struct sockaddr sa -> NSData *dsa = [NSData dataWithBytes:&remoteAddr length:remoteAddr.sa_len]; 272 | * struct sockaddr *sa -> NSData *dsa = [NSData dataWithBytes:remoteAddr length:remoteAddr->sa_len]; 273 | **/ 274 | - (BOOL)connectToAddress:(NSData *)remoteAddr error:(NSError **)errPtr; 275 | 276 | /** 277 | * This method is the same as connectToAddress:error: with an additional timeout option. 278 | * To not time out use a negative time interval, or simply use the connectToAddress:error: method. 279 | **/ 280 | - (BOOL)connectToAddress:(NSData *)remoteAddr withTimeout:(NSTimeInterval)timeout error:(NSError **)errPtr; 281 | 282 | - (BOOL)connectToAddress:(NSData *)remoteAddr 283 | viaInterfaceAddress:(NSData *)interfaceAddr 284 | withTimeout:(NSTimeInterval)timeout 285 | error:(NSError **)errPtr; 286 | 287 | /** 288 | * Disconnects immediately. Any pending reads or writes are dropped. 289 | * If the socket is not already disconnected, the onSocketDidDisconnect delegate method 290 | * will be called immediately, before this method returns. 291 | * 292 | * Please note the recommended way of releasing an AsyncSocket instance (e.g. in a dealloc method) 293 | * [asyncSocket setDelegate:nil]; 294 | * [asyncSocket disconnect]; 295 | * [asyncSocket release]; 296 | **/ 297 | - (void)disconnect; 298 | 299 | /** 300 | * Disconnects after all pending reads have completed. 301 | * After calling this, the read and write methods will do nothing. 302 | * The socket will disconnect even if there are still pending writes. 303 | **/ 304 | - (void)disconnectAfterReading; 305 | 306 | /** 307 | * Disconnects after all pending writes have completed. 308 | * After calling this, the read and write methods will do nothing. 309 | * The socket will disconnect even if there are still pending reads. 310 | **/ 311 | - (void)disconnectAfterWriting; 312 | 313 | /** 314 | * Disconnects after all pending reads and writes have completed. 315 | * After calling this, the read and write methods will do nothing. 316 | **/ 317 | - (void)disconnectAfterReadingAndWriting; 318 | 319 | /* Returns YES if the socket and streams are open, connected, and ready for reading and writing. */ 320 | - (BOOL)isConnected; 321 | 322 | /** 323 | * Returns the local or remote host and port to which this socket is connected, or nil and 0 if not connected. 324 | * The host will be an IP address. 325 | **/ 326 | - (NSString *)connectedHost; 327 | - (UInt16)connectedPort; 328 | 329 | - (NSString *)localHost; 330 | - (UInt16)localPort; 331 | 332 | /** 333 | * Returns the local or remote address to which this socket is connected, 334 | * specified as a sockaddr structure wrapped in a NSData object. 335 | * 336 | * See also the connectedHost, connectedPort, localHost and localPort methods. 337 | **/ 338 | - (NSData *)connectedAddress; 339 | - (NSData *)localAddress; 340 | 341 | /** 342 | * Returns whether the socket is IPv4 or IPv6. 343 | * An accepting socket may be both. 344 | **/ 345 | - (BOOL)isIPv4; 346 | - (BOOL)isIPv6; 347 | 348 | // The readData and writeData methods won't block (they are asynchronous). 349 | // 350 | // When a read is complete the onSocket:didReadData:withTag: delegate method is called. 351 | // When a write is complete the onSocket:didWriteDataWithTag: delegate method is called. 352 | // 353 | // You may optionally set a timeout for any read/write operation. (To not timeout, use a negative time interval.) 354 | // If a read/write opertion times out, the corresponding "onSocket:shouldTimeout..." delegate method 355 | // is called to optionally allow you to extend the timeout. 356 | // Upon a timeout, the "onSocket:willDisconnectWithError:" method is called, followed by "onSocketDidDisconnect". 357 | // 358 | // The tag is for your convenience. 359 | // You can use it as an array index, step number, state id, pointer, etc. 360 | 361 | /** 362 | * Reads the first available bytes that become available on the socket. 363 | * 364 | * If the timeout value is negative, the read operation will not use a timeout. 365 | **/ 366 | - (void)readDataWithTimeout:(NSTimeInterval)timeout tag:(long)tag; 367 | 368 | /** 369 | * Reads the first available bytes that become available on the socket. 370 | * The bytes will be appended to the given byte buffer starting at the given offset. 371 | * The given buffer will automatically be increased in size if needed. 372 | * 373 | * If the timeout value is negative, the read operation will not use a timeout. 374 | * If the buffer if nil, the socket will create a buffer for you. 375 | * 376 | * If the bufferOffset is greater than the length of the given buffer, 377 | * the method will do nothing, and the delegate will not be called. 378 | * 379 | * If you pass a buffer, you must not alter it in any way while AsyncSocket is using it. 380 | * After completion, the data returned in onSocket:didReadData:withTag: will be a subset of the given buffer. 381 | * That is, it will reference the bytes that were appended to the given buffer. 382 | **/ 383 | - (void)readDataWithTimeout:(NSTimeInterval)timeout 384 | buffer:(NSMutableData *)buffer 385 | bufferOffset:(NSUInteger)offset 386 | tag:(long)tag; 387 | 388 | /** 389 | * Reads the first available bytes that become available on the socket. 390 | * The bytes will be appended to the given byte buffer starting at the given offset. 391 | * The given buffer will automatically be increased in size if needed. 392 | * A maximum of length bytes will be read. 393 | * 394 | * If the timeout value is negative, the read operation will not use a timeout. 395 | * If the buffer if nil, a buffer will automatically be created for you. 396 | * If maxLength is zero, no length restriction is enforced. 397 | * 398 | * If the bufferOffset is greater than the length of the given buffer, 399 | * the method will do nothing, and the delegate will not be called. 400 | * 401 | * If you pass a buffer, you must not alter it in any way while AsyncSocket is using it. 402 | * After completion, the data returned in onSocket:didReadData:withTag: will be a subset of the given buffer. 403 | * That is, it will reference the bytes that were appended to the given buffer. 404 | **/ 405 | - (void)readDataWithTimeout:(NSTimeInterval)timeout 406 | buffer:(NSMutableData *)buffer 407 | bufferOffset:(NSUInteger)offset 408 | maxLength:(NSUInteger)length 409 | tag:(long)tag; 410 | 411 | /** 412 | * Reads the given number of bytes. 413 | * 414 | * If the timeout value is negative, the read operation will not use a timeout. 415 | * 416 | * If the length is 0, this method does nothing and the delegate is not called. 417 | **/ 418 | - (void)readDataToLength:(NSUInteger)length withTimeout:(NSTimeInterval)timeout tag:(long)tag; 419 | 420 | /** 421 | * Reads the given number of bytes. 422 | * The bytes will be appended to the given byte buffer starting at the given offset. 423 | * The given buffer will automatically be increased in size if needed. 424 | * 425 | * If the timeout value is negative, the read operation will not use a timeout. 426 | * If the buffer if nil, a buffer will automatically be created for you. 427 | * 428 | * If the length is 0, this method does nothing and the delegate is not called. 429 | * If the bufferOffset is greater than the length of the given buffer, 430 | * the method will do nothing, and the delegate will not be called. 431 | * 432 | * If you pass a buffer, you must not alter it in any way while AsyncSocket is using it. 433 | * After completion, the data returned in onSocket:didReadData:withTag: will be a subset of the given buffer. 434 | * That is, it will reference the bytes that were appended to the given buffer. 435 | **/ 436 | - (void)readDataToLength:(NSUInteger)length 437 | withTimeout:(NSTimeInterval)timeout 438 | buffer:(NSMutableData *)buffer 439 | bufferOffset:(NSUInteger)offset 440 | tag:(long)tag; 441 | 442 | /** 443 | * Reads bytes until (and including) the passed "data" parameter, which acts as a separator. 444 | * 445 | * If the timeout value is negative, the read operation will not use a timeout. 446 | * 447 | * If you pass nil or zero-length data as the "data" parameter, 448 | * the method will do nothing, and the delegate will not be called. 449 | * 450 | * To read a line from the socket, use the line separator (e.g. CRLF for HTTP, see below) as the "data" parameter. 451 | * Note that this method is not character-set aware, so if a separator can occur naturally as part of the encoding for 452 | * a character, the read will prematurely end. 453 | **/ 454 | - (void)readDataToData:(NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)tag; 455 | 456 | /** 457 | * Reads bytes until (and including) the passed "data" parameter, which acts as a separator. 458 | * The bytes will be appended to the given byte buffer starting at the given offset. 459 | * The given buffer will automatically be increased in size if needed. 460 | * 461 | * If the timeout value is negative, the read operation will not use a timeout. 462 | * If the buffer if nil, a buffer will automatically be created for you. 463 | * 464 | * If the bufferOffset is greater than the length of the given buffer, 465 | * the method will do nothing, and the delegate will not be called. 466 | * 467 | * If you pass a buffer, you must not alter it in any way while AsyncSocket is using it. 468 | * After completion, the data returned in onSocket:didReadData:withTag: will be a subset of the given buffer. 469 | * That is, it will reference the bytes that were appended to the given buffer. 470 | * 471 | * To read a line from the socket, use the line separator (e.g. CRLF for HTTP, see below) as the "data" parameter. 472 | * Note that this method is not character-set aware, so if a separator can occur naturally as part of the encoding for 473 | * a character, the read will prematurely end. 474 | **/ 475 | - (void)readDataToData:(NSData *)data 476 | withTimeout:(NSTimeInterval)timeout 477 | buffer:(NSMutableData *)buffer 478 | bufferOffset:(NSUInteger)offset 479 | tag:(long)tag; 480 | 481 | /** 482 | * Reads bytes until (and including) the passed "data" parameter, which acts as a separator. 483 | * 484 | * If the timeout value is negative, the read operation will not use a timeout. 485 | * 486 | * If maxLength is zero, no length restriction is enforced. 487 | * Otherwise if maxLength bytes are read without completing the read, 488 | * it is treated similarly to a timeout - the socket is closed with a AsyncSocketReadMaxedOutError. 489 | * The read will complete successfully if exactly maxLength bytes are read and the given data is found at the end. 490 | * 491 | * If you pass nil or zero-length data as the "data" parameter, 492 | * the method will do nothing, and the delegate will not be called. 493 | * If you pass a maxLength parameter that is less than the length of the data parameter, 494 | * the method will do nothing, and the delegate will not be called. 495 | * 496 | * To read a line from the socket, use the line separator (e.g. CRLF for HTTP, see below) as the "data" parameter. 497 | * Note that this method is not character-set aware, so if a separator can occur naturally as part of the encoding for 498 | * a character, the read will prematurely end. 499 | **/ 500 | - (void)readDataToData:(NSData *)data withTimeout:(NSTimeInterval)timeout maxLength:(NSUInteger)length tag:(long)tag; 501 | 502 | /** 503 | * Reads bytes until (and including) the passed "data" parameter, which acts as a separator. 504 | * The bytes will be appended to the given byte buffer starting at the given offset. 505 | * The given buffer will automatically be increased in size if needed. 506 | * A maximum of length bytes will be read. 507 | * 508 | * If the timeout value is negative, the read operation will not use a timeout. 509 | * If the buffer if nil, a buffer will automatically be created for you. 510 | * 511 | * If maxLength is zero, no length restriction is enforced. 512 | * Otherwise if maxLength bytes are read without completing the read, 513 | * it is treated similarly to a timeout - the socket is closed with a AsyncSocketReadMaxedOutError. 514 | * The read will complete successfully if exactly maxLength bytes are read and the given data is found at the end. 515 | * 516 | * If you pass a maxLength parameter that is less than the length of the data parameter, 517 | * the method will do nothing, and the delegate will not be called. 518 | * If the bufferOffset is greater than the length of the given buffer, 519 | * the method will do nothing, and the delegate will not be called. 520 | * 521 | * If you pass a buffer, you must not alter it in any way while AsyncSocket is using it. 522 | * After completion, the data returned in onSocket:didReadData:withTag: will be a subset of the given buffer. 523 | * That is, it will reference the bytes that were appended to the given buffer. 524 | * 525 | * To read a line from the socket, use the line separator (e.g. CRLF for HTTP, see below) as the "data" parameter. 526 | * Note that this method is not character-set aware, so if a separator can occur naturally as part of the encoding for 527 | * a character, the read will prematurely end. 528 | **/ 529 | - (void)readDataToData:(NSData *)data 530 | withTimeout:(NSTimeInterval)timeout 531 | buffer:(NSMutableData *)buffer 532 | bufferOffset:(NSUInteger)offset 533 | maxLength:(NSUInteger)length 534 | tag:(long)tag; 535 | 536 | /** 537 | * Writes data to the socket, and calls the delegate when finished. 538 | * 539 | * If you pass in nil or zero-length data, this method does nothing and the delegate will not be called. 540 | * If the timeout value is negative, the write operation will not use a timeout. 541 | **/ 542 | - (void)writeData:(NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)tag; 543 | 544 | /** 545 | * Returns progress of current read or write, from 0.0 to 1.0, or NaN if no read/write (use isnan() to check). 546 | * "tag", "done" and "total" will be filled in if they aren't NULL. 547 | **/ 548 | - (float)progressOfReadReturningTag:(long *)tag bytesDone:(NSUInteger *)done total:(NSUInteger *)total; 549 | - (float)progressOfWriteReturningTag:(long *)tag bytesDone:(NSUInteger *)done total:(NSUInteger *)total; 550 | 551 | /** 552 | * Secures the connection using SSL/TLS. 553 | * 554 | * This method may be called at any time, and the TLS handshake will occur after all pending reads and writes 555 | * are finished. This allows one the option of sending a protocol dependent StartTLS message, and queuing 556 | * the upgrade to TLS at the same time, without having to wait for the write to finish. 557 | * Any reads or writes scheduled after this method is called will occur over the secured connection. 558 | * 559 | * The possible keys and values for the TLS settings are well documented. 560 | * Some possible keys are: 561 | * - kCFStreamSSLLevel 562 | * - kCFStreamSSLAllowsExpiredCertificates 563 | * - kCFStreamSSLAllowsExpiredRoots 564 | * - kCFStreamSSLAllowsAnyRoot 565 | * - kCFStreamSSLValidatesCertificateChain 566 | * - kCFStreamSSLPeerName 567 | * - kCFStreamSSLCertificates 568 | * - kCFStreamSSLIsServer 569 | * 570 | * Please refer to Apple's documentation for associated values, as well as other possible keys. 571 | * 572 | * If you pass in nil or an empty dictionary, the default settings will be used. 573 | * 574 | * The default settings will check to make sure the remote party's certificate is signed by a 575 | * trusted 3rd party certificate agency (e.g. verisign) and that the certificate is not expired. 576 | * However it will not verify the name on the certificate unless you 577 | * give it a name to verify against via the kCFStreamSSLPeerName key. 578 | * The security implications of this are important to understand. 579 | * Imagine you are attempting to create a secure connection to MySecureServer.com, 580 | * but your socket gets directed to MaliciousServer.com because of a hacked DNS server. 581 | * If you simply use the default settings, and MaliciousServer.com has a valid certificate, 582 | * the default settings will not detect any problems since the certificate is valid. 583 | * To properly secure your connection in this particular scenario you 584 | * should set the kCFStreamSSLPeerName property to "MySecureServer.com". 585 | * If you do not know the peer name of the remote host in advance (for example, you're not sure 586 | * if it will be "domain.com" or "www.domain.com"), then you can use the default settings to validate the 587 | * certificate, and then use the X509Certificate class to verify the issuer after the socket has been secured. 588 | * The X509Certificate class is part of the CocoaAsyncSocket open source project. 589 | **/ 590 | - (void)startTLS:(NSDictionary *)tlsSettings; 591 | 592 | /** 593 | * For handling readDataToData requests, data is necessarily read from the socket in small increments. 594 | * The performance can be much improved by allowing AsyncSocket to read larger chunks at a time and 595 | * store any overflow in a small internal buffer. 596 | * This is termed pre-buffering, as some data may be read for you before you ask for it. 597 | * If you use readDataToData a lot, enabling pre-buffering will result in better performance, especially on the iPhone. 598 | * 599 | * The default pre-buffering state is controlled by the DEFAULT_PREBUFFERING definition. 600 | * It is highly recommended one leave this set to YES. 601 | * 602 | * This method exists in case pre-buffering needs to be disabled by default for some unforeseen reason. 603 | * In that case, this method exists to allow one to easily enable pre-buffering when ready. 604 | **/ 605 | - (void)enablePreBuffering; 606 | 607 | /** 608 | * When you create an AsyncSocket, it is added to the runloop of the current thread. 609 | * So for manually created sockets, it is easiest to simply create the socket on the thread you intend to use it. 610 | * 611 | * If a new socket is accepted, the delegate method onSocket:wantsRunLoopForNewSocket: is called to 612 | * allow you to place the socket on a separate thread. This works best in conjunction with a thread pool design. 613 | * 614 | * If, however, you need to move the socket to a separate thread at a later time, this 615 | * method may be used to accomplish the task. 616 | * 617 | * This method must be called from the thread/runloop the socket is currently running on. 618 | * 619 | * Note: After calling this method, all further method calls to this object should be done from the given runloop. 620 | * Also, all delegate calls will be sent on the given runloop. 621 | **/ 622 | - (BOOL)moveToRunLoop:(NSRunLoop *)runLoop; 623 | 624 | /** 625 | * Allows you to configure which run loop modes the socket uses. 626 | * The default set of run loop modes is NSDefaultRunLoopMode. 627 | * 628 | * If you'd like your socket to continue operation during other modes, you may want to add modes such as 629 | * NSModalPanelRunLoopMode or NSEventTrackingRunLoopMode. Or you may simply want to use NSRunLoopCommonModes. 630 | * 631 | * Accepted sockets will automatically inherit the same run loop modes as the listening socket. 632 | * 633 | * Note: NSRunLoopCommonModes is defined in 10.5. For previous versions one can use kCFRunLoopCommonModes. 634 | **/ 635 | - (BOOL)setRunLoopModes:(NSArray *)runLoopModes; 636 | - (BOOL)addRunLoopMode:(NSString *)runLoopMode; 637 | - (BOOL)removeRunLoopMode:(NSString *)runLoopMode; 638 | 639 | /** 640 | * Returns the current run loop modes the AsyncSocket instance is operating in. 641 | * The default set of run loop modes is NSDefaultRunLoopMode. 642 | **/ 643 | - (NSArray *)runLoopModes; 644 | 645 | /** 646 | * In the event of an error, this method may be called during onSocket:willDisconnectWithError: to read 647 | * any data that's left on the socket. 648 | **/ 649 | - (NSData *)unreadData; 650 | 651 | /* A few common line separators, for use with the readDataToData:... methods. */ 652 | + (NSData *)CRLFData; // 0x0D0A 653 | + (NSData *)CRData; // 0x0D 654 | + (NSData *)LFData; // 0x0A 655 | + (NSData *)ZeroData; // 0x00 656 | 657 | @end 658 | --------------------------------------------------------------------------------