属性customUserAgent

WKWebView有一个属性customUserAgent

/*! @abstract The custom user agent string or nil if no custom user agent string has been set.
*/
@property (nullable, nonatomic, copy) NSString *customUserAgent API_AVAILABLE(macosx(10.11), ios(9.0));

问题1

在一次使用webView的时候出现了这样一个问题:在iOS9上加载显示空白,iOS12上加载显示成功,但是加载的不是手机上的网页,而是网页版。

网页版:
网页版
手机版:
手机版

可以看出同一个链接地址,手机版和网页版区别还是很大的,手机上我们需要加载手机版网页,才能显示正常。

找了找问题,后来发现是设置customUserAgent位置不当导致的。

起初我在创建webView的时候直接设置customUserAgent:

    self.webView = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:config];
    self.webView.UIDelegate = self;
    self.webView.navigationDelegate = self;
    //self.webView.customUserAgent = @"xxx";//bug,切勿再此设置,切记在didFinishNavigation处设置。
    NSURLRequest *request = [NSURLRequest requestWithURL:self.webURL];
    [self.webView loadRequest:request];
    [self.view addSubview:self.webView];

后来将这里的设置注释掉,发现加载就正常了,iOS9加载正常,iOS12也加载正常,而且加载的是手机版页面,而不是网页版。

虽然现实正常了,但是js端小伙伴要用到userAgent判断是哪一个端,iOS,安卓还是h5,所以就还是需要设置userAgent,将设置放在网页加载成功后设置:

- (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation {
    NSLog(@"webView load finished");
    webView.customUserAgent = @"xxx";
}

这里不设置userAgent的话,js端是不会把事件回调给OC端的,因为我们的js根据userAgen判断是哪一个端,然后js交互调用不同的方法传进行传值。如果js端不用这个userAgent的话不用设置也可以。

思考

为什么我们在创建webView的时候设置userAgent,有些机型会加载H5的网页而不是手机浏览器的网页内容?

这就得知道userAgent的作用是什么,浏览器通过userAgent来判断是哪一端,百度“移动和pc userAgent判断”。

我们在创建webView的时候给userAgent赋值,这样的话,覆盖了原有的userAgent的值,导致浏览器无法判断是pc端还是手机端,所以在手机上加载了pc上的网页。

再看一下customUserAgent这个属性在文档中的描述,如果我们设置,原customUserAgent的值就会被覆盖。

关于customUserAgent

作用

其他端用customUserAgent来判断是是哪一端,pc端还是手机端。

读customUserAgent的值

在webView未加载出来前获取webView的customUserAgent,会获取不到。只有loading之后才能获取到值,获取办法:

- (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation
{
    NSLog(@"webView load finished");
    [self.loadingView stopAnimating];
    
    //设置userAgent
    [self.webView evaluateJavaScript:@"navigator.userAgent" completionHandler:^(id _Nullable result, NSError * _Nullable error) {

        NSString *newUserAgent = [NSString stringWithFormat:@"%@iphone iOS xxx",result];
        self.webView.customUserAgent = newUserAgent;

        NSLog(@"customUserAgent : %@",self.webView.customUserAgent);
    }];
}

通过js方法获取userAgent,回调里的result即userAgent。

打印了两个手机的userAgent

iPhone6

Mozilla/5.0 (iPhone; CPU iPhone OS 12_1_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/16D57i phonexxx

iPhoneX

Mozilla/5.0 (iPhone; CPU iPhone OS 12_3_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148i phonexxx

iPadAri3 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/605.1.15 (KHTML, like Gecko)

iPhone11模拟器 Mozilla/5.0 (iPhone; CPU iPhone OS 14_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148

需要设置App Transport Security Settings。

上面的设置方式在新一些的iOS版本中可能会存在customUserAgent字符串被重复的拼接 iphone iOS xxx 的问题,较早一些的版本我还没发现这个问题,今天发现是在iOS 14上,重新来编辑一下笔记。

使用下面的方式来设置,避免多次重复的设置和多次拼接我们需要添加的字符串。

例如我们要加一个版本号

	NSString *versionIdentifier = [[[NSBundle mainBundle] infoDictionary] objectForKey:(NSString *)kCFBundleVersionKey]
    [webView evaluateJavaScript:@"navigator.userAgent" completionHandler:^(id _Nullable result, NSError * _Nullable error) {
        if (![result containsString:versionIdentifier]) {
            NSString *deviceIdentifier = (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) ? @"iPad" :@"iPhone";
            webView.customUserAgent = [NSString stringWithFormat:@"%@^%@^%@",result,deviceIdentifier,versionIdentifier];
        }
        NSLog(@"user-Agent : %@",webView.customUserAgent);
    }];

调试一下就知道是什么问题,该怎么处理了,很简单,不赘述。

设置customUserAgent

上面我们获取到userAgent后,使用NSString *newUserAgent = [NSString stringWithFormat:@"%@iphonevhallclass",result]; 拼接了一段“iphone iOS xxx”,这个跟js商量好就行。这样设置不会覆盖userAgent原有值。

问题2

H5的小伙伴需要在网页加载前就用userAgent,要判断是iOS还是安卓或者是pc。

感觉这种网页没加载就要userAgent的值的做法不是很合理,网页未加载前我们拿不到userAgent的值,如果设置成别的值就会出现userAgent被覆盖问题。

    self.webView = [[WKWebView alloc] initWithFrame:CGRectMake(0, 20, CGRectGetWidth(self.view.frame), CGRectGetHeight(self.view.frame)-20) configuration:config];
    self.webView.UIDelegate = self;
    self.webView.navigationDelegate = self;
    self.webView.allowsBackForwardNavigationGestures = YES;
    self.webView.customUserAgent = @"Mozilla/5.0 (iPhone; CPU iPhone OS 12_1_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/16D57 iphone iOS xxx";

直接用了iPhone6的userAgent后面拼接上’iphone iOS xxx‘,在开始创建的时候直接设置上了。

这是个投机的解决办法,最好不要这样,H5的同学还有没有其他的办法呢?非得网页加载前就用userAgent?这合理吗?

Logo

Agent 垂直技术社区,欢迎活跃、内容共建,欢迎商务合作。wx: diudiu5555

更多推荐