UIWebView 桌面网站无法运行
UIWebView Desktop Website Won't Work
部分是作为学习一点 iOS 编程的练习,部分是因为我希望我在 iPad 上有一个 WhatsApp 客户端,我正在尝试创建一个我可以个人使用的应用程序我的 iPad 的 WhatsApp 客户端。它所做的只是在 UIWebView 中加载 web.whatsapp.com 桌面站点,如下所示:
override func viewDidLoad() {
NSUserDefaults.standardUserDefaults().registerDefaults(["UserAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/601.5.17 (KHTML, like Gecko) Version/9.1 Safari/601.5.17"])
super.viewDidLoad()
self.webView.frame = self.view.bounds
self.webView.scalesPageToFit = true
// Do any additional setup after loading the view, typically from a nib.
let url = NSURL(string: "https://web.whatsapp.com")
let requestObj = NSMutableURLRequest(URL: url!)
webView.loadRequest(requestObj)
//webView.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
}
这没问题。它实际上加载了正确的 webapp,而不是像服务器检测到移动设备时通常发生的那样重定向到 whatsapp 主页。但是,它没有向我显示用于登录的二维码屏幕,而是向我显示了以下内容:
现在,如果我在我的 iPad 上使用 Safari 中的 WhatsApp Web(并请求桌面版),它工作得很好。如您所见,我正在通过设置 UserAgent 为我的 UIWebView 请求桌面站点。现在,我想知道为什么它在 UIWebView 中不起作用,是否可能需要设置其他一些 header 或值才能说服 App 在我的 UIWebView 控件中工作?
编辑
我已通过将 Boris Verebsky 的代码从 Objective-C 转换为 Swift 来更改为 WKWebView。然而,虽然一开始我看到的是和以前一样的屏幕(告诉我使用另一个浏览器),但在改变它并试图让它工作之后,我发现自己的屏幕是空白的。什么都没有出现了。
这是我目前的完整代码:
import UIKit
import WebKit
class ViewController: UIViewController, WKNavigationDelegate {
@IBOutlet var webView: WKWebView!
override func viewDidLoad() {
super.viewDidLoad()
self.webView = WKWebView(frame: self.view.bounds)
if #available(iOS 9.0, *) {
self.webView.customUserAgent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/601.5.17 (KHTML, like Gecko) Version/9.1 Safari/601.5.17"
} else {
// Fallback on earlier versions
NSUserDefaults.standardUserDefaults().registerDefaults(["UserAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/601.5.17 (KHTML, like Gecko) Version/9.1 Safari/601.5.17"])
}
self.view!.addSubview(self.webView)
self.webView.navigationDelegate = self
// Do any additional setup after loading the view, typically from a nib.
let url: NSURL = NSURL(string: "http://web.whatsapp.com")!
let urlRequest: NSURLRequest = NSURLRequest(URL: url)
webView.loadRequest(urlRequest)
}
func webView(webView: WKWebView, decidePolicyForNavigationAction: WKNavigationAction, decisionHandler: WKNavigationActionPolicy -> Void) {
decisionHandler(.Allow)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
可能是我从Objective-C到Swift的转换不正确。我不熟悉Objective-C,所以很有可能。
你真的应该切换到使用 WKWebView
然后你可以简单地使用 customUserAgent
直接在网络视图上设置你想要的代理字符串。
检查用户代理后,https://web.whatsapp.com checks that client supports indexeddb, probably by some JavaScript. It's easy to notice - if you will trace all redirects your app performed, then you will find redirect to https://web.whatsapp.com/browsers.html?missing=indexeddb。就我而言,我使用简单的 NSURLProtocol
子类来记录所有重定向。遗憾的是,NSURLProtocol
不再适用于 WKWebView
。
UIWebView
根本没有实现 indexeddb。据我所知,我自己没有简单的方法来实现 indexeddb 支持。
您可以通过访问 UIWebView
中的 html5test.com 轻松检查 indexeddb 支持。你会看到像这样的东西:
但是WKWebView
确实支持indexeddb:
我已经检查 web.whatsapp.com 使用自定义用户代理在 iOS WKWebView
中加载,使用 http://whatsmyuseragent.com 从我的桌面 Safari 中获取,它显示了二维码预期的。此外,迁移到 WKWebView
将增加一些好处,例如提高性能和稳定性。
我在测试中使用了以下代码:
#import <WebKit/WebKit.h>
@interface ViewController () <WKNavigationDelegate>
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.webView = [[WKWebView alloc] initWithFrame:self.view.bounds];
self.webView.customUserAgent = @"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/601.6.17 (KHTML, like Gecko) Version/9.1.1 Safari/601.6.17";
[self.view addSubview:self.webView];
self.webView.navigationDelegate = self;
NSURL *url = [NSURL URLWithString:@"http://web.whatsapp.com"];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
[self.webView loadRequest:urlRequest];
}
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(nonnull WKNavigationAction *)navigationAction decisionHandler:(nonnull void (^)(WKNavigationActionPolicy))decisionHandler {
decisionHandler(WKNavigationActionPolicyAllow);
}
@end
虽然是Objective-C,但转换成swift应该很简单。
更新:
你对 WKWebView
的看法是空白的原因是运输安全。将 https://web.whatsapp.com
用作 URL(注意 HTTPS 而不是 HTTP),或者在您的应用程序 info.plist
中添加 NSAllowsArbitraryLoads: YES
部分是作为学习一点 iOS 编程的练习,部分是因为我希望我在 iPad 上有一个 WhatsApp 客户端,我正在尝试创建一个我可以个人使用的应用程序我的 iPad 的 WhatsApp 客户端。它所做的只是在 UIWebView 中加载 web.whatsapp.com 桌面站点,如下所示:
override func viewDidLoad() {
NSUserDefaults.standardUserDefaults().registerDefaults(["UserAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/601.5.17 (KHTML, like Gecko) Version/9.1 Safari/601.5.17"])
super.viewDidLoad()
self.webView.frame = self.view.bounds
self.webView.scalesPageToFit = true
// Do any additional setup after loading the view, typically from a nib.
let url = NSURL(string: "https://web.whatsapp.com")
let requestObj = NSMutableURLRequest(URL: url!)
webView.loadRequest(requestObj)
//webView.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
}
这没问题。它实际上加载了正确的 webapp,而不是像服务器检测到移动设备时通常发生的那样重定向到 whatsapp 主页。但是,它没有向我显示用于登录的二维码屏幕,而是向我显示了以下内容:
现在,如果我在我的 iPad 上使用 Safari 中的 WhatsApp Web(并请求桌面版),它工作得很好。如您所见,我正在通过设置 UserAgent 为我的 UIWebView 请求桌面站点。现在,我想知道为什么它在 UIWebView 中不起作用,是否可能需要设置其他一些 header 或值才能说服 App 在我的 UIWebView 控件中工作?
编辑
我已通过将 Boris Verebsky 的代码从 Objective-C 转换为 Swift 来更改为 WKWebView。然而,虽然一开始我看到的是和以前一样的屏幕(告诉我使用另一个浏览器),但在改变它并试图让它工作之后,我发现自己的屏幕是空白的。什么都没有出现了。
这是我目前的完整代码:
import UIKit
import WebKit
class ViewController: UIViewController, WKNavigationDelegate {
@IBOutlet var webView: WKWebView!
override func viewDidLoad() {
super.viewDidLoad()
self.webView = WKWebView(frame: self.view.bounds)
if #available(iOS 9.0, *) {
self.webView.customUserAgent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/601.5.17 (KHTML, like Gecko) Version/9.1 Safari/601.5.17"
} else {
// Fallback on earlier versions
NSUserDefaults.standardUserDefaults().registerDefaults(["UserAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/601.5.17 (KHTML, like Gecko) Version/9.1 Safari/601.5.17"])
}
self.view!.addSubview(self.webView)
self.webView.navigationDelegate = self
// Do any additional setup after loading the view, typically from a nib.
let url: NSURL = NSURL(string: "http://web.whatsapp.com")!
let urlRequest: NSURLRequest = NSURLRequest(URL: url)
webView.loadRequest(urlRequest)
}
func webView(webView: WKWebView, decidePolicyForNavigationAction: WKNavigationAction, decisionHandler: WKNavigationActionPolicy -> Void) {
decisionHandler(.Allow)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
可能是我从Objective-C到Swift的转换不正确。我不熟悉Objective-C,所以很有可能。
你真的应该切换到使用 WKWebView
然后你可以简单地使用 customUserAgent
直接在网络视图上设置你想要的代理字符串。
检查用户代理后,https://web.whatsapp.com checks that client supports indexeddb, probably by some JavaScript. It's easy to notice - if you will trace all redirects your app performed, then you will find redirect to https://web.whatsapp.com/browsers.html?missing=indexeddb。就我而言,我使用简单的 NSURLProtocol
子类来记录所有重定向。遗憾的是,NSURLProtocol
不再适用于 WKWebView
。
UIWebView
根本没有实现 indexeddb。据我所知,我自己没有简单的方法来实现 indexeddb 支持。
您可以通过访问 UIWebView
中的 html5test.com 轻松检查 indexeddb 支持。你会看到像这样的东西:
但是WKWebView
确实支持indexeddb:
我已经检查 web.whatsapp.com 使用自定义用户代理在 iOS WKWebView
中加载,使用 http://whatsmyuseragent.com 从我的桌面 Safari 中获取,它显示了二维码预期的。此外,迁移到 WKWebView
将增加一些好处,例如提高性能和稳定性。
我在测试中使用了以下代码:
#import <WebKit/WebKit.h>
@interface ViewController () <WKNavigationDelegate>
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.webView = [[WKWebView alloc] initWithFrame:self.view.bounds];
self.webView.customUserAgent = @"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/601.6.17 (KHTML, like Gecko) Version/9.1.1 Safari/601.6.17";
[self.view addSubview:self.webView];
self.webView.navigationDelegate = self;
NSURL *url = [NSURL URLWithString:@"http://web.whatsapp.com"];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
[self.webView loadRequest:urlRequest];
}
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(nonnull WKNavigationAction *)navigationAction decisionHandler:(nonnull void (^)(WKNavigationActionPolicy))decisionHandler {
decisionHandler(WKNavigationActionPolicyAllow);
}
@end
虽然是Objective-C,但转换成swift应该很简单。
更新:
你对 WKWebView
的看法是空白的原因是运输安全。将 https://web.whatsapp.com
用作 URL(注意 HTTPS 而不是 HTTP),或者在您的应用程序 info.plist
NSAllowsArbitraryLoads: YES