布景

早从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。详细的时刻点可以看下面这张图(有点像是找前史的感觉..)

UserAgent获取与修正

不过好像Apple觉得可能这样太苛责了,或许商店改动的App比较少的原因,后边将这个时刻放的宽松了些文档,会留给开发者更多的时刻,后续详细的截止时刻再告诉,可是为了更多的时刻兼容WKWebView,主张仍是更早的替换,咱们的App已经将内容展现的部分替换为了WKWebView,可是对于获取UserAgent的部分还运用的UIWebView的API,本篇文章就来讨论运用WKWebView获取并设置UA的实践。

查找项目是否包括UIWebView的代码

  1. 搜索项目代码,查找是否有UIWebView的代码
  2. 查看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

iOS修正WebView的UserAgent

NSUserDefaults中的registerDefaults

记运用WKWebView修正user-agent在iOS 12踩的一个坑

WKWebView iOS17设置UserAgent

UserAgent cannot be changed from UserDefaults only iOS 17 Device using Xcode 15

iOS 设置userAgent