WKWebView无法加载https的URL?

24

我有一个WKWebView,应该加载以下URL:

https://buchung.salonmeister.de/place/#offer-details-page?id=907599&venueId=301655

这是我使用的代码:

import UIKit
import WebKit


class MMWKBrowserController: UIViewController {

  private let closeButtonSelector: Selector = "closeButtonTapped:"

  private var urlString: String
  private let request: NSMutableURLRequest

  private var webView: WKWebView!
  private var twoLineTitleView: UIView!
  private var titleLabel: UILabel?
  private var subTitleLabel: UILabel?
  private var indicator: UIActivityIndicatorView!


  init(urlString: String) {
    self.urlString = urlString

    println("*** Using MMWKBrowserController ***")

    var url: NSURL? = NSURL(string: urlString)
    if url == nil {
      var escapedString: String = urlString.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)!
      self.urlString = escapedString
      url = NSURL(string: escapedString)
    }

    println("url: \(url)")
    request = NSMutableURLRequest(URL: url!)

    request.setValue("Mozilla/5.0 (iPhone; CPU iPhone OS 8_4 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Version/8.0 Mobile/12H141 Safari/600.1.4", forHTTPHeaderField: "UserAgent")

    super.init(nibName: nil, bundle: nil)
  }

  required init(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
  }


  deinit {
    self.webView.removeObserver(self, forKeyPath: "loading")
    self.webView.removeObserver(self, forKeyPath: "title")
    self.webView.removeObserver(self, forKeyPath: "URL")
    self.webView.removeObserver(self, forKeyPath: "estimatedProgress")
    self.webView.stopLoading()
  }


  override func viewDidLoad() {
    super.viewDidLoad()
    createNavigationView()


    self.navigationController?.navigationBar.tintColor = MGColor.actionColor

    let config = WKWebViewConfiguration()
    self.webView = WKWebView(frame: self.view.bounds, configuration: config)
    self.view.addSubview(self.webView)


    indicator = UIActivityIndicatorView(activityIndicatorStyle: UIActivityIndicatorViewStyle.Gray)
    //indicator.backgroundColor = UIColor(white: 0.1, alpha: 0.5)
    webView.addSubview(indicator)

    self.webView.snp_makeConstraints { (make) -> Void in
      make.edges.equalTo(self.view)
    }

    indicator.snp_makeConstraints { (make) -> Void in
      make.center.equalTo(self.webView)
    }

    webView.addObserver(self, forKeyPath: "loading", options: NSKeyValueObservingOptions.New, context: nil)
    webView.addObserver(self, forKeyPath: "title", options: NSKeyValueObservingOptions.New, context: nil)
    webView.addObserver(self, forKeyPath: "URL", options: NSKeyValueObservingOptions.New, context: nil)
    webView.addObserver(self, forKeyPath: "estimatedProgress", options: NSKeyValueObservingOptions.New, context: nil)
  }


  override func viewDidDisappear(animated: Bool) {
    super.viewDidDisappear(animated)
    self.webView.stopLoading()
  }


  private func createNavigationView() {
    let closeItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.Stop, target: self, action: closeButtonSelector)
    self.navigationItem.leftBarButtonItem = closeItem

    // create center view
    let titleViewWidth = self.view.frame.size.width - 100

    twoLineTitleView = UIView(frame: CGRectMake(0, 0, titleViewWidth, 44))

    titleLabel = UILabel(frame: CGRectMake(0, 6, titleViewWidth, 16))
    titleLabel?.backgroundColor = UIColor.clearColor()
    titleLabel?.font = UIFont.boldSystemFontOfSize(16)
    titleLabel?.textAlignment = NSTextAlignment.Center

    subTitleLabel = UILabel(frame: CGRectMake(0, 21, titleViewWidth, 20))
    subTitleLabel?.backgroundColor = UIColor.clearColor()
    subTitleLabel?.font = UIFont.systemFontOfSize(10)
    subTitleLabel?.textAlignment = NSTextAlignment.Center

    twoLineTitleView.addSubview(titleLabel!)
    twoLineTitleView.addSubview(subTitleLabel!)
    self.navigationItem.titleView = twoLineTitleView
  }



  override func viewWillAppear(animated: Bool) {
    super.viewWillAppear(animated)

    self.webView.loadRequest(self.request)

  }


  func closeButtonTapped(sender: UIBarButtonItem) {
    self.presentingViewController?.dismissViewControllerAnimated(true, completion: nil)
  }


  override func observeValueForKeyPath(keyPath: String, ofObject object: AnyObject, change: [NSObject : AnyObject], context: UnsafeMutablePointer<Void>) {

    if let wk = object as? WKWebView {
      switch keyPath {
      case "loading":
        if let val: AnyObject = change[NSKeyValueChangeNewKey] {
          if let val = val as? Bool {
            if val {
              self.indicator.startAnimating()
            }
            else {
              self.indicator.stopAnimating()
            }
          }
        }
      case "title":
        self.titleLabel?.text = self.webView.title
      case "URL":
        self.subTitleLabel?.text = self.webView.URL?.URLString
      case "estimatedProgress":
        println("progress: \(Int32(self.webView.estimatedProgress*100))")

      default: break
      }
    }
  }


}
注意:我使用的是 iOS 8.4 SDK。
为什么移动 Safari 能够加载这个 URL,但 WKWebView 却不能呢?

你正在使用哪个SDK?iOS8还是iOS9? - itsji10dra
这部分URL加载正常:http://buchung.salonmeister.de,其余部分可能有一些Webview Kit无法识别的字符。尝试使用不同的选择。 - Teja Nandamuri
1
一旦我添加了webView.loadRequest(request)(请参见截图),你的webView对我有效,但请注意你的URL似乎指向一个不存在的页面。 - Eric Aya
在移动Safari中加载URL,您会看到页面正在加载。 - Michael
你可能需要在字符串中添加“www”,因为苹果对其格式非常挑剔。 - Cyber
请参考以下链接:https://stackoverflow.com/a/59391866/810466 - Tomer Even
6个回答

30

2
Josh,你能解释一下为什么AppStore会因为plist中的这些行而拒绝你的应用程序吗? - Werewolf
我找到了为什么有时会被苹果拒绝的原因。如果你访问作者发布的链接,你会发现一种更好的方法,可以指定你正在访问的网站的实际域名,以确保安全性。它还警告说允许任意加载是不推荐的。 - Joseph Astrahan

22

对我而言,问题是由WKWebView的服务器信任检查引起的。

为了解决这个问题,我需要处理挑战认证回调并返回一个服务器信任凭据。

Swift 4

func webView(_ webView: WKWebView, 
    didReceive challenge: URLAuthenticationChallenge, 
    completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) 
{
    if(challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust)
    {
        let cred = URLCredential(trust: challenge.protectionSpace.serverTrust!)
        completionHandler(.useCredential, cred)
    }
    else
    {
        completionHandler(.performDefaultHandling, nil)
    }
}

6
如果您在一个沙盒化的macOS应用程序中,您需要设置传出连接(客户端)功能,您不需要处理“允许任意加载”,这对于受信任的https请求不应该起作用。 Xcode Capabilities Screenshot showing the Outgoing Connections (Client) checkbox checked 然而,在iOS中,允许客户端连接是默认的,因此您可能需要实现WKNavigationDelegate方法来处理安全性。但请确保不要仅信任不受信任的证书。这个Swift Talk视频来自objc.io,是我所知道的最好的资源,如果您正在这个领域工作,绝对值得花20分钟时间观看: https://talk.objc.io/episodes/S01E57-certificate-pinning

4

我曾遇到一个类似的问题,那个网站也是受到高安全性TLS 1.2证书的保护。为了让WKWebView接受服务器证书,我在我的Web视图控制器委托中添加了以下代码:

-(void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler
{
    if ([[[challenge protectionSpace]authenticationMethod] isEqualToString: @"NSURLAuthenticationMethodServerTrust"]) {
        SecTrustRef serverTrust = challenge.protectionSpace.serverTrust;
        CFDataRef exceptions = SecTrustCopyExceptions(serverTrust);
        SecTrustSetExceptions(serverTrust, exceptions);
        CFRelease(exceptions);
        newCredential = [NSURLCredential credentialForTrust:serverTrust];
        completionHandler(NSURLSessionAuthChallengeUseCredential, newCredential);
    } else {
        completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, newCredential);
    }
}

1

不确定是否是同样的错误原因,但在iOS9下我遇到了相同的问题。

某些域名无法加载。

结果发现问题出在

- (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))completionHandler {

并提供返回

completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);

我应该返回的位置

completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil);

我之前使用了https://github.com/ShingoFukuyama/WKWebViewTips上的错误代码。


我没有明白您的意思。能否请您详细描述一下?我不使用“didReceiveAuthenticationChallenge”方法。 - Michael
我曾经遇到过类似的错误行为,似乎是webview没有加载https,结果发现问题出在didReceiveAuthenticationChallenge上。 - Peter Lapisu
请问您能否发布更多的代码?您的“didReceiveAuthenticationChallenge”方法是什么样子的? - Michael
如果这样做可以解决您的问题,那么请尝试只返回 completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil); - Peter Lapisu
这行代码是做什么的? - Michael

0
// Add plist file 
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
<key>NSExceptionDomains</key>
<dict>
    <key>google.com</key>
    <dict>
        <key>NSExceptionAllowsInsecureHTTPLoads</key>
        <true/>
        <key>NSIncludesSubdomains</key>
        <true/>
    </dict>
</dict>

如果WKWebView不支持,则在.m文件中声明以下代码:
@interface WebScannerViewController()
{

 WKWebView *webView;

}


@end



@implementation WebScannerViewController

 - (void)viewDidLoad   {

    [super viewDidLoad];
    webView.hidden=YES;

    webView.UIDelegate = self;
    webView.navigationDelegate = self;
    self.loadingSign.hidden = NO;


        webView.frame=CGRectMake(0, 94, Width, Height-128);
    }

感谢您展示了上面的plist更新,这是正确的方法,以便苹果不会因安全原因拒绝应用程序。 - Joseph Astrahan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接