首页 文章 精选 留言 我的

精选列表

搜索[ios],共10000篇文章
优秀的个人博客,低调大师

iOS安全–IOS应用调试检测以及反调试

一、检测调试 当一个应用被调试的时候,会给进程设置一个标识(P_TRACED),我们可以通过检测该进程是否有设置这个标识来检测进程是否正在被调试以保护好我们的应用。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 #include <sys/types.h>#include <sys/sysctl.h>staticintcheck_debugger()__attribute__((always_inline));intcheck_debugger(){ size_tsize=sizeof(structkinfo_proc); structkinfo_proc info; intret,name[4]; memset(&info,0,sizeof(structkinfo_proc)); name[0]=CTL_KERN; name[1]=KERN_PROC; name[2]=KERN_PROC_PID; name[3]=getpid(); if((ret=(sysctl(name,4,&info,&size,NULL,0)))){ returnret;//sysctl() failed for some reason } return(info.kp_proc.p_flag&P_TRACED)?1:0;} 为了让这个函数以inline方式编译,需要设置编译器的优化选项,-0z(函数以inline方式编译),-fast(加快编译速度)。 如果你不确信产生的目标代码以inline的方式编译该函数,你也可以将其转化成宏的方式。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 #define DEBUGGER_CHECK { \ size_t size = sizeof(struct kinfo_proc); \ struct kinfo_proc info; \ int ret,name[4]; \ \ memset(&info, 0, sizeof(struct kinfo_proc)); \ \ name[0] = CTL_KERN; \ name[1] = KERN_PROC; \ name[2] = KERN_PROC_PID; \ name[3] = getpid(); \ \ if(ret = (sysctl(name, 4, &info, &size, NULL, 0))){ \ return (EXIT_FAILURE); \ } \ \ if(info.kp_proc.p_flag & P_TRACED){ \ /* Code to react to debugging goes here */ \ } \ } 当前该方法只能检测debugger或dtrace的调试,而不能阻止非法代码注入或者cycript依附。 二、阻止调试 调用ptrace设置参数PT_DENY_ATTACH,如果有调试器依附,则会产生错误并退出。关于PT_DENY_ATTACH的说明如下: 这时再使用gdb attach的话会产生错误: Segmentation fault: 11 或者使用gdb run该应用也会产生错误: Program exited with code 055. Mac OS X系统中,可以这样使用: 1 2 3 4 5 #include <sys/ptrace.h>intmain(){ ptrace(PT_DENY_ATTACH,0,0,0); ...} 但是在IPhone中,<sys/ptrace>是不可用的,所以我们可以用下面的方式来代替: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 #import <dlfcn.h>#import <sys/types.h>typedefint(*ptrace_ptr_t)(int_request,pid_t _pid,caddr_t _addr,int_data);#if !defined(PT_DENY_ATTACH)#define PT_DENY_ATTACH 31#endif // !defined(PT_DENY_ATTACH)voiddisable_gdb(){ void*handle=dlopen(0,RTLD_GLOBAL|RTLD_NOW); ptrace_ptr_t ptrace_ptr=dlsym(handle,"ptrace"); ptrace_ptr(PT_DENY_ATTACH,0,0,0); dlclose(handle);} 当然该方法也会被调试者下断点的方式来动态绕过或者使用IDA等反汇编工具打补丁绕过,所以我们应该在程序的多处地方调用该方式。 本文链接:http://www.blogfshare.com/ioss-check-debug.html 本文转自ljianbing51CTO博客,原文链接:http://blog.51cto.com/ljianbing/1876332,如需转载请自行联系原作者

优秀的个人博客,低调大师

iOS: 如何获取ios设备的当前IP地址

有的时候,我们项目上线后,需要根据ip地址去统计不同地区的用户情况,此时IP地址的收取显得尤其重要,一般情况下,在用户登录时去获取用户的ip是准确的,当然实时追踪ip的变化而统计是更安全可靠的。 ip地址长度现在是有区别的,分为IPv4和IPv6.IPv4地址是类似 A.B.C.D 的格式,它是32位,用\".\"分成四段,用10进制表示;而IPv6地址类似X:X:X:X:X:X:X:X的格式,它是128位的,用\":\"分成8段,用16进制表示;可见,IPv6地址空间相对于IPv4地址有了极大的扩充。 IPv4是32位地址长度 IPv6是128位地址长度 下面有两个方法,可供使用,如下: 方法一:使用一套C的方法去获取IP地址 IPAddress.h:声明文件 View Code IPAddress.c:实现文件 View Code 将头文件导入ViewController.m中进行测试 View Code 测试结果: 模拟器上连接wifi: 2016-07-15 16:19:49.187 IP_Test[5674:205359] Name: lo0 MAC: 00:00:00:00:00:00 IP: 127.0.0.1 2016-07-15 16:19:49.187 IP_Test[5674:205359] Name: en1 MAC: BC:54:36:CC:9C:96 IP: 192.168.0.109 iphone上: 连接wifi时: 2016-07-15 17:32:08.884 IP_Test[4813:2032752] Name: lo0 MAC: 00:00:00:00:00:00 IP: 127.0.0.1 2016-07-15 17:32:08.885 IP_Test[4813:2032752] Name: pdp_ip0 MAC: 00:00:00:00:00:70 IP: 10.204.102.136 2016-07-15 17:32:08.885 IP_Test[4813:2032752] Name: en0 MAC: 02:00:00:00:00:00 IP: 192.168.0.111 使用4G时: 2016-07-15 17:32:44.163 IP_Test[4817:2033214] Name: lo0 MAC: 00:00:00:00:00:00 IP: 127.0.0.1 2016-07-15 17:32:44.164 IP_Test[4817:2033214] Name: pdp_ip0 MAC: 00:00:00:00:00:70 IP: 10.204.102.136 方法二:使用一套OC的方法去获取IP地址,该方法简单,能实时监测IP地址的变化 stackoverflow参考地址为:http://stackoverflow.com/questions/7072989/iphone-ipad-how-to-get-my-ip-address-programmatically View Code 测试结果: 模拟器上连接wifi: 2016-07-15 16:23:35.864 IP_Test[5718:207702] { "awdl0/ipv6" = "fe80::e863:edff:fe93:a1c2"; "en1/ipv4" = "192.168.0.109"; "en1/ipv6" = "fe80::be54:36ff:fecc:9c96"; "lo0/ipv4" = "127.0.0.1"; "lo0/ipv6" = "fe80::1"; } 2016-07-15 17:24:12.877 IP_Test[4796:2028704] 0.0.0.0 iphone上: 连接wifi时: 2016-07-15 17:29:22.526 IP_Test[4807:2031207] addresses: { "awdl0/ipv6" = "fe80::6c6a:24ff:fe91:39f7"; "en0/ipv4" = "192.168.0.111"; "en0/ipv6" = "fe80::42d:42b4:82a7:3de8"; "lo0/ipv4" = "127.0.0.1"; "lo0/ipv6" = "fe80::1"; "pdp_ip0/ipv4" = "10.204.102.136"; } 2016-07-15 17:29:22.527 IP_Test[4807:2031207] 192.168.0.111 使用4G时: 2016-07-15 17:24:12.875 IP_Test[4796:2028704] addresses: { "lo0/ipv4" = "127.0.0.1"; "lo0/ipv6" = "fe80::1"; "pdp_ip0/ipv4" = "10.204.102.136"; } 2016-07-15 17:24:12.877 IP_Test[4796:2028704] 10.204.102.136 温馨提示:本人进一步做了简单的封装,封装成工具库,支持CocoaPods下载,源码在github上,欢迎大家下载,如果对您有帮助,请给我一个star吧 CocoaPods:pod 'IPTool','~> 1.0.0' Github:https://github.com/xiayuanquan/IP_Test 程序猿神奇的手,每时每刻,这双手都在改变着世界的交互方式! 本文转自当天真遇到现实博客园博客,原文链接:http://www.cnblogs.com/XYQ-208910/p/5674063.html ,如需转载请自行联系原作者

优秀的个人博客,低调大师

iOS Bluetooth(蓝牙)

1. 蓝牙发送照片 #import "ViewController.h" #import <GameKit/GameKit.h> @interface ViewController ()<UINavigationControllerDelegate, UIImagePickerControllerDelegate, GKPeerPickerControllerDelegate> @property (weak, nonatomic) IBOutlet UIImageView *imageView; /** 会话类*/ @property (nonatomic, strong) GKSession *session; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. } #pragma mark 连接设备 - (IBAction)connectClick:(id)sender { //1. 创建GKPeerPickerController连接控制器 GKPeerPickerController * picker = [GKPeerPickerController new]; //2. 设置代理 --> 获取数据 picker.delegate = self; //3. 显示控制器 --> show 此控制器和AlertView很像, 不是全屏的, 不用push modal [picker show]; } #pragma mark GKPeerPickerController 代理方法 /** 此方法在连接到另一台设备时, 会调用 peerID: 另一台设备的ID session: 会话类, 用于接收和发送数据 */ - (void)peerPickerController:(GKPeerPickerController *)picker didConnectPeer:(NSString *)peerID toSession:(GKSession *)session { //1. 保留session self.session = session; //2. 设置句柄 (设置代理) --> 将来一旦受到数据, 将由句柄的方法来处理数据 // 一旦设置了句柄, 那么还需要实现另一个方法 [self.session setDataReceiveHandler:self withContext:nil]; //3. 消失控制器 [picker dismiss]; } // 一旦设置了句柄, 还需要实现此方法 #pragma mark 接收到数据的时候, 会调用此方法来处理 - (void)receiveData:(NSData *)data fromPeer:(NSString *)peer inSession: (GKSession *)session context:(void *)context { //1. 将Data转换成image对象 UIImage *image = [UIImage imageWithData:data]; //2. 然后设置到界面上 self.imageView.image = image; } #pragma mark 发送照片方法 - (IBAction)sendPhotoClick:(id)sender { //1. 将image转换成Data NSData *data = UIImageJPEGRepresentation(self.imageView.image, 0.5); //2. 使用会话类发送数据 /** GKSendDataReliable, 如果发送失败, 会重新发送, 直到成功 GKSendDataUnreliable, 发送一次就不管了 */ [self.session sendDataToAllPeers:data withDataMode:GKSendDataReliable error:nil]; } #pragma mark 选择照片 - (IBAction)selectPhontoClick:(id)sender { //1. 判断是否可用 if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]) { return; } //2. 创建UIImagePickerController UIImagePickerController *picker = [UIImagePickerController new]; //3. 设置类型 picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary; //4. 设置代理 picker.delegate = self; //5. 模态视图弹出 [self presentViewController:picker animated:YES completion:nil]; } #pragma mark UIImagePickerController 代理方法 - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info { //1. 获取照片并显示到界面上 self.imageView.image = info[UIImagePickerControllerOriginalImage]; //2. 关闭控制器 [picker dismissViewControllerAnimated:YES completion:nil]; } @end 2. CoreBluetooth #import "ViewController.h" #import <CoreBluetooth/CoreBluetooth.h> @interface ViewController ()<CBCentralManagerDelegate, CBPeripheralDelegate> /** 中央管理者*/ @property (nonatomic, strong) CBCentralManager *mgr; /** 扫描到的外围设备的数据数组*/ @property (nonatomic, strong) NSMutableArray *peripheralArray; @end @implementation ViewController - (NSMutableArray *)peripheralArray { if (_peripheralArray == nil) { _peripheralArray = [NSMutableArray array]; } return _peripheralArray; } - (void)viewDidLoad { [super viewDidLoad]; //1. 建立中央管理者 //queue: 如果传空, 就代表着在主队列 self.mgr = [[CBCentralManager alloc] initWithDelegate:self queue:nil]; //2. 扫描周边设备 //Services: 是服务的UUID, 而且是个数据. 如果不穿, 默认扫描全部服务 [self.mgr scanForPeripheralsWithServices:nil options:nil]; } #pragma mark - CBCentralManager 代理方法 #pragma mark 必须调用的代理方法 - (void)centralManagerDidUpdateState:(CBCentralManager *)central { NSLog(@"state: %zd",central.state); } #pragma mark 当发现外围设备时, 会调用的方法 /** Peripheral: 外围设备 Data : 相关的数据 RSSI : 信号强度 */ - (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *,id> *)advertisementData RSSI:(NSNumber *)RSSI { //3. 记录扫描到的设备 if (![self.peripheralArray containsObject:peripheral]) { [self.peripheralArray addObject:peripheral]; } // 隐藏的步骤: 你应该搞一个列表给用户选择, 让用户自己选择要连接到哪一个设备 } #pragma mark 连接扫描到的设备 --> 此方法是咱们自己写的, 用户当选中了设备时,应该调用此方法 - (void)connectPeripheral:(CBPeripheral *)peripheral { //4. 连接外围设备 [self.mgr connectPeripheral:peripheral options:nil]; } #pragma mark 此方法是连接到外设时会调用的代理方法 - (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral { #warning //5. 设置外围设备的代理 --> 一旦连接外设, 那么将有外设来管理服务和特征的处理 peripheral.delegate = self; //6. 扫描服务 --> 可以传入UUID // 传空, 代表扫描所有服务 [peripheral discoverServices:nil]; } #pragma mark 外设的代理方法 当发现到服务的时候会调用 - (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error { //7. 获取指定的服务, 然后根据此服务来查找特征 //services : 外设的所有服务, 会保存在一个services中 for (CBService *service in peripheral.services) { //加入我们的服务的UUID是 "123" if ([service.UUID.UUIDString isEqualToString:@"123"]) { //如果UUID一致, 则开始扫描特征 [peripheral discoverCharacteristics:nil forService:service]; } } } #pragma mark 外设的代理方法 当发现到特征的时候会调用 - (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error { //8. 获取指定的特征, 然后根据此特征, 才能根据自己的需求进行数据交互处理 //char<#(nonnull CBCharacteristic *)#>acteristics : 服务的数组中, 会包含在一个characteristics的数组 for (CBCharacteristic *characteristic in service.characteristics) { //假如我们的特征的UUID是 "456" if ([characteristic.UUID.UUIDString isEqualToString:@"456"]) { // 如果获取到了指定的特征, 则可以进行数据交互处理 //[peripheral readValueForCharacteristic:characteristic]; // peripheral writeValue:<#(nonnull NSData *)#> forCharacteristic: type:<#(CBCharacteristicWriteType)#> } } // } #pragma mark 断开连接 - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; //9. 断开连接 [self.mgr stopScan]; } @end

优秀的个人博客,低调大师

iOS Spin(换肤)

MTSkinTools.h #import <UIKit/UIKit.h> //专门写常量值的 // 以下的格式, 只是对常量的声明 //extern: 代表其他类可以引用 extern NSString *const MTSkinToolLabelTextDayColor; extern NSString *const MTSkinToolLabelBackgroundDayColor; @interface MTSkinTools : NSObject /** 返回对应的皮肤的图像*/ + (UIImage *)imageWithImageName:(NSString *)imageName; /** 保存皮肤信息*/ + (void)saveSkinName:(NSString *)skinName; /** 返回制定标识符所对应的颜色*/ + (UIColor *)colorWithName:(NSString *)name; @end MTSkinTools.m #import "MTSkinTools.h" //专门写常量值的 // 以下的格式, 只是对常量的声明 NSString *const MTSkinToolLabelTextDayColor = @"labelTextDayColor"; NSString *const MTSkinToolLabelBackgroundDayColor = @"labelBackgroundDayColor"; static NSString *_skinName; //#1. 创建一个static的可变字典 static NSMutableDictionary *_colorDict; @implementation MTSkinTools /** 保证代码只加载一次: 1. 多线程 --> dispatchOnce 2. 只调用一次的方法 */ /** load方法, 只要头文件参与了编译就会调用此方法 */ + (void)load { NSLog(@"%s",__func__); } /** 类的实例创建时, 才会调用此方法*/ + (void)initialize { //1. 读取偏好设置信息 --> 访问磁盘是耗性能的, 所以只需要加载一次即可 _skinName = [[NSUserDefaults standardUserDefaults] objectForKey:@"skinName"]; if (_skinName == nil) { _skinName = @"green"; } //#2. 可变字典做初始化 _colorDict = [NSMutableDictionary dictionary]; //#3. 加载颜色plist [self loadColorDict]; } /** 返回对应的皮肤的图像*/ + (UIImage *)imageWithImageName:(NSString *)imageName { //1. 拼接文件路径 NSString *imageStr = [NSString stringWithFormat:@"skin/%@/%@",_skinName,imageName]; //2. 返回一个指定的图像 return [UIImage imageNamed:imageStr]; } /** 保存皮肤信息*/ + (void)saveSkinName:(NSString *)skinName { //当皮肤读取改变成一次之后, 那么我们做皮肤切换保存操作, 原来的_skinName //更改皮肤 _skinName = skinName; // 当设置了不同皮肤时, 我们还需要将皮肤plist颜色信息进行重新加载 [self loadColorDict]; //保存皮肤 [[NSUserDefaults standardUserDefaults] setObject:skinName forKey:@"skinName"]; [[NSUserDefaults standardUserDefaults] synchronize]; } /** 返回制定标识符所对应的颜色*/ + (UIColor *)colorWithName:(NSString *)name { return _colorDict[name]; } /** 初始化时需要调用一次, 来加载字典及转换颜色*/ + (void)loadColorDict { //1. 获取plist列表 //2. 颜色转换(255,0,0,1 --> UIColor对象) //1. plist只需要加载一次 //2. 将转换后的UIColor做保存 //1. 获取plist路径 NSString *pathStr = [NSString stringWithFormat:@"skin/%@/SkinColors.plist",_skinName]; NSString *path = [[NSBundle mainBundle] pathForResource:pathStr ofType:nil]; //2. 获取字典 NSDictionary *colorDict = [NSDictionary dictionaryWithContentsOfFile:path]; //3. 直接获取所有颜色值将其转换成UIColor对象 [colorDict enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull colorStr, BOOL * _Nonnull stop) { //4. 截取字符串 NSArray *colorArr = [colorStr componentsSeparatedByString:@","]; //5. 创建颜色赋值给缓存字典 CGFloat r = [colorArr[0] doubleValue]; CGFloat g = [colorArr[1] doubleValue]; CGFloat b = [colorArr[2] doubleValue]; CGFloat a = [colorArr[3] doubleValue]; //字典的里面存的是转换好的UIColor对象, 当设置切换皮肤后, 需要重新调用此方法, 进行_colorDict的更新 _colorDict[key] = [UIColor colorWithRed:r / 255.0 green:g / 255.0 blue:b / 255.0 alpha:a]; }]; } @end ViewController.m #import "ViewController.h" #import "MTSkinTools.h" @interface ViewController () @property (weak, nonatomic) IBOutlet UIImageView *faceView; @property (weak, nonatomic) IBOutlet UIImageView *heartView; @property (weak, nonatomic) IBOutlet UIImageView *rectView; @property (weak, nonatomic) IBOutlet UILabel *label; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // 启动时加载皮肤 [self changeSkinWithSkinName:nil]; } - (IBAction)redClick:(id)sender { // 切换皮肤 [self changeSkinWithSkinName:@"red"]; } - (IBAction)greenClick:(id)sender { // 切换皮肤 [self changeSkinWithSkinName:@"green"]; } - (IBAction)blueClick:(id)sender { // 切换皮肤 [self changeSkinWithSkinName:@"blue"]; } - (IBAction)orangeClick:(id)sender { // 切换皮肤 [self changeSkinWithSkinName:@"orange"]; } //抽取公用方法 - (void)changeSkinWithSkinName:(NSString *)skinName { // 判断如果皮肤名称传了空, 那么不用管保存 if (skinName != nil) { [MTSkinTools saveSkinName:skinName]; } // 切换图像 self.faceView.image = [MTSkinTools imageWithImageName:@"face"]; self.heartView.image = [MTSkinTools imageWithImageName:@"heart"]; self.rectView.image = [MTSkinTools imageWithImageName:@"rect"]; // 切换文字颜色 self.label.textColor = [MTSkinTools colorWithName:MTSkinToolLabelTextDayColor]; // 切换背景颜色 self.label.backgroundColor = [MTSkinTools colorWithName:MTSkinToolLabelBackgroundDayColor]; } @end

优秀的个人博客,低调大师

iOS UIWebView使用

1. 加载 WebView可直接加载.mp4,.pdf,.html,.doc等格式文件。 @interface ViewController () @property (nonatomic, strong) UIWebView *webView; @end @implementation ViewController - (void)loadView { self.webView = [[UIWebView alloc] initWithFrame:[UIScreen mainScreen].bounds]; self.view = self.webView; } - (void)viewDidLoad { [super viewDidLoad]; self.webView.backgroundColor = [UIColor whiteColor]; // 加载网页 // NSURL *url = [[NSBundle mainBundle] URLForResource:@"index.html" withExtension:nil]; // 加载doc // NSURL *url = [[NSBundle mainBundle] URLForResource:@"面向对象C.doc" withExtension:nil]; // 加载pdf // NSURL *url = [[NSBundle mainBundle] URLForResource:@"史提夫乔布斯传.pdf" withExtension:nil]; // 播放视频 NSURL *url = [[NSBundle mainBundle] URLForResource:@"qixi.mp4" withExtension:nil]; NSURLRequest *request = [NSURLRequest requestWithURL:url]; [self.webView loadRequest:request]; // 自动检测电话号码、网址、邮件地址 self.webView.dataDetectorTypes = UIDataDetectorTypePhoneNumber; // 缩放网页 self.webView.scalesPageToFit = YES; } @end 2. 与JS交互 1). OC调用JS代码 @interface ViewController () <UIWebViewDelegate> @property (nonatomic, strong) UIWebView *webView; @end @implementation ViewController - (void)loadView { self.webView = [[UIWebView alloc] initWithFrame:[UIScreen mainScreen].bounds]; self.view = self.webView; } - (void)viewDidLoad { [super viewDidLoad]; self.webView.backgroundColor = [UIColor whiteColor]; NSURL *url = [[NSBundle mainBundle] URLForResource:@"index.html" withExtension:nil]; NSURLRequest *request = [NSURLRequest requestWithURL:url]; [self.webView loadRequest:request]; self.webView.scalesPageToFit = YES; // 设置代理 self.webView.delegate = self; } #pragma mark 代理方法 // 等待网页加载完成 才能执行js - (void)webViewDidFinishLoad:(UIWebView *)webView { // 调用网页中的函数 NSString *string = [webView stringByEvaluatingJavaScriptFromString:@"test();"]; NSLog(@"----%@", string); } index.html <!DOCTYPE html> <html xmlns="[http://www.w3.org/1999/xhtml](http://www.w3.org/1999/xhtml)"> <head> <meta name="viewport" content="width=device-width, initial-scale=1.0"/> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <title></title> <script> function test() { return "abc"; } </script> </head> <body> <br /> <br /><br /> 11111111111 <br />abc <br /> <a href="source:///showMessage:/helloworld">HelloWorld!</a> <br /> <a href="http://www.baidu.com">baidu</a> <br /> 123@abc.com <br /> http://www.baidu.com <div id="container"> </div> </body> </html> 2). JS调用OC代码 @interface ViewController () <UIWebViewDelegate> @property (nonatomic, strong) UIWebView *webView; @end @implementation ViewController - (void)loadView { self.webView = [[UIWebView alloc] initWithFrame:[UIScreen mainScreen].bounds]; self.view = self.webView; } - (void)viewDidLoad { [super viewDidLoad]; self.webView.backgroundColor = [UIColor whiteColor]; NSURL *url = [[NSBundle mainBundle] URLForResource:@"index.html" withExtension:nil]; NSURLRequest *request = [NSURLRequest requestWithURL:url]; [self.webView loadRequest:request]; self.webView.scalesPageToFit = YES; // 设置代理 self.webView.delegate = self; } #pragma mark 代理方法 // 发送请求之前, JS调用OC代码 - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { // 获取url中的协议 NSLog(@"%@", request.URL.scheme); // 判断协议是否是自定义协议 if ([request.URL.scheme isEqualToString:@"source"]) { NSLog(@"%@", request.URL.pathComponents); // 获取方法名 NSString *methodName = request.URL.pathComponents[1]; // 获取参数 NSString *param = request.URL.pathComponents[2]; // 调用方法 // 把字符串的方法名称转换为一个selector SEL method = NSSelectorFromString(methodName); if ([self respondsToSelector:method]) { // 解决执行方法的内存泄漏问题 #pragma clang diagnostic push #pragma clang diagnostic ignored "-Warc-performSelector-leaks" // 调用放法 [self performSelector: method withObject:param]; #pragma mark diagnostic pop } } // 返回NO,所有的请求都不执行 return YES; } // 显示对话框 - (void)showMessage:(NSString *)str { UIAlertController *vc = [UIAlertController alertControllerWithTitle:@"提示" message:str preferredStyle:UIAlertControllerStyleAlert]; // 弹出的按钮 UIAlertAction *action = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) { NSLog(@"clicker"); }]; [vc addAction:action]; [self presentViewController:vc animated:YES completion:nil]; } @end

优秀的个人博客,低调大师

iOS 关联对象

关联对象的作用: 可以在运行期间给某个对象增加属性 可以在运行期间获取某个对象的所有属性名称 交换方法 示例: UIImageView+MyView.h #import <UIKit/UIKit.h> @interface UIImageView (MyView) @property (nonatomic, copy) NSString *urlString; @end UIImageView+MyView.m #import <objc/runtime.h> //1 可以在运行期间给某个对象增加属性 //2 可以在运行期间获取某个对象的所有属性名称 //3 交换方法 @implementation UIImageView (MyView) - (NSString *)urlString { return objc_getAssociatedObject(self, "str"); } - (void)setUrlString:(NSString *)urlString { //可以在运行期间给某个对象增加属性 //关联对象 objc_setAssociatedObject(self, "str", urlString, OBJC_ASSOCIATION_COPY_NONATOMIC); } @end

优秀的个人博客,低调大师

iOS NSURLSession HTTPS

@interface ViewController () <NSURLSessionTaskDelegate> @property (nonatomic, strong) NSURLSession *session; @end @implementation ViewController - (NSURLSession *)session { if (_session == nil) { NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration]; _session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:nil]; } return _session; } - (void)viewDidLoad { [super viewDidLoad]; //https://kyfw.12306.cn/otn/ NSURL *url = [NSURL URLWithString:@"https://kyfw.12306.cn/otn/"]; [[self.session dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { NSString *html = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; NSLog(@"%@",html); }] resume]; } //代理的方法 //接受服务器的挑战,信任服务器 - (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler { if (challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust) { NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]; completionHandler(0,credential); } } @end

优秀的个人博客,低调大师

iOS NSString 加密

NSString+Hash.h #import <Foundation/Foundation.h> @interface NSString (Hash) #pragma mark - 散列函数 /** * 计算MD5散列结果 * * 终端测试命令: * @code * md5 -s "string" * @endcode * * <p>提示:随着 MD5 碰撞生成器的出现,MD5 算法不应被用于任何软件完整性检查或代码签名的用途。<p> * * @return 32个字符的MD5散列字符串 */ - (NSString *)md5String; /** * 计算SHA1散列结果 * * 终端测试命令: * @code * echo -n "string" | openssl sha -sha1 * @endcode * * @return 40个字符的SHA1散列字符串 */ - (NSString *)sha1String; /** * 计算SHA256散列结果 * * 终端测试命令: * @code * echo -n "string" | openssl sha -sha256 * @endcode * * @return 64个字符的SHA256散列字符串 */ - (NSString *)sha256String; /** * 计算SHA 512散列结果 * * 终端测试命令: * @code * echo -n "string" | openssl sha -sha512 * @endcode * * @return 128个字符的SHA 512散列字符串 */ - (NSString *)sha512String; #pragma mark - HMAC 散列函数 /** * 计算HMAC MD5散列结果 * * 终端测试命令: * @code * echo -n "string" | openssl dgst -md5 -hmac "key" * @endcode * * @return 32个字符的HMAC MD5散列字符串 */ - (NSString *)hmacMD5StringWithKey:(NSString *)key; /** * 计算HMAC SHA1散列结果 * * 终端测试命令: * @code * echo -n "string" | openssl sha -sha1 -hmac "key" * @endcode * * @return 40个字符的HMAC SHA1散列字符串 */ - (NSString *)hmacSHA1StringWithKey:(NSString *)key; /** * 计算HMAC SHA256散列结果 * * 终端测试命令: * @code * echo -n "string" | openssl sha -sha256 -hmac "key" * @endcode * * @return 64个字符的HMAC SHA256散列字符串 */ - (NSString *)hmacSHA256StringWithKey:(NSString *)key; /** * 计算HMAC SHA512散列结果 * * 终端测试命令: * @code * echo -n "string" | openssl sha -sha512 -hmac "key" * @endcode * * @return 128个字符的HMAC SHA512散列字符串 */ - (NSString *)hmacSHA512StringWithKey:(NSString *)key; #pragma mark - 文件散列函数 /** * 计算文件的MD5散列结果 * * 终端测试命令: * @code * md5 file.dat * @endcode * * @return 32个字符的MD5散列字符串 */ - (NSString *)fileMD5Hash; /** * 计算文件的SHA1散列结果 * * 终端测试命令: * @code * openssl sha -sha1 file.dat * @endcode * * @return 40个字符的SHA1散列字符串 */ - (NSString *)fileSHA1Hash; /** * 计算文件的SHA256散列结果 * * 终端测试命令: * @code * openssl sha -sha256 file.dat * @endcode * * @return 64个字符的SHA256散列字符串 */ - (NSString *)fileSHA256Hash; /** * 计算文件的SHA512散列结果 * * 终端测试命令: * @code * openssl sha -sha512 file.dat * @endcode * * @return 128个字符的SHA512散列字符串 */ - (NSString *)fileSHA512Hash; @end NSString+Hash.m #import "NSString+Hash.h" #import <CommonCrypto/CommonCrypto.h> @implementation NSString (Hash) #pragma mark - 散列函数 - (NSString *)md5String { const char *str = self.UTF8String; uint8_t buffer[CC_MD5_DIGEST_LENGTH]; CC_MD5(str, (CC_LONG)strlen(str), buffer); return [self stringFromBytes:buffer length:CC_MD5_DIGEST_LENGTH]; } - (NSString *)sha1String { const char *str = self.UTF8String; uint8_t buffer[CC_SHA1_DIGEST_LENGTH]; CC_SHA1(str, (CC_LONG)strlen(str), buffer); return [self stringFromBytes:buffer length:CC_SHA1_DIGEST_LENGTH]; } - (NSString *)sha256String { const char *str = self.UTF8String; uint8_t buffer[CC_SHA256_DIGEST_LENGTH]; CC_SHA256(str, (CC_LONG)strlen(str), buffer); return [self stringFromBytes:buffer length:CC_SHA256_DIGEST_LENGTH]; } - (NSString *)sha512String { const char *str = self.UTF8String; uint8_t buffer[CC_SHA512_DIGEST_LENGTH]; CC_SHA512(str, (CC_LONG)strlen(str), buffer); return [self stringFromBytes:buffer length:CC_SHA512_DIGEST_LENGTH]; } #pragma mark - HMAC 散列函数 - (NSString *)hmacMD5StringWithKey:(NSString *)key { const char *keyData = key.UTF8String; const char *strData = self.UTF8String; uint8_t buffer[CC_MD5_DIGEST_LENGTH]; CCHmac(kCCHmacAlgMD5, keyData, strlen(keyData), strData, strlen(strData), buffer); return [self stringFromBytes:buffer length:CC_MD5_DIGEST_LENGTH]; } - (NSString *)hmacSHA1StringWithKey:(NSString *)key { const char *keyData = key.UTF8String; const char *strData = self.UTF8String; uint8_t buffer[CC_SHA1_DIGEST_LENGTH]; CCHmac(kCCHmacAlgSHA1, keyData, strlen(keyData), strData, strlen(strData), buffer); return [self stringFromBytes:buffer length:CC_SHA1_DIGEST_LENGTH]; } - (NSString *)hmacSHA256StringWithKey:(NSString *)key { const char *keyData = key.UTF8String; const char *strData = self.UTF8String; uint8_t buffer[CC_SHA256_DIGEST_LENGTH]; CCHmac(kCCHmacAlgSHA256, keyData, strlen(keyData), strData, strlen(strData), buffer); return [self stringFromBytes:buffer length:CC_SHA256_DIGEST_LENGTH]; } - (NSString *)hmacSHA512StringWithKey:(NSString *)key { const char *keyData = key.UTF8String; const char *strData = self.UTF8String; uint8_t buffer[CC_SHA512_DIGEST_LENGTH]; CCHmac(kCCHmacAlgSHA512, keyData, strlen(keyData), strData, strlen(strData), buffer); return [self stringFromBytes:buffer length:CC_SHA512_DIGEST_LENGTH]; } #pragma mark - 文件散列函数 #define FileHashDefaultChunkSizeForReadingData 4096 - (NSString *)fileMD5Hash { NSFileHandle *fp = [NSFileHandle fileHandleForReadingAtPath:self]; if (fp == nil) { return nil; } CC_MD5_CTX hashCtx; CC_MD5_Init(&hashCtx); while (YES) { @autoreleasepool { NSData *data = [fp readDataOfLength:FileHashDefaultChunkSizeForReadingData]; CC_MD5_Update(&hashCtx, data.bytes, (CC_LONG)data.length); if (data.length == 0) { break; } } } [fp closeFile]; uint8_t buffer[CC_MD5_DIGEST_LENGTH]; CC_MD5_Final(buffer, &hashCtx); return [self stringFromBytes:buffer length:CC_MD5_DIGEST_LENGTH]; } - (NSString *)fileSHA1Hash { NSFileHandle *fp = [NSFileHandle fileHandleForReadingAtPath:self]; if (fp == nil) { return nil; } CC_SHA1_CTX hashCtx; CC_SHA1_Init(&hashCtx); while (YES) { @autoreleasepool { NSData *data = [fp readDataOfLength:FileHashDefaultChunkSizeForReadingData]; CC_SHA1_Update(&hashCtx, data.bytes, (CC_LONG)data.length); if (data.length == 0) { break; } } } [fp closeFile]; uint8_t buffer[CC_SHA1_DIGEST_LENGTH]; CC_SHA1_Final(buffer, &hashCtx); return [self stringFromBytes:buffer length:CC_SHA1_DIGEST_LENGTH]; } - (NSString *)fileSHA256Hash { NSFileHandle *fp = [NSFileHandle fileHandleForReadingAtPath:self]; if (fp == nil) { return nil; } CC_SHA256_CTX hashCtx; CC_SHA256_Init(&hashCtx); while (YES) { @autoreleasepool { NSData *data = [fp readDataOfLength:FileHashDefaultChunkSizeForReadingData]; CC_SHA256_Update(&hashCtx, data.bytes, (CC_LONG)data.length); if (data.length == 0) { break; } } } [fp closeFile]; uint8_t buffer[CC_SHA256_DIGEST_LENGTH]; CC_SHA256_Final(buffer, &hashCtx); return [self stringFromBytes:buffer length:CC_SHA256_DIGEST_LENGTH]; } - (NSString *)fileSHA512Hash { NSFileHandle *fp = [NSFileHandle fileHandleForReadingAtPath:self]; if (fp == nil) { return nil; } CC_SHA512_CTX hashCtx; CC_SHA512_Init(&hashCtx); while (YES) { @autoreleasepool { NSData *data = [fp readDataOfLength:FileHashDefaultChunkSizeForReadingData]; CC_SHA512_Update(&hashCtx, data.bytes, (CC_LONG)data.length); if (data.length == 0) { break; } } } [fp closeFile]; uint8_t buffer[CC_SHA512_DIGEST_LENGTH]; CC_SHA512_Final(buffer, &hashCtx); return [self stringFromBytes:buffer length:CC_SHA512_DIGEST_LENGTH]; } #pragma mark - 助手方法 /** * 返回二进制 Bytes 流的字符串表示形式 * * @param bytes 二进制 Bytes 数组 * @param length 数组长度 * * @return 字符串表示形式 */ - (NSString *)stringFromBytes:(uint8_t *)bytes length:(int)length { NSMutableString *strM = [NSMutableString string]; for (int i = 0; i < length; i++) { [strM appendFormat:@"%02x", bytes[i]]; } return [strM copy]; } @end

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

用户登录
用户注册