WKWebView预初始化

论坛 期权论坛 脚本     
匿名技术用户   2020-12-28 22:28   16   0

开篇语:

由于业务需求,我们采用了WKWebView和其它view混合布局的展现方案。如果你的WKWebView个数不多,例如同一个页面不超过3个WKWebView,是很难发现这个瓶颈问题。不是内存占用太多,是init确实占用太多主线程时间。如果你尝试异步初始化WKWebView发现是不行的,init必须在主线程中执行。这就导致如果一个页面同时需要多个WKWebView,会产生卡顿问题(当然,新款设备CPU性能强悍,和老设备对比非常明显)。

方案:

船到桥头自然直,车到山前必有路…… 既然躲不过,那就直接面对吧!解决方法就是预初始化N个WKWebView备用,当使用的时候,直接设置HTML。那,预初始化的时候不会卡主线程吗?当然会,不过我们可以将这个过程放到页面加载(网络请求转圈圈)的地方,也就是牺牲用户网速体验,提升页面渲染速度。总体下来,我感觉加载变流畅了呢?,毕竟更多的人已经习惯了网络加载缓慢,反而更关心页面流畅度。况且,根据实际测试,初始化20个WKWebView的时间也就1秒--1.5秒(都是针对老设备而言的),新款设备基本体验不出差别。

说了这么多,无非就是写一个WKWebView池,必要的时间点初始化N个WKWebView,用的时候直接拿即可。如果池中的WKWebView不够用了,那就用一个初始化一个,反正都在主线程,没必要再预初始化更多了。

实现:

简单实现,一个单例管理所有预初始化的WKWebView。

HXWKWebViewPool.h

#import <Foundation/Foundation.h>
#import <WebKit/WebKit.h>

@interface HXWKWebViewPool : NSObject

+ (instancetype)sharedInstance;

/**
 预初始化若干WKWebView

 @param count 个数
 */
- (void)prepareWithCount:(NSUInteger)count;

/**
 从池中获取一个WKWebView
 
 @return WKWebView
 */
- (WKWebView *)getWKWebViewFromPool;

@end

HXWKWebViewPool.m

#import "HXWKWebViewPool.h"

@interface HXWKWebViewPool ()

@property (nonatomic) NSUInteger initialViewsMaxCount;  //最多初始化的个数
@property (nonatomic) NSMutableArray *preloadedViews;

@end

@implementation HXWKWebViewPool

+ (instancetype)sharedInstance {
    static dispatch_once_t onceToken;
    static HXWKWebViewPool *instance = nil;
    dispatch_once(&onceToken,^{
        instance = [[super allocWithZone:NULL] init];
    });
    return instance;
}

+ (id)allocWithZone:(struct _NSZone *)zone{
    return [self sharedInstance];
}

- (instancetype)init
{
    self = [super init];
    if (self) {
        self.initialViewsMaxCount = 20;
        self.preloadedViews = [NSMutableArray arrayWithCapacity:self.initialViewsMaxCount];
    }
    return self;
}

/**
 预初始化若干WKWebView
 
 @param count 个数
 */
- (void)prepareWithCount:(NSUInteger)count {
    
    NSTimeInterval start = CACurrentMediaTime();
    
    // Actually does nothing, only initialization must be called.
    while (self.preloadedViews.count < MIN(count,self.initialViewsMaxCount)) {
        id preloadedView = [self createPreloadedView];
        if (preloadedView) {
            [self.preloadedViews addObject:preloadedView];
        } else {
            break;
        }
    }
    
    NSTimeInterval delta = CACurrentMediaTime() - start;
    NSLog(@"=======初始化耗时:%f",  delta);
}

/**
 从池中获取一个WKWebView

 @return WKWebView
 */
- (WKWebView *)getWKWebViewFromPool {
    if (!self.preloadedViews.count) {
        NSLog(@"不够啦!");
        return [self createPreloadedView];
    } else {
        id preloadedView = self.preloadedViews.firstObject;
        [self.preloadedViews removeObject:preloadedView];
        return preloadedView;
    }
}

/**
 创建一个WKWebView

 @return WKWebView
 */
- (WKWebView *)createPreloadedView {
    
    WKWebViewConfiguration *wkWebConfig = [[WKWebViewConfiguration alloc] init];
    WKUserContentController *wkUController = [[WKUserContentController alloc] init];
    wkWebConfig.userContentController = wkUController;
    
    WKWebView *wkWebView = [[WKWebView alloc]initWithFrame:CGRectZero configuration:wkWebConfig];
    //根据自己的业务需求初始化WKWebView
    wkWebView.opaque = NO;
    wkWebView.scrollView.scrollEnabled = NO;
    wkWebView.scrollView.showsVerticalScrollIndicator = NO;
    wkWebView.scrollView.scrollsToTop = NO;
    wkWebView.scrollView.userInteractionEnabled = NO;
    if (@available(iOS 11.0,*)) {
        wkWebView.scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
    }
    wkWebView.scrollView.bounces = NO;
    wkWebView.backgroundColor = [UIColor clearColor];
    
    return wkWebView;
}

@end

使用的时候,根据业务需求提前预初始化 prepareWithCount:多个WKWebView。使用是时候直接调用单例的getWKWebViewFromPool 得到一个WKWebView即可。

实际测试中,发现页面渲染实际缩短了一倍,旧款设备提升明显。

相关文章:让你的WKWebView支持自动布局----Auto Layout

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:7942463
帖子:1588486
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP