美文网首页iOS开发
使用NSURLProtocol获取网页资源

使用NSURLProtocol获取网页资源

作者: 今晚月色 | 来源:发表于2020-06-22 16:27 被阅读0次

    利用NSURLProtocol可以获取网页中的资源。例如:图片,js,css,视频,音频等。

    代码

    继承NSURLProtocol

    #import <Foundation/Foundation.h>
    
    FOUNDATION_EXTERN NSString *const kHttpProtocolKey;
    FOUNDATION_EXTERN NSString *const kHttpsProtocolKey;
    FOUNDATION_EXTERN NSString *const kURLLoadingNotification;
    FOUNDATION_EXTERN NSString *const kVideoPlayURLGetNotificationName;
    
    @interface SechemaURLProtocol : NSURLProtocol
    
    @end
    
    #import "SechemaURLProtocol.h"
    
    static NSString *const kURLProtocolHandledKey = @"URLProtocolHandledKey";
    NSString *const kHttpProtocolKey = @"http";
    NSString *const kHttpsProtocolKey = @"https";
    NSString *const kURLLoadingNotification = @"com.wudan.URLLoadingNotificationName";
    NSString *const kVideoPlayURLGetNotificationName = @"com.wudan.VideoPlayURLGetNotificationName";
    
    @interface SechemaURLProtocol()<NSURLSessionDelegate>
    
    @property (atomic, strong, readwrite) NSURLSessionDataTask *task;
    @property (nonatomic, strong) NSURLSession *session;
    @property (nonatomic, strong) NSOperationQueue *queue;
    
    @end
    
    @implementation SechemaURLProtocol
    
    + (BOOL)canInitWithRequest:(NSURLRequest *)request {
        NSString *scheme = [[request URL] scheme];
        if ([request.URL.absoluteString containsString:@".mp4"] ||
            [request.URL.absoluteString containsString:@".m3u8"] ||
            [request.URL.absoluteString containsString:@".avi"] ||
            [request.URL.absoluteString containsString:@".rmvb"] ||
            [request.URL.absoluteString containsString:@".flv"] ||
            [request.URL.absoluteString containsString:@".3gp"] ||
            [request.URL.absoluteString containsString:@".wmv"]) {
            [[NSNotificationCenter defaultCenter] postNotificationName:kVideoPlayURLGetNotificationName object:request.URL.absoluteString];
        } else if ([request.URL.absoluteString containsString:@".jpg"] ||
            [request.URL.absoluteString containsString:@".png"] ||
            [request.URL.absoluteString containsString:@".bmp"] ||
            [request.URL.absoluteString containsString:@".jpeg"] ||
            [request.URL.absoluteString containsString:@".webp"] ||
            [request.URL.absoluteString containsString:@".gif"] ||
            [request.URL.absoluteString containsString:@".svg"]) {
            [[NSNotificationCenter defaultCenter] postNotificationName:kVideoPlayURLGetNotificationName object:request.URL.absoluteString];
        } else {
            NSLog(@"Other URL ----> %@", request.URL.absoluteString);
        }
    
        if ([scheme caseInsensitiveCompare:kHttpProtocolKey] == NSOrderedSame ||
            [scheme caseInsensitiveCompare:kHttpsProtocolKey] == NSOrderedSame) {
            if ([NSURLProtocol propertyForKey:kURLProtocolHandledKey inRequest:request]) {
                return NO;
            }
        }
        return YES;
    }
    
    + (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request {
        NSMutableURLRequest *mutableReqeust = [request mutableCopy];
        return mutableReqeust;
    }
    
    + (BOOL)requestIsCacheEquivalent:(NSURLRequest *)a toRequest:(NSURLRequest *)b {
        return [super requestIsCacheEquivalent:a toRequest:b];
    }
    
    - (void)startLoading {
        NSMutableURLRequest *mutableReqeust = [[self request] mutableCopy];
        [NSURLProtocol setProperty:@YES forKey:kURLProtocolHandledKey inRequest:mutableReqeust];
        [[NSNotificationCenter defaultCenter] postNotificationName:kURLLoadingNotification object:mutableReqeust.URL.absoluteString];
        NSURLSessionConfiguration *configure = [NSURLSessionConfiguration defaultSessionConfiguration];
        self.session  = [NSURLSession sessionWithConfiguration:configure delegate:self delegateQueue:self.queue];
        self.task = [self.session dataTaskWithRequest:mutableReqeust];
        [self.task resume];
    }
    
    - (void)stopLoading {
        [self.session invalidateAndCancel];
        self.session = nil;
        [[NSNotificationCenter defaultCenter] postNotificationName:kURLLoadingNotification object:@""];
    }
    
    #pragma mark - Getter
    - (NSOperationQueue *)queue {
        if (!_queue) {
            _queue = [[NSOperationQueue alloc] init];
        }
        return _queue;
    }
    @end
    
    @implementation SechemaURLProtocol(NSURLSessionDelegate)
    
    - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
        if (error != nil) {
            [self.client URLProtocol:self didFailWithError:error];
        } else {
            [self.client URLProtocolDidFinishLoading:self];
        }
    }
    
    - (void)URLSession:(NSURLSession *)session
              dataTask:(NSURLSessionDataTask *)dataTask
    didReceiveResponse:(NSURLResponse *)response
     completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler {
        
        [self.client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
        completionHandler(NSURLSessionResponseAllow);
    }
    
    - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data {
        [self.client URLProtocol:self didLoadData:data];
    }
    
    - (void)URLSession:(NSURLSession *)session
              dataTask:(NSURLSessionDataTask *)dataTask
     willCacheResponse:(NSCachedURLResponse *)proposedResponse
     completionHandler:(void (^)(NSCachedURLResponse * _Nullable))completionHandler {
        completionHandler(proposedResponse);
    }
    
    - (void)URLSession:(NSURLSession *)session
                  task:(NSURLSessionTask *)task
    willPerformHTTPRedirection:(NSHTTPURLResponse *)response
            newRequest:(NSURLRequest *)newRequest
     completionHandler:(void (^)(NSURLRequest *))completionHandler {
        
        NSMutableURLRequest *redirectRequest;
        redirectRequest = [newRequest mutableCopy];
        [[self class] removePropertyForKey:kURLProtocolHandledKey inRequest:redirectRequest];
        [[self client] URLProtocol:self wasRedirectedToRequest:redirectRequest redirectResponse:response];
        [self.task cancel];
        [[self client] URLProtocol:self didFailWithError:[NSError errorWithDomain:NSCocoaErrorDomain code:NSUserCancelledError userInfo:nil]];
    }
    @end
    

    说明

    这边代码里面我是根据获取的URL路径中是否含有该类型字段进行判断。

    使用方法

    注册类

    - (void)registerClass {
        NSArray *privateStrArr = @[@"Controller", @"Context", @"Browsing", @"K", @"W"];
        NSString *className =  [[[privateStrArr reverseObjectEnumerator] allObjects] componentsJoinedByString:@""];
        Class cls = NSClassFromString(className);
        SEL sel = NSSelectorFromString(@"registerSchemeForCustomProtocol:");
        if (cls && sel) {
            if ([(id)cls respondsToSelector:sel]) {
                [(id)cls performSelector:sel withObject:kHttpProtocolKey];
                [(id)cls performSelector:sel withObject:kHttpsProtocolKey];
            }
        }
        [NSURLProtocol registerClass:[SechemaURLProtocol class]];
    }
    

    移除

    - (void)dealloc {
        [NSURLProtocol unregisterClass:[SechemaURLProtocol class]];
    }
    

    效果图

    效果图

    相关文章

      网友评论

        本文标题:使用NSURLProtocol获取网页资源

        本文链接:https://www.haomeiwen.com/subject/foaxfktx.html