问题描述
我有一个关于如何在iOS 14上设置UDP侦听器的问题。我有一个曾经使用过的UDP侦听器,但是在更新到iOS 14之后,它偶尔会起作用/根本无法工作。
它驻留在NSObject中,并在端口15000(无特定IP地址)上侦听本地网络上的UDP广播。它使用CocoaAsyncSocket库。当我致电setUpSocket()
时,不会触发本地网络权限,但是该应用程序可以偶尔接收UDP数据包。
var socket: GCDAsyncUdpSocket?
var broadcastPort: UInt16 = 15000
var broadcastAddress: String = ""
var connectAddress = ""
var connectPort = 0
func setUpSocket() {
findUDP()
let socket = GCDAsyncUdpSocket(delegate: self,delegateQueue: DispatchQueue.main)
socket.setIPv4Enabled(true)
socket.setIPv6Enabled(false)
do {
try socket.bind(toPort: broadcastPort) /*15000*/
try socket.enableBroadcast(false)
try socket.beginReceiving()
} catch let error as NSError {
print("Issue with setting up listener \(error)")
}
}
/*Called when UDP packets are received.*/
func udpSocket(_ sock: GCDAsyncUdpSocket,didReceive data: Data,fromAddress: Data,withFilterContext filterContext: Any?) {
do {
let jsonDictionary = try JSONSerialization.jsonObject(with: data,options: []) as! [String : Any]
if (connected == false) {
if (jsonDictionary["Addresses"] != nil) {
if (jsonDictionary["Addresses"] is NSArray) {
let addresses = jsonDictionary["Addresses"] as! NSArray
for i in addresses {
let ipAddress:String = i as! String
if (ipAddress.range(of: "^([0-9]{1,3}\\.){3}[0-9]{1,3}(\\/([0-9]|[1-2][0-9]|3[0-2]))?$",options: .regularExpression) != nil) {
connectAddress = ipAddress
}
}
connectPort = jsonDictionary["Port"] as! Int
}
/*Sets up a TCP connection on the IP and Port provided in the UDP broadcast.*/
setupNetworkCommunication(ip: connectAddress,port: connectPort)
closeSocket()
}
}
} catch let error {
return print(error)
}
}
如何更新它以符合iOS 14?如果需要更新才能使用Bonjour服务,如何在不指定地址的情况下在端口上侦听(而不必查找特定的Bonjour服务广播,因为我要查找的广播不使用Bonjour)。 / p>
是否可以快速打开和关闭Bonjour NWBrowser来触发网络权限,然后按原样使用我的代码?这似乎可行,但充其量似乎很hacky。
谢谢。
解决方法
我能够在Apple开发者论坛上进行更多探索,并获得一些帮助,并在此处为有兴趣的人发布答案。
我最终使用NWListener侦听UDP数据包,然后在收到某些信息后立即建立NWConnection。我使用此NWConnection从UDP广播中读取数据。
摘自奎因《爱斯基摩人》:
侦听通过
NWListener
进行的UDP广播,然后使用它出售的NWConnection
对象(通过new connection handler)与广播的发送方进行单播通信,这是一个预期的用例。 / p>
我鼓励阅读此书的任何人也检出our discussion on the Apple Developer Forum。
这是我的实现方式
var udpListener: NWListener?
var udpConnection: NWConnection?
var backgroundQueueUdpListener = DispatchQueue.main
func findUDP() {
let params = NWParameters.udp
udpListener = try? NWListener(using: params,on: 15000)
udpListener?.service = NWListener.Service.init(type: "_appname._udp")
self.udpListener?.stateUpdateHandler = { update in
print("update")
print(update)
switch update {
case .failed:
print("failed")
default:
print("default update")
}
}
self.udpListener?.newConnectionHandler = { connection in
print("connection")
print(connection)
self.createConnection(connection: connection)
self.udpListener?.cancel()
}
udpListener?.start(queue: self.backgroundQueueUdpListener)
}
func createConnection(connection: NWConnection) {
self.udpConnection = connection
self.udpConnection?.stateUpdateHandler = { (newState) in
switch (newState) {
case .ready:
print("ready")
self.send()
self.receive()
case .setup:
print("setup")
case .cancelled:
print("cancelled")
case .preparing:
print("Preparing")
default:
print("waiting or failed")
}
}
self.udpConnection?.start(queue: .global())
}
func endConnection() {
self.udpConnection?.cancel()
}
,
要在我们的应用程序中将Info.plist
与UDP配合使用,我们必须执行以下步骤:
-
向Apple请求多播权利(请求者必须是团队的帐户持有人):
com.apple.developer.networking.multicast
-
在目标的
*.entitlements
中,为以下键设置一个字符串:隐私-本地网络使用说明
-
在获得Apple的权利许可后,在您应用的
com.apple.developer.networking.multicast
文件中为以下密钥添加一个true(1)布尔值(这是阻止我们接收UDP广播的最后一步)数据包):add_filter('woocommerce_add_to_cart_validation','shalior_flag_already_added_products_as_invalid',10,2); function shalior_flag_already_added_products_as_invalid ($result,$product_id){ if (false === $result){ return $result; } $url = wc_get_cart_url(); foreach ( WC()->cart->get_cart() as $cart_item ) { $cart_item_product_id = $cart_item['product_id']; if($product_id === $cart_item['product_id'] ) { $result = false; } } if (false === $result){ add_filter('woocommerce_cart_redirect_after_error',function (){ return wc_get_cart_url(); },999 ); } return $result; }