Luke Luke - 3 months ago 58
iOS Question

UIWebView Desktop Website Won't Work

Partly as an exercise for learning a little iOS programming, and partly because I wish I had a WhatsApp client on iPad, I am trying to create an app that I can personally use as a WhatsApp client for my iPad. All it does is load up the web.whatsapp.com desktop site in a UIWebView like so:

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);
}


This works okay. It does in fact load the correct webapp, rather than redirecting to the whatsapp home page as would usually happen when the server detects a mobile device. However, rather than presenting me with the QR Code screen for log in, it presents me with this:

enter image description here

Now, if I use WhatsApp Web from Safari on my iPad (and requesting Desktop version), it works perfectly fine. As you can see, I am requesting the Desktop site for my UIWebView by setting the UserAgent. Now, I am wondering why it would not work in the UIWebView, and whether perhaps there is some other header or value that needs to be set in order to convince the App to work within my UIWebView control?

EDIT

I have changed to WKWebView by converting Boris Verebsky's code from Objective-C to Swift. However, whilst at first I was seeing the same screen as before (telling me to use another browser), after changing it around and trying to get it to work I find myself with a blank white screen. Nothing is showing up anymore.

Blank screen

This is my full code as it currently stands:

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.
}


}


It may be that my conversion from Objective-C to Swift is incorrect. I am unfamiliar with Objective-C, so that is quite likely.

Answer

After checking user agent, 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. In my case, I've used simple NSURLProtocol subclass to log all redirects. Sadly, NSURLProtocol no longer works with WKWebView.

UIWebView doesn't implement indexeddb at all. As far as I know, there is no easy way to implement indexeddb support myself.

You can easily check indexeddb support by accessing html5test.com in UIWebView. You will see something like:

html5test.com result for UIWebView

But WKWebView does support indexeddb:

html5test.com result for WKWebView

I've checked web.whatsapp.com loading in iOS WKWebView with custom user agent, taken from my desktop Safari using http://whatsmyuseragent.com, and it shows QR code as you expected. Moreover, migration to WKWebView will add some bonuses like improved performance and stability.

I've used following code for my test:

#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

Although it's Objective-C, it should be pretty straightforward to convert into swift.

UPD:

Reason why you have blank view with WKWebView is transport security. Either use https://web.whatsapp.com as URL (note HTTPS instead of HTTP), or add NSAllowsArbitraryLoads: YES in your application info.plist

Comments