WKWebView не загружает URL-адрес https?

У меня есть 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
      }
    }
  }


}

Примечание. Я использую SDK iOS 8.4

Почему мобильный Safari загружает этот URL-адрес, но WKWebView не работает?

Ответы

Ответ 1

Добавьте это в свой plist

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsArbitraryLoads</key>
    <true/>
</dict>

Здесь объяснение этого изменения в 9.0 http://ste.vn/2015/06/10/configuring-app-transport-security-ios-9-osx-10-11/

Также, если вы хотите установить его более безопасным, это даст вам более сложный способ сделать это.

Ответ 2

Для меня проблема была вызвана проверкой доверия сервера из 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)
    }
}

Ответ 3

У меня была аналогичная проблема с сайтом, который также был защищен сертификатом TLS 1.2 высокой безопасности. Чтобы заставить WKWebView принять сертификат сервера, я добавил этот код к моему делегату контроллера веб-представления:

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

Ответ 4

Не уверен, что с той же ошибкой, но проблема была одинаковой для меня в iOS9

некоторые домены не могут быть загружены

оказалось, что проблема была в

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

и обеспечение назад

completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);

где я должен был бы вернуть

completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil);

Я использовал WRONG-код из https://github.com/ShingoFukuyama/WKWebViewTips

Ответ 5

// 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;

}

@конец

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

}

Ответ 6

Если вы находитесь в изолированном MacOS-приложении, вам нужно настроить возможность исходящих подключений (клиента), вам не нужно связываться с Allow Abitrary Loads, которые не должны вступать в игру для запросов 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