布景
早从19年 iOS 13开端Apple就主张咱们将App中运用UIWebView的当地切换为WKWebView了。
ITMS-90809: Deprecated API Usage – Apple will stop accepting submissions of apps that use UIWebView APIs . See developer.apple.com/documentati… for more information.
按照Apple2019年12月13日的文档,20年4月,新应用有必要运用WKWebView代替UIWebView,20年12月,应用更新有必要运用WKWebView替换UIWebView。详细的时刻点可以看下面这张图(有点像是找前史的感觉..)
不过好像Apple觉得可能这样太苛责了,或许商店改动的App比较少的原因,后边将这个时刻放的宽松了些文档,会留给开发者更多的时刻,后续详细的截止时刻再告诉,可是为了更多的时刻兼容WKWebView,主张仍是更早的替换,咱们的App已经将内容展现的部分替换为了WKWebView,可是对于获取UserAgent的部分还运用的UIWebView的API,本篇文章就来讨论运用WKWebView获取并设置UA的实践。
查找项目是否包括UIWebView的代码
- 搜索项目代码,查找是否有
UIWebView
的代码 - 查看SDK是否运用
UIWebView
,在终端指令行下cd到项目目录,输入下面指令:grep -r UIWebView .
找到所有包括UIWebView的SDK
UIWebView获取UA
UIWebView *webView = [[UIWebView alloc] initWithFrame:CGRectZero];
NSString *userAgent = [webView stringByEvaluatingJavaScriptFromString:@"navigator.userAgent"];
NSLog(@"userAgent :%@", userAgent);
WKWebView获取UA
WKWebView *webView = [[WKWebView alloc] initWithFrame:CGRectZero];
[wkWebView evaluateJavaScript:@"navigator.userAgent" completionHandler:^(id result, NSError *error) {
NSLog(@"userAgent :%@", result);
}];
怎么修正UA
这种需求太常见了,App内嵌的H5页面有时候需求判别App的版别,App的类型等等信息,这些信息在H5页面初始化的时候作为参数,经过UA来进行获取,所以就有了App修正UA的操作,当然这样的修正大部分是在默许的UA上增加所需求的元素。
网上常见的一种最佳实践方法是经过UIWebView获取UA并修正,然后经过WKWebView来进行页面的真实加载,这种的不符合咱们说的将UIWebView全部替换的思路,所以这儿不展开研讨,这是提一下这一种方法的确不错,UIWebView获取UA是同步的,这样获取修正比较方便,同时也不影响WKWebView加载主题内容,可是运用UIWebView的API不知道啥时候就可能被Apple封杀…
经过UserDefaults修正
由于WKWebView有一个特性,在初始化时会获取UserDefaults中“UserAgent”这个key的值,这需求咱们在真实运用的WKWebView之前要创建一个WKWebView获取它默许的UA
webView = WKWebView();
webView?.evaluateJavaScript("navigator.userAgent", completionHandler: { (obj: Any?, error: Error?) in
guard let ua = obj as? String else {
return
}
let customUA = "(ua) Custom User Agent"
UserDefaults.standard.register(defaults: ["UserAgent": customUA])
UserDefaults.standard.synchronize()
})
这种方法在特定版别会有问题 后边会详细说下这个问题
经过WKWebView.customUserAgent设置
这种方法其实和第一种方法并没有什么差别,并且还比较复杂,由于只对这一个WebView有效
let fakeWebView = WKWebView();
fakeWebView.evaluateJavaScript("navigator.userAgent", completionHandler: { (obj: Any?, error: Error?) in
guard let ua = obj as? String else {
return
}
let customUA = "(ua) Custom User Agent"
let realWebView = WKWebView()
realWebView.customUserAgent = customUA
})
let oldUserAgent = webView.value(forKey: "userAgent") as? String ?? ""
webView.customUserAgent = "(oldUserAgent) xxx"
这儿获取UA的webView和终究加载内容的WebView并不是同一个后边会说明原因
经过applicationNameForUserAgent设置
- config的此特点与上一个特点(webview.customUserAgent)不同,不是将设置的字符串彻底变成你所设置的值
- 它将字符串集增加到WebView的默许UserAgent并履行它。
- 这正好便是咱们想要的,您所要做的便是设置要增加的字符串。
- 修正后的UserAgent,如:Mozilla/5.0 (iPhone; CPU iPhone OS 13_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Custom UserAgent
let config = WKWebViewConfiguration()
config.applicationNameForUserAgent = "Custom User Agent"
let webview = WKWebView(frame: .zero, configuration: config)
还可以在WebView的base类里面增加
NSString *userAgent = [self valueForKey:@"applicationNameForUserAgent"];
userAgent = [userAgent stringByAppendingString:[NSString stringWithFormat:@"/myapp/%@", CURRENTAPPVERSION]];
[self setValue:userAgent forKey:@"applicationNameForUserAgent"];
在base类的初始化中增加上面的代码,经过applicationNameForUserAgent
来获取的userAgent是不包括Mozilla/5.0 (iPhone; CPU iPhone OS 9_3 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko)
的这是默许的一段,此刻userAgent打印为Mobile/13E230
,而H5获取到的UA打印出来为完整的Mozilla/5.0 (iPhone; CPU iPhone OS 9_3 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Mobile/13E230/myapp/1.0.0
但这个API是私有的运用的话要小心一些
以上三种方法体系采用的优先级
customUserAgent > UserDefault > applicationNameForUserAgent
- 左边优先级高于右侧
- 假如设置了customUserAgent或UserDefaults方法,则applicationNameForUserAgent将被疏忽。
- applicationNameForUserAgent仅增加到了webview具有的默许UserAgent中。(applicationNameForUserAgent被赋得值便是UA自定义的部分)
Xcode15 iOS 17 遇到的问题
上面的经过NSUserDefault的方法修正UA的在iOS17,Xcode15打包的版别上用不啦,会发现这样设置之后前端获取到的UA并不包括咱们自定义的部分,下一篇文章将会针对这个问题深化源码进行详细的剖析,这儿先知道这个定论就好啦,可以参阅这篇文章 遇到这个问题,咱们就可以运用其他两种方法来设置修正UA。
注意事项
- 修正UA的过程必定要在
loadRequest
之前,否则的话可能会导致修正了可是第一次不生效的状况(运用WKWebView是异步的操作,必定要把这部分考虑进去) - 获取并修正userAgent的webView目标跟加载网页的webView不是同一个目标 否则的话也会呈现第一次设置不生效的状况,可以参阅这片文章 参阅了下网上的文章这个问题呈现貌似是在iOS8以后,履行
evaluateJavaScript
后就设置不上了 - WKWebView的创建以及履行JS的方法evaluateJavaScript都有必要在主线程操作 WKWebView的渲染是在其他线程中,需求回调到主线程中进行相应的操作
Ref
NSUserDefaults中的registerDefaults
记运用WKWebView修正user-agent在iOS 12踩的一个坑
UserAgent cannot be changed from UserDefaults only iOS 17 Device using Xcode 15