iOS之WKWebView封裝

weixin_34234823發表於2019-01-21

最近在開發的時候遇到一個麻煩的事,iOS客戶端開發使用了webview,但是發現共性問題了之後,就得每個專案都要去改動,然後我就封裝了個webview,準備以後得iOS客戶端專案統一使用這個類,出現問題了也好處理。

首先,這個封裝是針對WKWebView的封裝,我們現在使用的也是此webview。原始碼如下,也歡迎大家留言,我來完善。

@interface LLWKWebView : UIView

//web的title,時時更新
@property (nonatomic, copy  )   NSString *titleName;

//載入的H5的連結
@property (nonatomic, copy  )   NSString *url;

//自定義的UA,預設為""
@property (nonatomic, copy  )   NSString *userAgent;

//url的requestHeader裡的內容,string形式的key和value,預設@{}
@property (nonatomic, copy  )   NSDictionary *headerParams;

//message.name,message.body
@property (nonatomic, copy  )   void(^jsActionBlock)(NSString *name,id body);

//jsArray:ScriptMessageHandler方法名
- (instancetype)initWithConfig:(NSArray *)jsArray frame:(CGRect)frame;

//載入url
- (void)startLoadUrl;

//重新整理介面
- (void)wkRefresh;

//返回上一個介面---popViewController
- (void)wkPopViewController;

//返回web的history---[wkWebView goBack];
- (void)wkGoWebHistory;

//返回主介面---popToRootViewController
- (void)wkPopRootViewController;

@end
@interface LLWKWebView()<WKNavigationDelegate,WKScriptMessageHandler>
{
    NSMutableURLRequest *webRequest;
    WKWebViewConfiguration *wkConfig;
    
    NSArray *configArray;
    NSMutableDictionary *headers;
}

@property (nonatomic, copy  )   WKWebView *wkWebView;

@property (nonatomic, copy  )   UIActivityIndicatorView *loadingView;

@end

@implementation LLWKWebView

- (void)dealloc
{
    [wkConfig.userContentController removeAllUserScripts];
    _wkWebView.navigationDelegate = nil;
}

#pragma -mark init
- (instancetype)initWithConfig:(NSArray *)jsArray frame:(CGRect)frame
{
    self = [super init];
    if (self) {
        self.frame = frame;
        configArray = jsArray;
        headers = [NSMutableDictionary dictionary];
        
        _titleName = @"";
        _url = @"";
        _userAgent = @"";
        wkConfig = [[WKWebViewConfiguration alloc] init];
        _loadingView = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
        
        [self initWeb:frame];
    }
    return self;
}

- (void)initWeb:(CGRect)frame
{
    WKUserContentController *userContentController = [[WKUserContentController alloc] init];
    for (NSString *jsName in configArray) {
        [userContentController addScriptMessageHandler:self name:AI_STR_DEFAULT(jsName)];
    }
    wkConfig.userContentController = userContentController;
    
    _wkWebView = [[WKWebView alloc]initWithFrame:CGRectMake(0, 0, frame.size.width, frame.size.height) configuration:wkConfig];
    _wkWebView.navigationDelegate = self;
    [self addSubview:_wkWebView];
    
    _loadingView.center = _wkWebView.center;
    [self addSubview:_loadingView];
}

#pragma -mark setter
- (void)setUserAgent:(NSString *)userAgent
{
    _userAgent = userAgent;
    if (@available(iOS 12.0, *)){
        NSString *baseAgent = [_wkWebView valueForKey:@"applicationNameForUserAgent"];
        NSString *userAgent = [NSString stringWithFormat:@"%@ %@",baseAgent,_userAgent];
        [_wkWebView setValue:userAgent forKey:@"applicationNameForUserAgent"];
    }
    [_wkWebView evaluateJavaScript:@"navigator.userAgent" completionHandler:^(id _Nullable result, NSError * _Nullable error) {
        NSString *newUA = [NSString stringWithFormat:@"%@ %@",result,self->_userAgent];
        self->_wkWebView.customUserAgent = newUA;
    }];
}

- (void)setUrl:(NSString *)url
{
    NSString *urlString = [url stringByReplacingOccurrencesOfString:@"\r" withString:@""];
    urlString = [urlString stringByReplacingOccurrencesOfString:@"\r" withString:@""];
    urlString = [urlString stringByReplacingOccurrencesOfString:@"\r" withString:@""];
    _url = urlString;
}

- (void)setHeaderParams:(NSDictionary *)headerParams
{
    _headerParams = headerParams;
    [headers setValuesForKeysWithDictionary:_headerParams];
}

#pragma mark - webView載入
- (void)startLoadUrl
{
    if (_url && _url.length > 0)
    {
        webRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:_url] cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:20];
        NSArray *headerKeys = headers.allKeys;
        for (NSInteger i=0;i<headerKeys.count;i++) {
            NSString *key = AI_STR_DEFAULT(headerKeys[i]);
            NSString *value = AI_STR_DEFAULT(headers[key]);
            [webRequest setValue:value forHTTPHeaderField:key];
        }
        [_wkWebView loadRequest:webRequest];
    }
}

- (void)wkRefresh
{
    [self startLoadUrl];
}

#pragma mark - WKWebview
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
{
    decisionHandler(WKNavigationActionPolicyAllow);
}

- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation
{
    [self startLoading];
}

- (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation
{
    [self stopLoding];
}

- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error
{
    [self stopLoding];
    if(error.code == NSURLErrorCancelled)  {
        return;
    }
    if (error.code == NSURLErrorUnsupportedURL) {
        return;
    }
}

- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation
{
    [self stopLoding];
    self.titleName = webView.title;
}

#pragma mark - 載入JS處理
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
{
    if (_jsActionBlock) {
        _jsActionBlock(AI_STR_DEFAULT(message.name),message.body);
    }
}

#pragma -mark 方法
- (void)startLoading
{
    [_loadingView startAnimating];
    _loadingView.hidden = NO;
}

- (void)stopLoding
{
    [_loadingView stopAnimating];
    _loadingView.hidden = YES;
}

- (UIViewController *)findViewController
{
    id target=self;
    while (target) {
        target = ((UIResponder *)target).nextResponder;
        if ([target isKindOfClass:[UIViewController class]])
            break;
    }
    return target;
}

- (void)wkPopViewController{
    [[self findViewController].navigationController popViewControllerAnimated:YES];
}

- (void)wkPopRootViewController{
    [[self findViewController].navigationController popToRootViewControllerAnimated:YES];
}

- (void)wkGoWebHistory{
    if ([_wkWebView canGoBack]) {
        [_wkWebView goBack];
    }
    else{
        [self wkPopViewController];
    }
}

@end

相關文章