Skip to content

制作流程

zhtut edited this page Dec 17, 2021 · 2 revisions

制作SSURLSession

1.复制FoudationNetwork下URLSession文件夹,以及URLCache,URLProtocol,DataURLProtocol文件到目录

2.全局SwiftFoundation替换成Foundation

3.URLSessionTaskMetrics 27行taskInterval没用上,注释掉

4.URLSessionConfiguration ephemeral方法用不上,注释掉

5.HTTPURLProtocol 400行 if request.isTimeoutIntervalSet 这个属性是内部方法,无法得知,使用timeoutInterval>0替换使用,判断一下是否为inf和nan

let requestTimeOut = request.timeoutInterval
if !requestTimeOut.isInfinite && !requestTimeOut.isNaN && request.timeoutInterval > 0 {
    timeoutInterval = Int(request.timeoutInterval) * 1000
}

6.URLCache 447行使用了ios11的api,需要把旧的api加上

if #available(iOS 11.0, *) {
    return try NSKeyedUnarchiver.unarchivedObject(ofClasses: [StoredCachedURLResponse.self], from: data) as? StoredCachedURLResponse
} else {
    return NSKeyedUnarchiver.unarchiveObject(with: data) as? StoredCachedURLResponse
}

500行也是一样 var serialized: Data? if #available(iOS 11.0, *) { serialized = (onDisk && diskCapacity > 0) ? try? NSKeyedArchiver.archivedData(withRootObject: object, requiringSecureCoding: true) : nil } else { // Fallback on earlier versions serialized = (onDisk && diskCapacity > 0) ? NSKeyedArchiver.archivedData(withRootObject: object) : nil }

7.URLProtocol使用了URLRequest的私有变量,转向Foundation.URLProtocol的方法,这里网络库没有用,这几个方法,注释也可以

return Foundation.URLProtocol.property(forKey: key, in: request)
Foundation.URLProtocol.setProperty(value, forKey: key, in: request)
Foundation.URLProtocol.removeProperty(forKey: key, in: request)

8.NativeProtocol缺少方法_InputStreamSPIForFoundationNetworkingUseOnly,在NativeProtocol底部加上

// add-
public struct _InputStreamSPIForFoundationNetworkingUseOnly {
var inputStream: InputStream

public init(_ inputStream: InputStream) {
    self.inputStream = inputStream
}

public func seek(to position: UInt64) throws {
    try inputStream.seek(to: position)
}
}

extension InputStream {
enum _Error: Error {
    case cantSeekInputStream
}

func seek(to position: UInt64) throws {
    guard position > 0 else {
        return
    }
    
    guard position < Int.max else { throw _Error.cantSeekInputStream }
    
    let bufferSize = 1024
    var remainingBytes = Int(position)
    
    let buffer = UnsafeMutableRawBufferPointer.allocate(byteCount: bufferSize, alignment: MemoryLayout<UInt8>.alignment)
    
    guard let pointer = buffer.baseAddress?.assumingMemoryBound(to: UInt8.self) else {
        buffer.deallocate()
        throw _Error.cantSeekInputStream
    }
    
    if self.streamStatus == .notOpen {
        self.open()
    }
    
    while remainingBytes > 0 && self.hasBytesAvailable {
        let read = self.read(pointer, maxLength: min(bufferSize, remainingBytes))
        if read == -1 {
            throw _Error.cantSeekInputStream
        }
        remainingBytes -= read
    }
    
    buffer.deallocate()
    if remainingBytes != 0 {
        throw _Error.cantSeekInputStream
    }
}
}

9.HTTPMessage使用了ios13的获取HeaderValue的方法,把旧的方法加上

if #available(iOS 13.0, *) {
    guard let authenticateValue = response.value(forHTTPHeaderField: "WWW-Authenticate") else {
        return []
    }
    return challenges(from: authenticateValue)
} else {
    // Fallback on earlier versions
        let allHeaders = response.allHeaderFields
        guard let authenticateValue = allHeaders["WWW-Authenticate"] as? String else {
            return []
        }
        return challenges(from: authenticateValue)
    }

10.NetworkingSpecific有找不到的结构体_NSNonfileURLContentLoading,这个在swiftRuntime中,把结构体定义拷过来即可,注册这个loader也可以,这里没有调用

public protocol _NSNonfileURLContentLoading: AnyObject {
    init()
    func contentsOf(url: URL) throws -> (result: NSData, textEncodingNameIfAvailable: String?)
}

11.URLSessionTask 788 行使用了URLProtectionSpace.create(with: response)私有方法,在底部加上这些缺少的

extension URLProtectionSpace {
//an internal helper to create a URLProtectionSpace from a HTTPURLResponse
static func create(with response: HTTPURLResponse) -> URLProtectionSpace? {
    // Using first challenge, as we don't support multiple challenges yet
    guard let challenge = _HTTPURLProtocol._HTTPMessage._Challenge.challenges(from: response).first else {
        return nil
    }
    guard let url = response.url, let host = url.host, let proto = url.scheme, proto == "http" || proto == "https" else {
        return nil
    }
    let port = url.port ?? (proto == "http" ? 80 : 443)
    return URLProtectionSpace(host: host,
                              port: port,
                              protocol: proto,
                              realm: challenge.parameter(withName: "realm")?.value,
                              authenticationMethod: challenge.authenticationMethod)
}
}

extension _HTTPURLProtocol._HTTPMessage._Challenge {
var authenticationMethod: String? {
    if authScheme.caseInsensitiveCompare(_HTTPURLProtocol._HTTPMessage._Challenge.AuthSchemeBasic) == .orderedSame {
        return NSURLAuthenticationMethodHTTPBasic
    } else if authScheme.caseInsensitiveCompare(_HTTPURLProtocol._HTTPMessage._Challenge.AuthSchemeDigest) == .orderedSame {
        return NSURLAuthenticationMethodHTTPDigest
    } else {
        return nil
    }
}
}

class URLSessionAuthenticationChallengeSender : NSObject, URLAuthenticationChallengeSender {
func cancel(_ challenge: URLAuthenticationChallenge) {
    fatalError("swift-corelibs-foundation only supports URLSession; for challenges coming from URLSession, please implement the appropriate URLSessionTaskDelegate methods rather than using the sender argument.")
}

func continueWithoutCredential(for challenge: URLAuthenticationChallenge) {
    fatalError("swift-corelibs-foundation only supports URLSession; for challenges coming from URLSession, please implement the appropriate URLSessionTaskDelegate methods rather than using the sender argument.")
}

func use(_ credential: URLCredential, for challenge: URLAuthenticationChallenge) {
    fatalError("swift-corelibs-foundation only supports URLSession; for challenges coming from URLSession, please implement the appropriate URLSessionTaskDelegate methods rather than using the sender argument.")
}

func performDefaultHandling(for challenge: URLAuthenticationChallenge) {
    fatalError("swift-corelibs-foundation only supports URLSession; for challenges coming from URLSession, please implement the appropriate URLSessionTaskDelegate methods rather than using the sender argument.")
}

func rejectProtectionSpaceAndContinue(with challenge: URLAuthenticationChallenge) {
    fatalError("swift-corelibs-foundation only supports URLSession; for challenges coming from URLSession, please implement the appropriate URLSessionTaskDelegate methods rather than using the sender argument.")
}
}

extension URLCredentialStorage {
@objc
public func getCredentials(for protectionSpace: URLProtectionSpace, task: URLSessionTask, completionHandler: ([String : URLCredential]?) -> Void) {
    completionHandler(credentials(for: protectionSpace))
}

@objc
public func set(_ credential: URLCredential, for protectionSpace: URLProtectionSpace, task: URLSessionTask) {
    set(credential, for: protectionSpace)
}

@objc
public func remove(_ credential: URLCredential, for protectionSpace: URLProtectionSpace, options: [String : AnyObject]? = [:], task: URLSessionTask) {
    remove(credential, for: protectionSpace, options: options)
}

@objc
public func getDefaultCredential(for space: URLProtectionSpace, task: URLSessionTask, completionHandler: (URLCredential?) -> Void) {
    completionHandler(defaultCredential(for: space))
}

@objc
public func setDefaultCredential(_ credential: URLCredential, for protectionSpace: URLProtectionSpace, task: URLSessionTask) {
    setDefaultCredential(credential, for: protectionSpace)
}
}

到这步swift就能编译通过了

剩余的就是在适当的地方加上@objc,使库支持oc访问