zoukankan      html  css  js  c++  java
  • WKWebView实现网页静态资源优先从本地加载

    前言:最近微信的小游戏跳一跳特别的火,顺便也让h5小游戏更加的火热。另外微信小程序,以及支付宝的小程序都是用H5写的。无论是小游戏还是小程序,这些都需要加载更多的资源文件,处理更多的业务。这些都对网页加载的速度提出了较高的要求。UIWebView由于占用内存大,释放不掉一直备受诟病。而且目前是大多数的app支持的最低版本都是从iOS 8开始的。我这里主要针对WKWebView来说一下。

    资源包压缩下载VS静态资源文件下载

      根据不同的业务需求,不同的app对于资源文件的处理情形是不同的。以12306app为例。选择了下载资源压缩到沙盒的策略,列车班次发生调整时,调用接口,强制下载资源压缩包到本地。注释:但是WKWebView加载本地资源文件,有些麻烦,后续会是专门深入研究下。由于强制下载资源包的形式用户体验不是特别好,很多小游戏,以及小程序为了更好的用户体验通常选择隐性下载静态资源文件的形式,加载时优先使用本地已下载的资源文件进行加载,不仅可以提高加载速度,而且还可以为用户节省流量。

    网络请求的拦截

      NSURLProtocol相信很多小伙伴都挺听说并使用过。记得很早一段时间,大家对于WKWebView使用NSURLProtocol进行网络请求进行拦截没有很好的办法,还好不知道哪位大神最终找到了解决的办法,在此万分感谢。代码入如下:

    //2.注册
    [NSURLProtocol registerClass:[NSURLProtocolCustom class]];
    //3.实现拦截功能,这个是核心
    Class cls = NSClassFromString(@"WKBrowsingContextController");
    SEL sel = NSSelectorFromString(@"registerSchemeForCustomProtocol:");
    if ([(id)cls respondsToSelector:sel]) {
    #pragma clang diagnostic push
    #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
    [(id)cls performSelector:sel withObject:@"http"];
    [(id)cls performSelector:sel withObject:@"https"];
    #pragma clang diagnostic pop
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    加载时优先加载本地资源文件

      对WKWebView发出的网络请求进行拦截后,我们需要对资源文件的进行判断本,判断本地是否有对应的资源文件,如果有的话优先加载本地的资源文件。对于资源文件的匹配,我这里将网络请求中资源文件的url进行MD5序列化后,作为资源文件的名字。代码如下:

    //
    // NSURLProtocolCustom.m
    // WKWebViewDemo1
    //
    // Created by JackLee on 2018/2/27.
    // Copyright © 2018年 JackLee. All rights reserved.
    //

    #import "NSURLProtocolCustom.h"
    #import "NSString+MD5.h"
    #import <JKSandBoxManager/JKSandBoxManager.h>
    #import <AFNetworking/AFNetworking.h>

    @interface NSURLProtocolCustom ()

    @property (nonatomic, strong) AFURLSessionManager *manager;

    @end

    static NSString* const FilteredKey = @"FilteredKey";

    @implementation NSURLProtocolCustom
    + (BOOL)canInitWithRequest:(NSURLRequest *)request
    {
    NSString *extension = request.URL.pathExtension;
    BOOL isSource = [[self resourceTypes] indexOfObjectPassingTest:^BOOL(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
    return [extension compare:obj options:NSCaseInsensitiveSearch] == NSOrderedSame;
    }] != NSNotFound;
    return [NSURLProtocol propertyForKey:FilteredKey inRequest:request] == nil && isSource;
    }

    + (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request
    {
    return request;
    }

    - (void)startLoading
    {
    NSMutableURLRequest *mutableReqeust = [super.request mutableCopy];
    //标记该请求已经处理
    [NSURLProtocol setProperty:@YES forKey:FilteredKey inRequest:mutableReqeust];
    NSString *fileName = [NSString stringWithFormat:@"%@.%@",[super.request.URL.absoluteString MD5Hash],super.request.URL.pathExtension];

    NSString *gameId = [[NSUserDefaults standardUserDefaults] stringForKey:@"GameId"];
    NSString *nameSpace = [NSString stringWithFormat:@"GameId%@",gameId];
    NSString *fileDir =[JKSandBoxManager createCacheFilePathWithFolderName:nameSpace];
    NSString *filePath =[fileDir stringByAppendingString:[NSString stringWithFormat:@"/%@",fileName]];
    NSLog(@"targetpath %@",filePath);

    if (![[NSFileManager defaultManager] fileExistsAtPath:filePath]) { //文件不存在,去下载
    [self downloadResourcesWithRequest:[mutableReqeust copy]];
    return;
    }
    //加载本地资源
    NSData *data = [NSData dataWithContentsOfFile:filePath];
    [self sendResponseWithData:data mimeType:[self getMimeTypeWithFilePath:filePath]];
    }

    - (void)stopLoading
    {

    }

    - (void)sendResponseWithData:(NSData *)data mimeType:(nullable NSString *)mimeType
    {
    // 这里需要用到MIMEType
    NSURLResponse *response = [[NSURLResponse alloc] initWithURL:super.request.URL
    MIMEType:mimeType
    expectedContentLength:-1
    textEncodingName:nil];

    //硬编码 开始嵌入本地资源到web中
    [[self client] URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
    [[self client] URLProtocol:self didLoadData:data];
    [[self client] URLProtocolDidFinishLoading:self];
    }

    /**
    * manager的懒加载
    */
    - (AFURLSessionManager *)manager {
    if (!_manager) {
    NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
    // 1. 创建会话管理者
    _manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];
    }
    return _manager;
    }

    ////下载资源文件
    - (void)downloadResourcesWithRequest:(NSURLRequest *)request{

    NSString *fileName = [NSString stringWithFormat:@"%@.%@",[super.request.URL.absoluteString MD5Hash],super.request.URL.pathExtension];

    NSString *gameId = [[NSUserDefaults standardUserDefaults] stringForKey:@"GameId"];
    NSString *nameSpace = [NSString stringWithFormat:@"GameId%@",gameId];
    NSString *fileDir =[JKSandBoxManager createCacheFilePathWithFolderName:nameSpace];
    NSString *targetFilePath =[fileDir stringByAppendingString:[NSString stringWithFormat:@"/%@",fileName]];

    NSURLSessionDownloadTask *downloadTask = [self.manager downloadTaskWithRequest:request progress:^(NSProgress *downloadProgress) {
    // 下载进度

    } destination:^NSURL *(NSURL *targetPath, NSURLResponse *response) {
    NSURL *path = [NSURL fileURLWithPath:JKSandBoxPathTemp];
    return [path URLByAppendingPathComponent:[NSString stringWithFormat:@"%@",fileName]];

    } completionHandler:^(NSURLResponse *response, NSURL *filePath, NSError *error) {
    [JKSandBoxManager moveFileFrom:filePath.path to:targetFilePath];
    NSLog(@"targetpath %@",targetFilePath);
    NSData *data = [NSData dataWithContentsOfFile:targetFilePath];
    [self sendResponseWithData:data mimeType:[self getMimeTypeWithFilePath:targetFilePath]];
    }];

    // 4. 开启下载任务
    [downloadTask resume];

    }

    - (NSString *)getMimeTypeWithFilePath:(NSString *)filePath{
    CFStringRef pathExtension = (__bridge_retained CFStringRef)[filePath pathExtension];
    CFStringRef type = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, pathExtension, NULL);
    CFRelease(pathExtension);

    //The UTI can be converted to a mime type:
    NSString *mimeType = (__bridge_transfer NSString *)UTTypeCopyPreferredTagWithClass(type, kUTTagClassMIMEType);
    if (type != NULL)
    CFRelease(type);

    return mimeType;
    }

    + (NSArray *)resourceTypes{
    return @[@"png", @"jpeg", @"gif", @"jpg",@"jpg",@"json", @"js", @"css",@"mp3",@"fnt"];
    }


    @end
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    其中,这里对资源文件的下载没有使用NSURLConnection,主要是NSURLConnection在iOS 9 以后就被废弃掉了。我这里用了AFnetworking进行处理。

    处理资源文件失效

      对着小程序或者小游戏的更新。某些资源文件会失效,如果不及时清除的话,就会非常的占用资源。针对这种情况,我们可以让用户主动删除相关的资源文件,也可以给资源文件设置有效期,进行自动的删除操作。
    demo如下:demo

    更多优质文章,可以微信扫码关注:
    ---------------------
    作者:JackLee18
    来源:CSDN
    原文:https://blog.csdn.net/hanhailong18/article/details/79394856
    版权声明:本文为博主原创文章,转载请附上博文链接!

  • 相关阅读:
    LC 综合 中级算法笔记
    LC 212. 单词搜索2
    [NLP] 2.2 文本正规化 (Text Normalization)
    本地秘钥复制到github,实现两者之间的交互
    Python 实例化对象
    C# 左补齐+ 生成一个星期的日期
    hello world
    迭代器模式、观察者模式
    代理模式、桥接模式、装饰器模式、适配器模式
    外观模式、组合模式、享元模式
  • 原文地址:https://www.cnblogs.com/lihaibo-Leao/p/10489614.html
Copyright © 2011-2022 走看看