ios开发进阶之网络06 网络安全 UIWebView

一 数据安全

  • 一定要使用POST请求提交用户的隐私数据
    • GET请求的所有参数都直接暴露在URL中
    • 请求的URL一般会记录在服务器的访问日志中
  • 常见的加密算法
    MD5 \ SHA \ DES \ 3DES \ RC2和RC4 \ RSA \ IDEA \ DSA \ AES

二 MD5

  • 什么是MD5

    • 全称是Message Digest Algorithm 5,译为“消息摘要算法第5版”
    • 效果:对输入信息生成唯一的128位散列值(32个字符)
  • MD5的特点

    • 输入两个不同的明文不会得到相同的输出值
    • 根据输出值,不能得到原始的明文,即其过程不可逆
  • MD5的应用

    • 由于MD5加密算法具有较好的安全性,而且免费,因此该加密算法被广泛使用
    • 主要运用在数字签名、文件完整性验证以及口令加密等方面
  • MD5解密网站:http://www.cmd5.com

  • MD5改进
    • 加盐(Salt):在明文的固定位置插入随机串,然后再进行MD5
    • 先加密,后乱序:先对明文进行MD5,然后对加密得到的MD5串的字符进行乱序

三 https

#pragma mark - NSURLSessionDataDelegate

// 只要访问的是HTTPS的路径就会调用
// 该方法的作用就是处理服务器返回的证书, 需要在该方法中告诉系统是否需要安装服务器返回的证书

- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))completionHandler
{  
    // 1.从服务器返回的受保护空间中拿到证书的类型
    // 2.判断服务器返回的证书是否是服务器信任的
    if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
        NSLog(@"是服务器信任的证书");
    // 3.根据服务器返回的受保护空间创建一个证书

//         void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *)         
//         代理方法的completionHandler block接收两个参数:
//         第一个参数: 代表如何处理证书
//         第二个参数: 代表需要处理哪个证书

        NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
        // 4.安装证书
       completionHandler(NSURLSessionAuthChallengeUseCredential , credential);

    }
}

四 UIWebView基本使用

  • 加载URL请求
NSURL *url  = [NSURL URLWithString:@"http://www.baidu.com"];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    // 用于调整界面
    self.webView.scalesPageToFit = YES;
    // 1.加载网页
    [self.webView loadRequest:request];
  • 加载html
NSURL *url = [[NSBundle mainBundle] URLForResource:@"test.html" withExtension:nil];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    // 用于识别网页中的特殊符号
    self.webView.dataDetectorTypes = UIDataDetectorTypeAll;
    [self.webView loadRequest:request];
  • 加载本地文件资源
NSURL *url = [NSURL fileURLWithPath:filePath];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[webView loadRequest:request];

#pragma mark - UIWebViewDelegate
// 每次即将加载一个新的资源都会调用
// 如果返回YES, 代表允许加载当前资源
// 如果返回NO, 代表不允许加载当前资源
// JS和OC进行互相调用
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
//    NSLog(@"%@", request.URL);
    return YES;
}

// 开始加载
// 只要webview加载一个资源就会调用一次
- (void)webViewDidStartLoad:(UIWebView *)webView
{
}
// 加载完毕
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
// 设置前进后退按钮的状态
    self.gobackBtn.enabled = [self.webView canGoBack];
    self.goforwardBtn.enabled = [self.webView canGoForward];
}
// 加载出错
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error
{
    NSLog(@"%@", error);
}

五 JS和OC互相调用

- (void)viewDidLoad {
    [super viewDidLoad];

    NSURL *url = [[NSBundle mainBundle] URLForResource:@"test.html" withExtension:nil];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    [self.webView loadRequest:request];
}
  • OC调JS
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
// OC调用JS,利用UIWebView的stringByEvaluatingJavaScriptFromString方法, 告诉系统需要调用的JS方法名称即可
   [self.webView  stringByEvaluatingJavaScriptFromString:@"showTitle();"];

}
  • JS调OC
#pragma mark - UIWebViewDelegate
// 利用该方法作为JS和OC之间的桥梁
// 在JS跳转网页
// 在OC代理方法中通过判断自定义协议头, 决定是否是JS调用OC方法
// 在OC代理方法中通过截取字符串, 获取JS想调用的OC方法名称
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
//    NSLog(@"%@", request.URL);
    NSString *schem = @"xmg://";
    NSString *urlStr = request.URL.absoluteString;
    if ([urlStr hasPrefix:schem]) {
        NSLog(@"需要调用OC方法");
        // 1.从URL中获取方法名称
        // xmg://call
        NSString *methodName = [urlStr substringFromIndex:schem.length];
        NSLog(@"%@", methodName);
        // 2.调用方法
        SEL sel = NSSelectorFromString(methodName);
        // 忽略警告信息的作用范围开始
#pragma clang diagnostic push
        // 下面这一行代码是用于指定需要忽略的警告信息
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
        [self performSelector:sel withObject:nil];
        // 忽略警告信息的作用范围结束
#pragma clang diagnostic pop
        return NO;
    }
    return YES;
}
  • JS和OC互调-带参数
NSString *schem = @"xmg://";
    NSString *urlStr = request.URL.absoluteString;
    if ([urlStr hasPrefix:schem]) {
        NSLog(@"需要调用OC方法");
        // 1.从URL中获取方法名称
        // xmg://sendMessageWithNumber_andContent_?10086&love
        NSString *subPath = [urlStr substringFromIndex:schem.length];
        // 注意: 如果指定的用于切割的字符串不存在, 那么就会返回整个字符串
        NSArray *subPaths = [subPath componentsSeparatedByString:@"?"];
        // 2.获取方法名称
        NSString *methodName = [subPaths firstObject];
        methodName = [methodName stringByReplacingOccurrencesOfString:@"_" withString:@":"];
        NSLog(@"%@", methodName);
        // 2.调用方法
        SEL sel = NSSelectorFromString(methodName);

        // 3.处理参数
        NSString *parma = nil;
        if (subPaths.count == 2) {
            parma = [subPaths lastObject];
            // 3.截取参数
            NSArray *parmas = [parma componentsSeparatedByString:@"&"];
            [self performSelector:sel withObject:[parmas firstObject] withObject:[parmas lastObject]];
            return NO;
        }
        [self performSelector:sel withObject:parma];
        return NO;
    }

多个参数的情况下,使用不方便,引出下节使用NSInvocation

六 NSInvocation

  • NSInvocation:用来包装方法和对应的对象, 可以存储方法的名称,对应的对象 ,对应的参数
//    Signature签名: 在创建NSInvocation的时候, 必须传递一个签名对象
//    签名对象的作用 : 用于获取参数的个数和方法的返回值
// 注意点: 创建签名对象的时候不是使用NSMethodSignature类创建,而是方法属于谁就用谁来创建
- (void)viewDidLoad {
    [super viewDidLoad];
     // 1.创建一个NSInvocation对象
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];

    invocation.target = self; // 保存方法所属的对象
    // 给invocation设置的方法, 必须和签名中的方法一致
    invocation.selector = @selector(sendMessageWithNumber:andContent:status:); // 保存方法名称

    // 第一个参数: 需要给指定方法传递的值
    //    + 第一个参数需要接收一个指针, 也就是传递值的时候需要传递地址
    // 第二个参数: 需要给指定方法的第几个参数传值
    NSString *number = @"10086";
    // 注意: 设置参数的索引时不能从0开始, 因为0已经被self占用, 1已经被_cmd占用
    [invocation setArgument:&number atIndex:2];

    NSString *content = @"love";
    [invocation setArgument:&content atIndex:3];

    NSString *status = @"success";
    [invocation setArgument:&status atIndex:4];

    // 2.调用NSInvocation对象的invoke方法
    // 只要调用invocation的invoke方法, 就代表需要执行 \
    NSInvocation对象中指定对象的指定方法, 并且传递指定的参数
    [invocation invoke];
}
  • 封装方法,解决参数越界的问题
- (id)performSelector:(SEL)aSelector withObjects:(NSArray *)objects
{
    //  1.创建签名对象
    NSMethodSignature *signature = [[self class] instanceMethodSignatureForSelector:aSelector];

    // 判断传入的方法是否存储, 如果方法不存在签名对象为nil
    if (signature == nil) {
        // 传入的方法不存在
        NSString *info = [NSString stringWithFormat:@" -[%@ %@]:  unrecognized selector sent to instance", [self class], NSStringFromSelector(aSelector)];
       // 直接抛异常 
        @throw [[NSException alloc] initWithName:@"一个牛B的错误" reason:info userInfo:nil];
    }

    // 2.创建一个NSInvocation对象
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];

     // 3.保存方法所属的对象
    invocation.target = self;

    // 给invocation设置的方法, 必须和签名中的方法一致
    //  4.保存方法名称
    invocation.selector = aSelector;

    // 5.设置参数
    /*
     当前如果直接遍历参数数组来设置参数, 会存在问题
     如果参数数组元素多余参数个数, 那么就会报错
     */
    NSUInteger arguments =  signature.numberOfArguments - 2;
    /*
     如果直接遍历参数值的个数, 会存在问题
     如果参数的个数大于了参数值的个数, 那么数组会越界
     */
    NSUInteger objectsCount = objects.count;
    /*
     参数和参数值, 谁少就遍历谁
     */
    NSUInteger count = MIN(arguments, objectsCount);

    for (int i = 0; i < count; i++) {
        NSObject *obj = objects[i];
        // 处理数组参数中NSNull问题
        if ([obj isKindOfClass:[NSNull class]]) {
            obj = nil;
        }
        [invocation setArgument:&obj atIndex:i + 2];
    }

    // 6.调用NSInvocation对象的invoke方法
    [invocation invoke];

    id res = nil;
    // 判断当前方法是否有返回值
    if ( signature.methodReturnLength != 0) {
     // 7.获取返回值
        // getReturnValue方法会将会去到的方法返回值赋值给传入的对象
        [invocation getReturnValue:&res];
    }

    return res;
}

你可能感兴趣的:(ios开发进阶之多线程与网络)