Пользовательская схема URI "Неподдерживаемый URL" - PullRequest
0 голосов
/ 18 сентября 2018

Ниже приведен мой info.plist, и я зарегистрировал URI пользовательской схемы запроса приложения.

Когда я выполняю обратный вызов OAuth с redirect_uri=myapplication://oauthcallback на симуляторе или устройстве, я получаю:

Task <CC539C38-4191-48BB-B126-E41BCE28151B>.<6> load failed with 
error Error Domain=NSURLErrorDomain Code=-1002 "unsupported URL" 
UserInfo={NSLocalizedDescription=unsupported URL, 
NSErrorFailingURLStringKey=myapplication://oauthcallback?code=rGudk3a7c7&state=state-F7AF0906-984F-47C3-841B-9A55246C3784, 
NSErrorFailingURLKey=myapplication://oauthcallback?code=rGudk3a7c7&state=state-F7AF0906-984F-47C3-841B-9A55246C3784, 
_NSURLErrorRelatedURLSessionTaskErrorKey=(
    "LocalDataTask <CC539C38-4191-48BB-B126-E41BCE28151B>.<6>"
), _NSURLErrorFailingURLSessionTaskErrorKey=LocalDataTask <CC539C38-4191-48BB-B126-E41BCE28151B>.<6>, 
NSUnderlyingError=0x60000253e8e0 {Error Domain=kCFErrorDomainCFNetwork Code=-1002 "(null)"}} [-1002]

Есть идеи?Info.plist ниже:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>CFBundleDevelopmentRegion</key>
    <string>$(DEVELOPMENT_LANGUAGE)</string>
    <key>CFBundleExecutable</key>
    <string>$(EXECUTABLE_NAME)</string>
    <key>CFBundleIdentifier</key>
    <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
    <key>CFBundleInfoDictionaryVersion</key>
    <string>6.0</string>
    <key>CFBundleName</key>
    <string>$(PRODUCT_NAME)</string>
    <key>CFBundlePackageType</key>
    <string>APPL</string>
    <key>CFBundleShortVersionString</key>
    <string>1.0.0</string>
    <key>CFBundleURLTypes</key>
    <array>
        <dict>
            <key>CFBundleURLName</key>
            <string></string>
            <key>CFBundleURLSchemes</key>
            <array>
                <string>myapplication</string>
            </array>
        </dict>
    </array>
    <key>CFBundleVersion</key>
    <string>1</string>
    <key>LSApplicationQueriesSchemes</key>
    <array>
        <string>tel</string>
        <string>myapplication</string>
    </array>
    <key>LSRequiresIPhoneOS</key>
    <true/>
    <key>UILaunchStoryboardName</key>
    <string>LaunchScreen</string>
    <key>UIRequiredDeviceCapabilities</key>
    <array>
        <string>armv7</string>
    </array>
    <key>UISupportedInterfaceOrientations</key>
    <array>
        <string>UIInterfaceOrientationPortrait</string>
    </array>
</dict>
</plist>

1 Ответ

0 голосов
/ 02 октября 2018

Я понял это.Оказывается, что при выполнении OAuth2 на iOS RedirectURI не работает!Он всегда возвращает неподдерживаемый URL-адрес. Итак, вам нужно создать собственный URL-протокол и обработать там свой redirectURI.

//
//  URLHandler.swift
//  XIO
//
//  Created by Brandon Anthony on 2018-10-01.
//  Copyright © 2018 SO. All rights reserved.
//

import Foundation

class URLHandler: URLProtocol {

  private static let requestIdentifier = "com.xio.uri.handled"

  override class func canInit(with request: URLRequest) -> Bool {
    guard request.url?.scheme == "myscheme" else {
      return false
    }

    guard let handled = URLProtocol.property(forKey: URLHandler.requestIdentifier, in: request) as? Bool else {
      return true
    }

    return !handled
  }

  override func startLoading() {
    guard let request = (self.request as NSURLRequest).mutableCopy() as? NSMutableURLRequest else {
      return
    }

    URLProtocol.setProperty(true, forKey: URLHandler.requestIdentifier, in: request)

    DispatchQueue.global(qos: .background).async {
      guard let url = request.url, let headers = request.allHTTPHeaderFields else {
        self.client?.urlProtocol(self, didFailWithError: RuntimeError("URLHandler - Invalid URL."))
        return
      }

      guard let response = HTTPURLResponse(url: url, statusCode: 200, httpVersion: "HTTP/1.1", headerFields: headers) else {
        self.client?.urlProtocol(self, didFailWithError: RuntimeError("URLHandler - Invalid Response."))
        return
      }


      let json: [String: Any] = ["key": "value"]

      do {
        let data = try JSONSerialization.data(withJSONObject: json, options: .prettyPrinted)
        self.client?.urlProtocol(self, didReceive: response, cacheStoragePolicy: .notAllowed)
        self.client?.urlProtocol(self, didLoad: data as Data)
        self.client?.urlProtocolDidFinishLoading(self)
      } catch {
        self.client?.urlProtocol(self, didFailWithError: error)
      }
    }
  }

  override func stopLoading() {

  }

  override class func canonicalRequest(for request: URLRequest) -> URLRequest {
    return request
  }

  override class func requestIsCacheEquivalent(_ a: URLRequest, to b: URLRequest) -> Bool {
    return super.requestIsCacheEquivalent(a, to: b)
  }
}

В качестве альтернативы вы можете подождать, пока вызов не завершится, и затем проанализировать ответ.из объекта NSError. Другое решение состоит в том, чтобы запустить запрос и затем обработать ответ самостоятельно:

//
//  URLHandler.swift
//  XIO
//
//  Created by Brandon Anthony on 2018-10-01.
//  Copyright © 2018 SO. All rights reserved.
//

import Foundation

class URLHandler: URLProtocol, URLSessionDataDelegate {

  private var session: URLSession?
  private var dataTask: URLSessionDataTask?
  private static let requestIdentifier = "com.xio.uri.handled"

  override class func canInit(with request: URLRequest) -> Bool {
    guard request.url?.scheme == "myscheme" else {
      return false
    }

    guard let handled = URLProtocol.property(forKey: URLHandler.requestIdentifier, in: request) as? Bool else {
      return true
    }

    return !handled
  }

  override func startLoading() {
    guard let request = (self.request as NSURLRequest).mutableCopy() as? NSMutableURLRequest else {
      return
    }

    URLProtocol.setProperty(true, forKey: URLHandler.requestIdentifier, in: request)


    var headers = request.allHTTPHeaderFields
    headers?["Accept"] = "application/json"
    headers?["Content-Type"] = "application/json"
    request.allHTTPHeaderFields = headers

    let configuration = URLSessionConfiguration.default
    self.session = URLSession(configuration: configuration, delegate: self, delegateQueue: nil)
    self.dataTask = self.session?.dataTask(with: request as URLRequest)
    self.dataTask?.resume()
  }

  override func stopLoading() {
    self.dataTask?.cancel()
    self.dataTask = nil

    self.session?.invalidateAndCancel()
    self.session = nil
  }

  override class func canonicalRequest(for request: URLRequest) -> URLRequest {
    return request
  }

  override class func requestIsCacheEquivalent(_ a: URLRequest, to b: URLRequest) -> Bool {
    return super.requestIsCacheEquivalent(a, to: b)
  }

  // MARK: NSURLSessionTaskDelegate

  func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
    if let error = error as NSError? {
      if error.code == NSURLErrorUnsupportedURL {

        guard let request = task.currentRequest else {
          self.client?.urlProtocol(self, didFailWithError: error)
          return
        }

        guard let url = request.url, let headers = request.allHTTPHeaderFields else {
          self.client?.urlProtocol(self, didFailWithError: error)
          return
        }

        guard let response = HTTPURLResponse(url: url, statusCode: 200, httpVersion: "HTTP/1.1", headerFields: headers) else {
          self.client?.urlProtocol(self, didFailWithError: error)
          return
        }

        OktaTokenManager(Okta.shared).parseCode(url: url) { state, code in
          guard let state = state, let code = code else {
            self.client?.urlProtocol(self, didFailWithError: error)
            return
          }

          let json: [String: Any] = ["key": "value"]
          ]

          do {
            let data = try JSONSerialization.data(withJSONObject: json, options: .prettyPrinted)
            self.client?.urlProtocol(self, didReceive: response, cacheStoragePolicy: .notAllowed)
            self.client?.urlProtocol(self, didLoad: data as Data)
            self.client?.urlProtocolDidFinishLoading(self)
          } catch let err {
            print(err)
            self.client?.urlProtocol(self, didFailWithError: error)
          }
        }
        return
      }
    }

    if let response = task.response {
      client?.urlProtocol(self, didReceive: response, cacheStoragePolicy: .notAllowed)
    }

    if let error = error { //&& error.code != NSURLErrorCancelled {
      self.client?.urlProtocol(self, didFailWithError: error)
    } else {
      self.client?.urlProtocolDidFinishLoading(self) //cacheResponse
    }
  }
}

Наконец, вы можете просто не делать ничего из вышеперечисленного, и когда ваш запрос не выполняется,Для получения реального ответа проанализируйте ошибку (аналогичную приведенной выше). Однако я предпочитаю такой подход. Особенно первый подход вместо запуска запроса.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...