关于WKWebView使用总结

闲着无聊,写写WKWebview的使用

WKWebViewde 初始化

WKUserContentController *wkUController = [[WKUserContentController alloc] init];
WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
NSString *jSString =@"";
config.allowsInlineMediaPlayback = YES;
if ([[UIDevice currentDevice].systemVersion floatValue] <= 9.0) {
    config.mediaPlaybackAllowsAirPlay = NO;
    config.mediaPlaybackRequiresUserAction = NO;
    } else {
    config.allowsPictureInPictureMediaPlayback = NO;
    config.allowsAirPlayForMediaPlayback = NO;
    config.requiresUserActionForMediaPlayback = NO;
    }
config.selectionGranularity = (WKSelectionGranularityCharacter | WKSelectionGranularityDynamic);
config.preferences = [[WKPreferences alloc] init];
config.preferences.minimumFontSize = 10;
config.preferences.javaScriptEnabled = YES;
config.processPool = [[WKProcessPool alloc] init];
WKUserScript *wkUserScript = [[WKUserScript alloc] initWithSource:jSString injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES];
config.userContentController = wkUController;
[wkUController addUserScript:wkUserScript];
[wkUController addUserScript:[self addUserScript]];
_scriptMessageDelegagte = [[WeakScriptMessageDelegate alloc] initWithDelegate:self];
[config.userContentController addScriptMessageHandler:self.scriptMessageDelegagte name:@"AppModel"];
_webView = [[WKWebView alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth([UIScreen mainScreen].bounds), CGRectGetHeight([UIScreen mainScreen].bounds)) configuration:config];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@""] cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:30];
[self.webView loadRequest:request];
self.webView.navigationDelegate = self;
self.webView.UIDelegate = self;
复制代码

WKWebView 禁止长按功能处理

/**
 禁止长安弹出框
 
 @return WKUserScript
 */
- (WKUserScript *)addUserScript {
    NSString *source = @"var style = document.createElement('style'); \
    style.type = 'text/css'; \
    style.innerText = '*:not(input):not(textarea) { -webkit-user-select: none; -webkit-touch-callout: none; }'; \
    var head = document.getElementsByTagName('head')[0];\
    head.appendChild(style);";
    // javascript注入
    WKUserScript *noneSelectScript = [[WKUserScript alloc] initWithSource:source injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES];
    return noneSelectScript;
}
复制代码

WKWebView 关于isSecureTextEntry 的奔溃处理(貌似是WKWebView的bug)


+ (void)catchWkWebViewContentViewCrash {
    const char *className = @"WKContentView".UTF8String;
    Class WKContentViewClass = objc_getClass(className);
    SEL isSecureTextEntry = NSSelectorFromString(@"isSecureTextEntry");
    SEL secureTextEntry = NSSelectorFromString(@"secureTextEntry");
    BOOL addIsSecureTextEntry = class_addMethod(WKContentViewClass, isSecureTextEntry, (IMP)isSecureTextEntryIMP, "B@:");
    BOOL addSecureTextEntry = class_addMethod(WKContentViewClass, secureTextEntry, (IMP)secureTextEntryIMP, "B@:");
    if (!addIsSecureTextEntry || !addSecureTextEntry) {
        DLog(@"WKContentView-Crash->修复失败");
    }
}

BOOL isSecureTextEntryIMP(id sender, SEL cmd) {
    return NO;
}

BOOL secureTextEntryIMP(id sender, SEL cmd) {
    return NO;
}


复制代码

WKWebView 支持多种网页样式(也可以支持网页小游戏)

config.selectionGranularity = (WKSelectionGranularityCharacter | WKSelectionGranularityDynamic);
复制代码

JS与原生交互处理

  • 需要注册交互模型对象
[config.userContentController addScriptMessageHandler:self.scriptMessageDelegagte name:@"AppModel"];
复制代码
  • 注册交互模型之后,内存不释放的问题定位

1.初次定位是设置这个WKScriptMessageHandler(delegate)之后,webView释放不掉

2.注释这句代码,webView正常释放

3.解决方案:

  • 新建一个对象模型,定义初始化方法
@interface WeakScriptMessageDelegate : NSObject <WKScriptMessageHandler>

@property (nonatomic, weak) id <WKScriptMessageHandler> scriptDelegate;

- (instancetype)initWithDelegate:(id<WKScriptMessageHandler>)scriptDelegate;

@end


@implementation WeakScriptMessageDelegate

- (instancetype)initWithDelegate:(id<WKScriptMessageHandler>)scriptDelegate {
    self = [super init];
    if (self) {
        _scriptDelegate = scriptDelegate;
    }
    return self;
}

- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
    [self.scriptDelegate userContentController:userContentController didReceiveScriptMessage:message];
}

复制代码

4.替换delegate (WeakScriptMessageDelegate)

 [config.userContentController addScriptMessageHandler:self.scriptMessageDelegagte name:@"AppModel"];
复制代码

WKWebView 调用原生弹窗

  • 需要在相应的delegate方法内支持
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler {
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"提示" message:message delegate:nil cancelButtonTitle:@"我知道了" otherButtonTitles:nil, nil];
    [alert show];
    completionHandler();
}
复制代码
  • 内容限制,只能取message,最好的方案是 js直接调用原生的方法,原生支持

WKWebView JS与原生交互

  • JS端想掉原生的方法需要调用下面的方法来发送
window.webkit.messageHandlers.<AppModel>.postMessage(data)
复制代码
  • data内容多为json模型
{
    body:login
    params:xxxx
}
params内容可以为string、json对象等等,body为方法名
复制代码
  • Native相应处理
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
    NSDictionary *dict = message.body;
    if ([dict[@"body"] isEqualToString:@"xxx"]) {
        [self xxx];
    } else if ([dict[@"body"] isEqualToString:@"xxxxx"]) {
        [self xxxxx:dict[@"params"]];
    }
}

复制代码
  • Native 调用JS代码
//callback 为js传给原生的参数
NSString *js = [NSString stringWithFormat:@"%@('%@')", callback,result];
NSLog(@"js is %@",js);
[self.webView evaluateJavaScript:js completionHandler:^(id _Nullable res, NSError * _Nullable error) {
    NSLog(error?@"调用JS失败":@"调用JS成功");
    }];
当需要传多个参数时,可以这样写:NSString *js = [NSString stringWithFormat:@"%@('%@','%@')", callback,result];
复制代码
  • 注意事项:
1.传给JS的参数不能包含空格、换行等等(\n  \r)
2.当传的参数是json是,可以先转为string,去处特殊字符,然后在处理

复制代码

需要动态设置标题或者需要知道当前加载进度的时候,可以这样写

//监听导航栏标题变化
[self.webView addObserver:self forKeyPath:@"title" options:NSKeyValueObservingOptionNew context:nil];
//监听webView加载进度
[self.webView addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionNew context:nil];

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
    if ([keyPath isEqualToString:@"estimatedProgress"]) {
        double progress = [change[@"new"] doubleValue];
        if (progress >= 1.0) {
           dissmiss
        }
        return;
    }
    if ([keyPath isEqualToString:@"title"]) {
        title  = self.webView.title;
    }
    
}

复制代码

当有webView的监听事件是,销毁webView时,会奔溃

  • 这时候,需要在remove的时候这样写
@try {
    [self.webView.configuration.userContentController removeScriptMessageHandlerForName:@"AppModel"];
    [self.webView removeObserver:self forKeyPath:@"title"];
    [self.webView removeObserver:self forKeyPath:@"estimatedProgress"];
  } @catch (NSException *exception) {
    DLog(@"exception is %@",exception);
  } @finally {
    
}

复制代码
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值