美文网首页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