iOS之UIWebView的坑
背景:我厂这个版本在开发航拍图,是一个H5页面,但是就是一个H5页面竟然引起了APP的crash。在当前航拍图页面,app进入后台,会直接crash。挂在gpus_returnnotpermittedkillclient
这个bug是iOS10.8以后就有的,特大好消息就是,iOS11苹果就把这个bug修复了,所以iOS11不会出现。
原因是,iOS进入后台禁止调用webGL,一帧都不允许,而这个H5还在调用,所以直接崩溃。而且游戏里面使用的openGL,在进入后台的时候是直接停止的
E04598C5-7BAD-4A29-B686-39FC80115D91.f9475027fb52451fa7a58f23c72e3c3a.png失败方案:
参考链接:其中一个解决方案
[https://forums.developer.apple.com/thread/30896]
1.webView loadRequest 之间调用,set bEnable NO,但是会引起webView上整张图都加载不出来。
2.进入后台的时候 set bEnable NO,进入前台 set bEnable YES,但是依然没有什么用。
typedef void (*CallFuc)(id, SEL, BOOL);
typedef BOOL (*GetFuc)(id, SEL);
-(BOOL)webView:(UIWebView*)view enableGL:(BOOL)bEnable
{
BOOL bRet = NO;
do
{
Ivar internalVar = class_getInstanceVariable([view class], "_internal");
if (!internalVar)
{
NSLog(@"enable GL _internal invalid!");
break;
}
UIWebViewInternal* internalObj = object_getIvar(view, internalVar);
Ivar browserVar = class_getInstanceVariable(object_getClass(internalObj), "browserView");
if (!browserVar)
{
NSLog(@"enable GL browserView invalid!");
break;
}
id webbrowser = object_getIvar(internalObj, browserVar);
Ivar webViewVar = class_getInstanceVariable(object_getClass(webbrowser), "_webView");
if (!webViewVar)
{
NSLog(@"enable GL _webView invalid!");
break;
}
id webView = object_getIvar(webbrowser, webViewVar);
if (!webView)
{
NSLog(@"enable GL webView obj nil!");
}
if(object_getClass(webView) != NSClassFromString(@"WebView"))
{
NSLog(@"enable GL webView not WebView!");
break;
}
SEL selector = NSSelectorFromString(@"_setWebGLEnabled:");
IMP impSet = [webView methodForSelector:selector];
CallFuc func = (CallFuc)impSet;
func(webView, selector, bEnable);
SEL selectorGet = NSSelectorFromString(@"_webGLEnabled");
IMP impGet = [webView methodForSelector:selectorGet];
GetFuc funcGet = (GetFuc)impGet;
BOOL val = funcGet(webView, selector);
bRet = (val == bEnable);
}while(NO);
return bRet;
}
最终解决方案有两个:
1.H5协议,暴露出可以停止绘制和重新绘制的方法,app端在进前台和后台的时候调用。
2.用WKWebView把UIWebView替换掉。
参考文档:[https://developer.apple.com/documentation/webkit/wkwebview]
一些我用到的WKWebView代理如下,详细的参考官方文档;
- (void)loadWebViewWithURL:(NSString *)urlString
{
NSURL *url = [self rtCreateWebViewURL:urlString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setValue:[AIFAppContext sharedInstance].appName forHTTPHeaderField:@"X-AJK-APP"];
NSString *cv = [[AJKSettingsManager sharedInstance] getAppVersion]?[[AJKSettingsManager sharedInstance] getAppVersion]:@"";
[request setValue:cv forHTTPHeaderField:@"X-AJK-CV"];
[self.webView loadRequest:request];
}
- (NSURL *)rtCreateWebViewURL:(NSString *)urlString
{
return [NSURL URLWithString:urlString];
}
pragma mark - WKNavigationDelegate
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation{
[self routeHandleWithRequest:webView.URL];
}
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation{
weakify(self);
[webView evaluateJavaScript:@"document.title" completionHandler:^(id _Nullable obj, NSError * _Nullable error) {
if (obj) {
strongify(self);
NSString *title = [NSString stringWithFormat:@"%@",obj];
self.title = title;
}
}];
NSURL *requestURL = webView.URL;
NSString *host = [requestURL host];
if ([host rangeOfString:@"anjuke.com" options:NSCaseInsensitiveSearch].location != NSNotFound
|| [host rangeOfString:@"58.com" options:NSCaseInsensitiveSearch].location != NSNotFound
|| [host rangeOfString:@"anjuke.test" options:NSCaseInsensitiveSearch].location != NSNotFound) {
weakify(self);
[webView evaluateJavaScript:[NSString stringWithFormat:@"getShareContents()"] completionHandler:^(id _Nullable obj, NSError * _Nullable error) {
if (obj) {
strongify(self);
NSString *str = [NSString stringWithFormat:@"%@",obj];
if (str.length > 0) {
NSArray *shares = [str JSONValue];
if ([shares isKindOfClass:[NSArray class]] && shares.count > 0) {
[self setShareDicFromArray:shares];
[self showShareBtn];
}
}
}
}];
}
[self.activity removeFromSuperview];
}
- (void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error{
if (![self checkNetwork]) {
[self.errorView showInView:self.view type:RTMessageTypeNoNetWork target:self action:@selector(reloadWebView)];
}
[self.activity removeFromSuperview];
}
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error{
}
pragma mark - WKScriptMessageHandler
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{
}
html的alert不弹的问题
需要实现WKWebView的UIDelegate
#pragma mark - WKUIDelegate
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler{
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"提示" message:message?:@"" preferredStyle:UIAlertControllerStyleAlert];
[alertController addAction:([UIAlertAction actionWithTitle:@"确认" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
completionHandler();
}])];
[self presentViewController:alertController animated:YES completion:nil];
}
- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL))completionHandler{
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"提示" message:message?:@"" preferredStyle:UIAlertControllerStyleAlert];
[alertController addAction:([UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
completionHandler(NO);
}])];
[alertController addAction:([UIAlertAction actionWithTitle:@"确认" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
completionHandler(YES);
}])];
[self presentViewController:alertController animated:YES completion:nil];
}
- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * _Nullable))completionHandler{
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:prompt message:@"" preferredStyle:UIAlertControllerStyleAlert];
[alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
textField.text = defaultText;
}];
[alertController addAction:([UIAlertAction actionWithTitle:@"完成" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
completionHandler(alertController.textFields[0].text?:@"");
}])];
[self presentViewController:alertController animated:YES completion:nil];
}
所以下版本计划将原本app里面的ADViewController的UIWebView替换成WKWebView,希望没有什么新坑!
网友评论