Tools.mm 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576
  1. //
  2. // Tools.m
  3. // jiaPei
  4. //
  5. // Created by apple on 16/3/12.
  6. // Copyright © 2016年 JCZ. All rights reserved.
  7. //
  8. #import "Tools.h"
  9. #import "SDSoundPlayer.h"
  10. #import "sys/utsname.h"
  11. //广告标识
  12. #import <AdSupport/ASIdentifierManager.h>
  13. #import <AppTrackingTransparency/AppTrackingTransparency.h>
  14. #import <AdSupport/AdSupport.h>
  15. //获取IP地址
  16. #import <ifaddrs.h>
  17. #import <arpa/inet.h>
  18. @implementation Tools
  19. #pragma mark - 绑定imei判断
  20. +(BOOL)confirmImeiWithLogType:(NSString *)logType successBlock:(void(^)(void))successBlock{
  21. if (defUser.userDict[@"outId"] && [defUser.userDict[@"outId"] length] > 0) {
  22. //存在outID(==“学员”身份证登录 or 已绑定“学员证件号”的手机/qq/wx登录)
  23. //判断是否绑定
  24. NSString *IMEI = defUser.userDict[@"imei"];
  25. if (IMEI && IMEI.length > 0) {
  26. //是否开启iMEi验证
  27. NSInteger isNeed = 1;
  28. for (NSDictionary * dic in defUser.userDict[@"params"]) {
  29. if ([dic[@"KEY"] isEqualToString:@"SP_VERIFY_IMEI"]) {
  30. isNeed = [dic[@"VALUE"] integerValue];
  31. }
  32. }
  33. if (isNeed == 1) {
  34. //判断是否是当前手机
  35. if ([Tools getIDFAWithType:GetIDFAType_Default]) {
  36. if ([IMEI isEqualToString:[Tools getIDFAWithType:GetIDFAType_Default]]) {
  37. if (successBlock) {
  38. successBlock();
  39. return YES;
  40. }
  41. }else{
  42. UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"温馨提示" message:@"您的账号已与其它手机绑定,请使用已绑定该账号的手机继续此操作。如果您中途更换过手机,或使用过手机系统设置里的还原功能,请联系驾校工作人员重新绑定" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil, nil];
  43. [alert show];
  44. }
  45. }
  46. }else{
  47. [Tools saveNotBindImeiLogWithType:logType block:^(BOOL isSuccess) {
  48. }];
  49. if (successBlock) {
  50. successBlock();
  51. return YES;
  52. }
  53. }
  54. }else{
  55. UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"温馨提示" message:@"您的账号暂未与该手机绑定,不能进行此操作,请通过“考试界面左上角点击头像-弹出左边侧栏-绑定账号”进行绑定" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil, nil];
  56. [alert show];
  57. }
  58. }else{
  59. //不存在outID
  60. NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
  61. NSDictionary *udDic = [ud objectForKey:@"jiaPeiLoginTest"];
  62. if ([udDic[@"loginType"] isEqualToString:@"1"]){
  63. UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"温馨提示" message:@"您的账号暂未在计时系统受理,无法计时!" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil, nil];
  64. [alert show];
  65. }else{
  66. UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"温馨提示" message:@"您的账号暂未与该手机绑定,不能进行此操作,请通过“考试界面左上角点击头像-弹出左边侧栏-绑定账号”进行绑定" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil, nil];
  67. [alert show];
  68. }
  69. }
  70. return NO;
  71. }
  72. #pragma mark - 保存非绑定IMEI操作日志
  73. +(void)saveNotBindImeiLogWithType:(NSString *)type block:(void (^)(BOOL isSuccess))block{
  74. NSMutableArray *arr=[NSMutableArray array];
  75. [arr addPro:@"dqbh" Value:defUser.userDict[@"city"]];
  76. [arr addPro:@"idcard" Value:defUser.sfzmhm];
  77. [arr addPro:@"cx" Value:defUser.userDict[@"carType"]];
  78. [arr addPro:@"type" Value:type];//操作类型(1理论设备扫码,2远程计时,3模拟终端,4大车)

  79. [arr addPro:@"bindImei" Value:defUser.userDict[@"imei"]];
  80. [arr addPro:@"kind" Value:@"2"];
  81. /// @RQ-MARK 1.0.6: 判断imei 和 bindImei 是否相同 不同则保存新的imei
  82. if ([Tools getIDFAWithType:GetIDFAType_Default]) {
  83. block(true);
  84. if ([[Tools getIDFAWithType:GetIDFAType_Default] isEqualToString:defUser.userDict[@"imei"]]) {
  85. return;
  86. } else {
  87. [arr addPro:@"imei" Value:[Tools getIDFAWithType:GetIDFAType_Default]];
  88. }
  89. } else {
  90. block(false);
  91. NSLog(@"IDFA未授权");
  92. return;
  93. }
  94. NSString* method = @"saveNotBindImeiLog";
  95. [jiaPeiManager requestAnythingWithURL:method array:arr data:nil completion:^(NSDictionary * root) {
  96. }];
  97. }
  98. #pragma mark - iphoneX验证
  99. + (BOOL)isIPhoneX {
  100. struct utsname systemInfo;
  101. uname(&systemInfo);
  102. NSString *platform = [NSString stringWithCString:systemInfo.machine encoding:NSASCIIStringEncoding];
  103. if ([platform isEqualToString:@"i386"] || [platform isEqualToString:@"x86_64"]) {
  104. // 模拟器下采用屏幕的高度来判断
  105. return [UIScreen mainScreen].bounds.size.height == 812;
  106. }
  107. // iPhone10,6是美版iPhoneX 感谢hegelsu指出:https://github.com/banchichen/TZImagePickerController/issues/635
  108. BOOL isIPhoneX = [platform isEqualToString:@"iPhone10,3"] || [platform isEqualToString:@"iPhone10,6"];
  109. return isIPhoneX;
  110. }
  111. + (NSString *)getPathWithFileName:(NSString *)fileName
  112. {
  113. NSString *document = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
  114. NSString *filePath = [document stringByAppendingPathComponent:fileName];
  115. return filePath;
  116. }
  117. + (NSString *)isWan:(NSString *)string
  118. {
  119. NSString *newString = string;
  120. if (string.length > 4) {
  121. newString = [NSString stringWithFormat:@"%@.%@万",[string substringToIndex:string.length - 4],[string substringWithRange:NSMakeRange(string.length - 4, 1)]];
  122. }
  123. return newString;
  124. }
  125. //播报声音
  126. +(void)playAudioWithString:(NSString *)string
  127. {
  128. SDSoundPlayer *player = [SDSoundPlayer SDSoundPlayerInit];
  129. [player setDefaultWithVolume:-1.0 rate:0.5 pitchMultiplier:1.2];
  130. [player play:string];
  131. }
  132. //验证是否是电话号码
  133. + (BOOL)isMobileNumber:(NSString *)mobileNum
  134. {
  135. // 电信号段:133/153/180/181/189/177
  136. // 联通号段:130/131/132/155/156/185/186/145/176
  137. // 移动号段:134/135/136/137/138/139/150/151/152/157/158/159/182/183/184/187/188/147/178
  138. // 虚拟运营商:170
  139. NSString *MOBILE = @"^1(3[0-9]|4[57]|5[0-35-9]|8[0-9]|7[06-8])\\d{8}$";
  140. NSPredicate *regextestmobile = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", MOBILE];
  141. return [regextestmobile evaluateWithObject:mobileNum];
  142. }
  143. //汉字转拼音
  144. + (NSString *)pinYinFromChinese:(NSString *)chinese
  145. {
  146. if (chinese.length < 1) {
  147. return @"";
  148. }
  149. return [ChineseToPinyin pinyinFromChiniseString:chinese];
  150. }
  151. //根据图片二进制流获取图片格式
  152. + (NSString *)typeForImageData:(NSData *)data {
  153. uint8_t c;
  154. [data getBytes:&c length:1];
  155. switch (c) {
  156. case 0xFF:
  157. return @"jpeg";
  158. case 0x89:
  159. return @"png";
  160. case 0x47:
  161. return @"gif";
  162. case 0x49:
  163. case 0x4D:
  164. return @"tiff";
  165. }
  166. return @"jpg";
  167. }
  168. //烦烦烦 每次返回的都不一样 这里给个方法 解决图片的问题 优先显示photo
  169. + (NSString *)imageStringWithPhotoString:(NSString *)firstString HeadImgString:(NSString *)secondString Type:(NSInteger)type
  170. {
  171. NSString *imgString = @"";
  172. if (type == 1) {
  173. imgString = firstString;
  174. if (imgString && imgString.length > 0) {
  175. NSString *photoString = @"http://fj.jppt.com.cn";
  176. if (imgString && ![imgString hasPrefix:@"http"]){
  177. imgString = [photoString stringByAppendingString:imgString];
  178. }
  179. }else{
  180. imgString = secondString;
  181. if (imgString && ![imgString hasPrefix:@"http"]){
  182. imgString = [imgPreFix stringByAppendingString:imgString];
  183. }
  184. }
  185. }else{
  186. imgString = secondString;
  187. if (imgString && imgString.length > 0) {
  188. if (imgString && ![imgString hasPrefix:@"http"]){
  189. imgString = [imgPreFix stringByAppendingString:imgString];
  190. }
  191. }else{
  192. imgString = firstString;
  193. NSString *photoString = @"http://fj.jppt.com.cn";
  194. if (imgString && ![imgString hasPrefix:@"http"]){
  195. imgString = [photoString stringByAppendingString:imgString];
  196. }
  197. }
  198. }
  199. if (!imgString) {
  200. imgString = @"";
  201. }
  202. return imgString;
  203. }
  204. + (UIImage *)watermarkImage:(UIImage *)img withDic:(NSDictionary *)dic
  205. {
  206. NSString *mark = @"";
  207. int w = img.size.width;
  208. int h = img.size.height;
  209. UIGraphicsBeginImageContext(img.size);
  210. [img drawInRect:CGRectMake(0, 0, w, h)];
  211. NSDictionary *attr = @{
  212. NSFontAttributeName: [UIFont boldSystemFontOfSize:16], //设置字体
  213. NSForegroundColorAttributeName : [UIColor redColor] //设置字体颜色
  214. };
  215. mark = dic[@"up1"];
  216. [mark drawInRect:CGRectMake(10, 10, 200, 20) withAttributes:attr]; //上一
  217. mark = dic[@"up2"];
  218. [mark drawInRect:CGRectMake(10, 35, 200, 20) withAttributes:attr]; //上二
  219. mark = dic[@"down1"];
  220. [mark drawInRect:CGRectMake(w - 170, h - 80 , 170, 20) withAttributes:attr]; //下一
  221. mark = dic[@"down2"];
  222. [mark drawInRect:CGRectMake(w - 170, h - 55 , 170, 20) withAttributes:attr]; //下二
  223. mark = dic[@"down3"];
  224. [mark drawInRect:CGRectMake(w - 170, h - 30 , 170, 20) withAttributes:attr]; //下三
  225. UIImage *aimg = UIGraphicsGetImageFromCurrentImageContext();
  226. UIGraphicsEndImageContext();
  227. return aimg;
  228. }
  229. //获取ip地址
  230. + (NSString *)getIpAddresses
  231. {
  232. NSString *address = @"error";
  233. struct ifaddrs *interfaces = NULL;
  234. struct ifaddrs *temp_addr = NULL;
  235. int success = 0;
  236. // retrieve the current interfaces - returns 0 on success
  237. success = getifaddrs(&interfaces);
  238. if (success == 0)
  239. {
  240. // Loop through linked list of interfaces
  241. temp_addr = interfaces;
  242. while(temp_addr != NULL)
  243. {
  244. if(temp_addr->ifa_addr->sa_family == AF_INET)
  245. {
  246. // Check if interface is en0 which is the wifi connection on the iPhone
  247. if([[NSString stringWithUTF8String:temp_addr->ifa_name] isEqualToString:@"en0"])
  248. {
  249. // Get NSString from C String
  250. address = [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr)];
  251. }
  252. }
  253. temp_addr = temp_addr->ifa_next;
  254. }
  255. }
  256. // Free memory
  257. freeifaddrs(interfaces);
  258. return address;
  259. }
  260. //获取IDFV
  261. + (NSString *)getIDFAWithType:(GetIDFAType)type
  262. {
  263. //这里复制的时候忘记改一个独立于其它app的key了 暂时未有什么影响。 中途要改的话 得考虑以前的用户
  264. NSString * const KEY_USERNAME_PASSWORD = @"com.danson.jiaPeiCo.usernamepassword";
  265. NSString * const KEY_PASSWORD = @"com.danson.jiaPeiCo.password";
  266. //测试用 清除keychain中的内容
  267. // [Tools delete:KEY_USERNAME_PASSWORD];
  268. NSMutableDictionary *readUserPwd = (NSMutableDictionary *)[Tools load:KEY_USERNAME_PASSWORD];
  269. //NSLog(@"keychain------><>%@",readUserPwd);
  270. if (!readUserPwd) {
  271. //如果为空 说明是第一次安装 做存储操作
  272. /*
  273. 仅在第一次装app的时候获取。并存储下来。
  274. */
  275. //IDFV
  276. // NSString *identifierStr = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
  277. // NSMutableDictionary *usernamepasswordKVPairs = [NSMutableDictionary dictionaryWithObject:identifierStr forKey:KEY_PASSWORD];
  278. // [Tools save:KEY_USERNAME_PASSWORD data:usernamepasswordKVPairs];
  279. // return identifierStr;
  280. //IDFA
  281. NSString *adId = [XYUUID uuidForDevice];
  282. // if (@available(iOS 14, *)) {
  283. // [ATTrackingManager requestTrackingAuthorizationWithCompletionHandler:^(ATTrackingManagerAuthorizationStatus status) {
  284. // if (status == ATTrackingManagerAuthorizationStatusAuthorized) {
  285. // adId = [[ASIdentifierManager sharedManager] advertisingIdentifier].UUIDString;
  286. // }
  287. // }];
  288. // } else {
  289. // // 使用原方式访问 IDFA
  290. // adId = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
  291. // }
  292. if (!adId) {
  293. return nil;
  294. } else {
  295. if ([adId isEqualToString:@"00000000-0000-0000-0000-000000000000"] || [adId isEqualToString:@"00000000000000000000000000000000"]) {
  296. [RQ_SHARE_FUNCTION showAlertWithTitle:@"温馨提示" message:@"获取广告标识失败,请在“设置-隐私-广告”中,关闭“限制广告跟踪”" alertControllerStyle:UIAlertControllerStyleAlert cancelButtonTitle:@"确定" otherButtonTitles:nil otherButtonStyles:nil completion:nil];
  297. return nil;
  298. } else {
  299. NSMutableDictionary *usernamepasswordKVPairs = [NSMutableDictionary dictionaryWithObject:adId forKey:KEY_PASSWORD];
  300. [Tools save:KEY_USERNAME_PASSWORD data:usernamepasswordKVPairs];
  301. return adId;
  302. }
  303. }
  304. }else{
  305. NSString *theIdfv = [readUserPwd objectForKey:KEY_PASSWORD];
  306. return theIdfv;
  307. }
  308. }
  309. //存
  310. + (void)save:(NSString *)service data:(id)data {
  311. //Get search dictionary
  312. NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
  313. //Delete old item before add new item
  314. SecItemDelete((__bridge CFDictionaryRef)keychainQuery);
  315. //Add new object to search dictionary(Attention:the data format)
  316. [keychainQuery setObject:[NSKeyedArchiver archivedDataWithRootObject:data] forKey:(__bridge id)kSecValueData];
  317. //Add item to keychain with the search dictionary
  318. SecItemAdd((__bridge CFDictionaryRef)keychainQuery, NULL);
  319. }
  320. + (NSMutableDictionary *)getKeychainQuery:(NSString *)service {
  321. return [NSMutableDictionary dictionaryWithObjectsAndKeys:
  322. (__bridge id)kSecClassGenericPassword,(__bridge id)kSecClass,
  323. service, (__bridge id)kSecAttrService,
  324. service, (__bridge id)kSecAttrAccount,
  325. (__bridge id)kSecAttrAccessibleAfterFirstUnlock,(__bridge id)kSecAttrAccessible,
  326. nil];
  327. }
  328. //取
  329. + (id)load:(NSString *)service {
  330. id ret = nil;
  331. NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
  332. //Configure the search setting
  333. //Since in our simple case we are expecting only a single attribute to be returned (the password) we can set the attribute kSecReturnData to kCFBooleanTrue
  334. [keychainQuery setObject:(__bridge id)kCFBooleanTrue forKey:(__bridge id)kSecReturnData];
  335. [keychainQuery setObject:(__bridge id)kSecMatchLimitOne forKey:(__bridge id)kSecMatchLimit];
  336. CFDataRef keyData = NULL;
  337. if (SecItemCopyMatching((__bridge CFDictionaryRef)keychainQuery, (CFTypeRef *)&keyData) == noErr) {
  338. @try {
  339. ret = [NSKeyedUnarchiver unarchiveObjectWithData:(__bridge NSData *)keyData];
  340. } @catch (NSException *e) {
  341. NSLog(@"Unarchive of %@ failed: %@", service, e);
  342. } @finally {
  343. }
  344. }
  345. if (keyData)
  346. CFRelease(keyData);
  347. return ret;
  348. }
  349. //删除
  350. + (void)delete:(NSString *)service {
  351. NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
  352. SecItemDelete((__bridge CFDictionaryRef)keychainQuery);
  353. }
  354. #pragma mark 16进制与NSData之间的转化 及验证算法计算
  355. //data转换为16进制
  356. + (NSString *)convertDataToHexStr:(NSData *)data {
  357. if (!data || [data length] == 0) {
  358. return @"";
  359. }
  360. NSMutableString *string = [[NSMutableString alloc] initWithCapacity:[data length]];
  361. [data enumerateByteRangesUsingBlock:^(const void *bytes, NSRange byteRange, BOOL *stop) {
  362. unsigned char *dataBytes = (unsigned char*)bytes;
  363. for (NSInteger i = 0; i < byteRange.length; i++) {
  364. NSString *hexStr = [NSString stringWithFormat:@"%x", (dataBytes[i]) & 0xff];
  365. if ([hexStr length] == 2) {
  366. [string appendString:hexStr];
  367. } else {
  368. [string appendFormat:@"0%@", hexStr];
  369. }
  370. }
  371. }];
  372. return string;
  373. }
  374. //16进制转换为data
  375. + (NSData *)convertHexStrToData:(NSString *)str {
  376. if (!str || [str length] == 0) {
  377. return nil;
  378. }
  379. NSMutableData *hexData = [[NSMutableData alloc] initWithCapacity:8];
  380. NSRange range;
  381. if ([str length] % 2 == 0) {
  382. range = NSMakeRange(0, 2);
  383. } else {
  384. range = NSMakeRange(0, 1);
  385. }
  386. for (NSInteger i = range.location; i < [str length]; i += 2) {
  387. unsigned int anInt;
  388. NSString *hexCharStr = [str substringWithRange:range];
  389. NSScanner *scanner = [[NSScanner alloc] initWithString:hexCharStr];
  390. [scanner scanHexInt:&anInt];
  391. NSData *entity = [[NSData alloc] initWithBytes:&anInt length:1];
  392. [hexData appendData:entity];
  393. range.location += range.length;
  394. range.length = 2;
  395. }
  396. return hexData;
  397. }
  398. /**
  399. 将原本是16进制数字的字符串转换成计算机可以识别的int型10进制数据
  400. */
  401. + (int)getHexNumWithString:(NSString *)string {
  402. int number = 0;
  403. for (int i = 0; i < string.length; i ++) {
  404. NSString *letterOrNumber = [string substringWithRange:NSMakeRange(string.length - i - 1, 1)];
  405. int a = 0;
  406. if ([letterOrNumber isEqualToString:@"a"] || [letterOrNumber isEqualToString:@"A"]) {
  407. a = 10;
  408. }else if ([letterOrNumber isEqualToString:@"b"] || [letterOrNumber isEqualToString:@"B"]){
  409. a = 11;
  410. }else if ([letterOrNumber isEqualToString:@"c"] || [letterOrNumber isEqualToString:@"C"]){
  411. a = 12;
  412. }else if ([letterOrNumber isEqualToString:@"d"] || [letterOrNumber isEqualToString:@"D"]){
  413. a = 13;
  414. }else if ([letterOrNumber isEqualToString:@"e"] || [letterOrNumber isEqualToString:@"E"]){
  415. a = 14;
  416. }else if ([letterOrNumber isEqualToString:@"f"] || [letterOrNumber isEqualToString:@"F"]){
  417. a = 15;
  418. }else {
  419. a = [letterOrNumber intValue];
  420. }
  421. a = a * pow(16, i);
  422. number += a;
  423. }
  424. return number;
  425. }
  426. //将十六进制的字符串转换成NSString则可使用如下方式
  427. + (NSString *)convertHexStrToString:(NSString *)str {
  428. if (!str || [str length] == 0) {
  429. return nil;
  430. }
  431. NSMutableData *hexData = [[NSMutableData alloc] initWithCapacity:8];
  432. NSRange range;
  433. if ([str length] % 2 == 0) {
  434. range = NSMakeRange(0, 2);
  435. } else {
  436. range = NSMakeRange(0, 1);
  437. }
  438. for (NSInteger i = range.location; i < [str length]; i += 2) {
  439. unsigned int anInt;
  440. NSString *hexCharStr = [str substringWithRange:range];
  441. NSScanner *scanner = [[NSScanner alloc] initWithString:hexCharStr];
  442. [scanner scanHexInt:&anInt];
  443. NSData *entity = [[NSData alloc] initWithBytes:&anInt length:1];
  444. [hexData appendData:entity];
  445. range.location += range.length;
  446. range.length = 2;
  447. }
  448. NSString *string = [[NSString alloc]initWithData:hexData encoding:NSUTF8StringEncoding];
  449. return string;
  450. }
  451. //将NSString转换成十六进制的字符串则可使用如下方式
  452. + (NSString *)convertStringToHexStr:(NSString *)str {
  453. if (!str || [str length] == 0) {
  454. return @"";
  455. }
  456. NSData *data = [str dataUsingEncoding:NSUTF8StringEncoding];
  457. NSMutableString *string = [[NSMutableString alloc] initWithCapacity:[data length]];
  458. [data enumerateByteRangesUsingBlock:^(const void *bytes, NSRange byteRange, BOOL *stop) {
  459. unsigned char *dataBytes = (unsigned char*)bytes;
  460. for (NSInteger i = 0; i < byteRange.length; i++) {
  461. NSString *hexStr = [NSString stringWithFormat:@"%x", (dataBytes[i]) & 0xff];
  462. if ([hexStr length] == 2) {
  463. [string appendString:hexStr];
  464. } else {
  465. [string appendFormat:@"0%@", hexStr];
  466. }
  467. }
  468. }];
  469. return string;
  470. }
  471. @end