starscream

Starscream 是一个符合 WebSocket (RFC 6455) 协议的 Swift 客户端库。

它的 Objective-C 版本在这里:Jetfire

特性

示例

首先需要导入 framework。请查看安装说明,了解如何将 framework 添加到你的项目中。

import Starscream

导入后,你可以打开到 WebSocket 服务器的连接。请注意,最好将 socket 设置为属性,这样它才不会在设置后立即被释放。

socket = WebSocket(url: URL(string: "ws://:8080/")!)
socket.delegate = self
socket.connect()

连接之后,我们需要实现一些 delegate 方法。

websocketDidConnect

当客户端连接到服务器时,会立即调用 websocketDidConnect。

func websocketDidConnect(socket: WebSocketClient) {
    print("websocket is connected")
}

websocketDidDisconnect

当客户端与服务器断开连接时,会立即调用 websocketDidDisconnect。

func websocketDidDisconnect(socket: WebSocketClient, error: Error?) {
	print("websocket is disconnected: \(error?.localizedDescription)")
}

websocketDidReceiveMessage

当客户端从连接接收到文本帧时,会调用 websocketDidReceiveMessage。

func websocketDidReceiveMessage(socket: WebSocketClient, text: String) {
	print("got some text: \(text)")
}

websocketDidReceiveData

当客户端从连接接收到二进制帧时,会调用 websocketDidReceiveData。

func websocketDidReceiveData(socket: WebSocketClient, data: Data) {
	print("got some data: \(data.count)")
}

可选: websocketDidReceivePong *(需要协议:WebSocketPongDelegate)*

当客户端从连接接收到 pong 响应时,会调用 websocketDidReceivePong。你需要实现 WebSocketPongDelegate 协议并设置一个额外的 delegate,例如:socket.pongDelegate = self

func websocketDidReceivePong(socket: WebSocketClient, data: Data?) {
	print("Got pong! Maybe some data: \(data?.count)")
}

或者你可以使用闭包。

socket = WebSocket(url: URL(string: "ws://:8080/")!)
//websocketDidConnect
socket.onConnect = {
    print("websocket is connected")
}
//websocketDidDisconnect
socket.onDisconnect = { (error: Error?) in
    print("websocket is disconnected: \(error?.localizedDescription)")
}
//websocketDidReceiveMessage
socket.onText = { (text: String) in
    print("got some text: \(text)")
}
//websocketDidReceiveData
socket.onData = { (data: Data) in
    print("got some data: \(data.count)")
}
//you could do onPong as well.
socket.connect()

还有一点:你可以通过通知监听 socket 的连接和断开连接。 Starscream 会发布 WebsocketDidConnectNotificationWebsocketDidDisconnectNotification。你可以通过访问通知 userInfo 中的 WebsocketDisconnectionErrorKeyName 找到导致断开连接的 Error

Delegate 方法提供了一种简单的方式来处理来自服务器的数据,但如何发送数据呢?

写入一个二进制帧

writeData 方法提供了一种简单的方式来向服务器发送 Data(二进制)数据。

socket.write(data: data) //write some Data over the socket!

写入一个字符串帧

writeString 方法与 writeData 相同,但发送的是文本/字符串。

socket.write(string: "Hi Server!") //example on how to write text over the socket!

写入一个 ping 帧

writePing 方法与 write 相同,但发送的是 ping 控制帧。

socket.write(ping: Data()) //example on how to write a ping control frame over the socket!

写入一个 pong 帧

writePong 方法与 writePing 相同,但发送的是 pong 控制帧。

socket.write(pong: Data()) //example on how to write a pong control frame over the socket!

Starscream 会自动响应收到的 ping 控制帧,所以你不需要手动发送 pong

但是,如果出于某种原因你需要控制这个过程,你可以通过禁用 respondToPingWithPong 来关闭自动 ping 响应。

socket.respondToPingWithPong = false //Do not automaticaly respond to incoming pings with pongs.

在大多数情况下,你不需要这样做。

断开连接

disconnect 方法会执行你期望的操作并关闭 socket。

socket.disconnect()

isConnected

返回 socket 是否已连接。

if socket.isConnected {
  // do cool stuff.
}

自定义 Headers

你还可以使用你自己的自定义 header 覆盖默认的 WebSocket header,如下所示

var request = URLRequest(url: URL(string: "ws://:8080/")!)
request.timeoutInterval = 5
request.setValue("someother protocols", forHTTPHeaderField: "Sec-WebSocket-Protocol")
request.setValue("14", forHTTPHeaderField: "Sec-WebSocket-Version")
request.setValue("Everything is Awesome!", forHTTPHeaderField: "My-Awesome-Header")
let socket = WebSocket(request: request)

自定义 HTTP 方法

你的服务器在连接到 WebSocket 时可能使用不同的 HTTP 方法

var request = URLRequest(url: URL(string: "ws://:8080/")!)
request.httpMethod = "POST"
request.timeoutInterval = 5
let socket = WebSocket(request: request)

协议

如果你需要指定协议,只需将其添加到 init 中

//chat and superchat are the example protocols here
socket = WebSocket(url: URL(string: "ws://:8080/")!, protocols: ["chat","superchat"])
socket.delegate = self
socket.connect()

自签名 SSL

socket = WebSocket(url: URL(string: "ws://:8080/")!, protocols: ["chat","superchat"])

//set this if you want to ignore SSL cert validation, so a self signed SSL certificate can be used.
socket.disableSSLCertValidation = true

SSL Pinning

Starscream 也支持 SSL Pinning。

socket = WebSocket(url: URL(string: "ws://:8080/")!, protocols: ["chat","superchat"])
let data = ... //load your certificate from disk
socket.security = SSLSecurity(certs: [SSLCert(data: data)], usePublicKeys: true)
//socket.security = SSLSecurity() //uses the .cer files in your app's bundle

你可以加载证书的 Data blob,或者如果你有想要使用的公钥,可以使用 SecKeyRefusePublicKeys 布尔值决定是使用证书进行验证还是使用公钥。如果选择了 usePublicKeys,则会自动从证书中提取公钥。

SSL Cipher Suites

要使用 SSL 加密连接,你需要告诉 Starscream 你的服务器支持的密码套件。

socket = WebSocket(url: URL(string: "wss://:8080/")!, protocols: ["chat","superchat"])

// Set enabled cipher suites to AES 256 and AES 128
socket.enabledSSLCipherSuites = [TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256] 

如果你不知道你的服务器支持哪些密码套件,你可以尝试使用 SSL Labs 对其进行测试并查看结果。

压缩扩展

Starscream 支持压缩扩展 (RFC 7692)。默认情况下启用压缩,但是只有在服务器也支持的情况下才会使用压缩。你可以通过 .enableCompression 属性启用或禁用压缩。

socket = WebSocket(url: URL(string: "ws://:8080/")!)
socket.enableCompression = false

如果你的应用程序传输的是已经压缩的、随机的或其他不可压缩的数据,则应禁用压缩。

自定义队列

可以在调用 delegate 方法时指定自定义队列。默认情况下使用 DispatchQueue.main,因此所有 delegate 方法调用都在主线程上运行。重要的是要注意,所有 WebSocket 处理都在后台线程上完成,只有在修改队列时才会更改 delegate 方法调用。实际处理始终在后台线程上,不会暂停你的应用程序。

socket = WebSocket(url: URL(string: "ws://:8080/")!, protocols: ["chat","superchat"])
//create a custom queue
socket.callbackQueue = DispatchQueue(label: "com.vluxe.starscream.myapp")

示例项目

查看 examples 目录中的 SimpleTest 项目,了解如何设置与 WebSocket 服务器的简单连接。

要求

Starscream 适用于 iOS 7/OSX 10.9 或更高版本。建议使用 iOS 8/10.10 或更高版本以获得 CocoaPods/framework 支持。 要在以 iOS 7 为目标的项目中使用 Starscream,你必须将所有 Swift 文件直接包含在你的项目中。

安装

CocoaPods

查看 cocoapods.org 上的 Get Started 选项卡。

要在你的项目中使用 Starscream,请将以下 'Podfile' 添加到你的项目

source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '9.0'
use_frameworks!

pod 'Starscream', '~> 3.0.2'

然后运行

pod install

Carthage

查看 Carthage 文档,了解如何添加安装。Starscream framework 已经设置了共享 scheme。

Carthage 安装

你可以使用 Homebrew 使用以下命令安装 Carthage

$ brew update
$ brew install carthage

要使用 Carthage 将 Starscream 集成到你的 Xcode 项目中,请在你的 Cartfile 中指定它

github "daltoniam/Starscream" >= 3.0.2

Rogue

首先查看 安装文档,了解如何安装 Rogue。

要在你创建 rogue 文件的目录中安装 Starscream,请运行以下命令。

rogue add https://github.com/daltoniam/Starscream

接下来,打开 libs 文件夹并将 Starscream.xcodeproj 添加到你的 Xcode 项目。完成后,在你的 "Build Phases" 中,将 Starscream.framework 添加到你的 "Link Binary with Libraries" 阶段。请确保将 libs 文件夹添加到你的 .gitignore 文件中。

Swift Package Manager

Swift Package Manager 是一种用于自动化 Swift 代码分发的工具,它已集成到 swift 编译器中。

设置好 Swift 包后,将 Starscream 添加为依赖项就像将其添加到 Package.swiftdependencies 值一样简单。

dependencies: [
    .Package(url: "https://github.com/daltoniam/Starscream.git", majorVersion: 3)
]

其他

只需获取 framework(通过 git submodule 或其他包管理器)。

Starscream.xcodeproj 添加到你的 Xcode 项目。完成后,在你的 "Build Phases" 中,将 Starscream.framework 添加到你的 "Link Binary with Libraries" 阶段。

添加 Copy Frameworks 阶段

如果你在 OSX 应用程序中或在物理 iOS 设备上运行此程序,你需要确保将 Starscream.framework 添加到你的应用程序包中。 为此,在 Xcode 中,通过单击蓝色项目图标并选择侧边栏中“Targets”标题下的应用程序目标来导航到目标配置窗口。 在该窗口顶部的选项卡栏中,打开“Build Phases”面板。 展开“Link Binary with Libraries”组,然后添加 Starscream.framework。 单击面板左上角的 + 按钮,然后选择“New Copy Files Phase”。 将此新阶段重命名为“Copy Frameworks”,将“Destination”设置为“Frameworks”,并分别添加 Starscream.framework

WebSocketAdvancedDelegate

高级 delegate 的作用与更简单的 delegate 相同,但提供了有关连接和传入帧的一些其他信息。

socket.advancedDelegate = self

在大多数情况下,你不需要额外的信息,应该使用普通的 delegate。

websocketDidReceiveMessage

func websocketDidReceiveMessage(socket: WebSocketClient, text: String, response: WebSocket.WSResponse) {
	print("got some text: \(text)")
	print("First frame for this message arrived on \(response.firstFrame)")
}

websocketDidReceiveData

func websocketDidReceiveData(socket: WebSocketClient, data: Date, response: WebSocket.WSResponse) {
	print("got some data it long: \(data.count)")
	print("A total of \(response.frameCount) frames were used to send this data")
}

websocketHttpUpgrade

这些方法在发送 HTTP 升级请求和返回响应时调用。

func  websocketHttpUpgrade(socket: WebSocketClient, request: CFHTTPMessage) {
	print("the http request was sent we can check the raw http if we need to")
}
func  websocketHttpUpgrade(socket: WebSocketClient, response: CFHTTPMessage) {
	print("the http response has returned.")
}

已知问题

TODOs

许可证

Starscream 在 Apache v2 许可证下获得许可。

联系方式

Dalton Cherry

Austin Cherry