diff --git a/AgoraUIKit_iOS.podspec b/AgoraUIKit_iOS.podspec index 63d5e09f..289dffe3 100644 --- a/AgoraUIKit_iOS.podspec +++ b/AgoraUIKit_iOS.podspec @@ -8,7 +8,7 @@ Pod::Spec.new do |s| s.name = 'AgoraUIKit_iOS' - s.version = '1.6.4' + s.version = '1.6.5' s.summary = 'Agora video session UIKit template.' s.description = <<-DESC diff --git a/Sources/Agora-UIKit/AgoraRtmController+Helpers.swift b/Sources/Agora-UIKit/AgoraRtmController+Helpers.swift new file mode 100644 index 00000000..415666a8 --- /dev/null +++ b/Sources/Agora-UIKit/AgoraRtmController+Helpers.swift @@ -0,0 +1,159 @@ +// +// AgoraRtmController+Helpers.swift +// +// +// Created by Max Cobb on 30/09/2021. +// + +import AgoraRtmKit + +// MARK: Helper Methods +extension AgoraRtmController { + /// Type of decoded message coming from other users + public enum DecodedRtmAction { + /// Mute is when a user is requesting another user to mute or unmute a device + case mute(_: MuteRequest) + /// DecodedRtmAction type containing data about a user (local or remote) + case userData(_: UserData) + /// Message that contains a small action request, such as a ping or requesting a user's data + case genericAction(_: RtmGenericRequest) + } + + /// Decode message to a compatible DecodedRtmMessage type. + /// - Parameters: + /// - data: Raw data input, should be utf8 encoded JSON string of MuteRequest or UserData. + /// - rtmId: Sender Real-time Messaging ID. + /// - Returns: DecodedRtmMessage enum of the appropriate type. + internal static func decodeRawRtmData(data: Data, from rtmId: String) -> DecodedRtmAction? { + let decoder = JSONDecoder() + if let userData = try? decoder.decode(UserData.self, from: data) { + return .userData(userData) + } else if let muteReq = try? decoder.decode(MuteRequest.self, from: data) { + return .mute(muteReq) + } else if let genericRequest = try? decoder.decode(RtmGenericRequest.self, from: data) { + return .genericAction(genericRequest) + } + return nil + } + + /// Share local UserData to all connected channels. + /// Call this method when personal details are updated. + open func broadcastPersonalData() { + for channel in self.channels { self.sendPersonalData(to: channel.value) } + } + + /// Share local UserData to a specific channel + /// - Parameter channel: Channel to share UserData with. + open func sendPersonalData(to channel: AgoraRtmChannel) { + self.sendRaw(message: self.personalData, channel: channel) { sendMsgState in + switch sendMsgState { + case .errorOk: + AgoraVideoViewer.agoraPrint( + .verbose, message: "Personal data sent to channel successfully" + ) + case .errorFailure, .errorTimeout, .tooOften, + .invalidMessage, .errorNotInitialized, .notLoggedIn: + AgoraVideoViewer.agoraPrint( + .error, message: "Could not send message to channel \(sendMsgState.rawValue)" + ) + @unknown default: + AgoraVideoViewer.agoraPrint(.error, message: "Could not send message to channel (unknown)") + } + } + } + + /// Share local UserData to a specific RTM member + /// - Parameter member: Member to share UserData with. + open func sendPersonalData(to member: String) { + self.sendRaw(message: self.personalData, member: member) { sendMsgState in + switch sendMsgState { + case .ok: + AgoraVideoViewer.agoraPrint( + .verbose, message: "Personal data sent to member successfully" + ) + case .failure, .timeout, .tooOften, .invalidMessage, .notInitialized, .notLoggedIn, + .peerUnreachable, .cachedByServer, .invalidUserId, .imcompatibleMessage: + AgoraVideoViewer.agoraPrint( + .error, message: "Could not send message to channel \(sendMsgState.rawValue)" + ) + @unknown default: + AgoraVideoViewer.agoraPrint(.error, message: "Could not send message to channel (unknown)") + } + } + } + + /// Send a raw codable message over RTM to the channel. + /// - Parameters: + /// - message: Codable message to send over RTM. + /// - channel: String channel name to send the message to. + /// - callback: Callback, to see if the message was sent successfully. + public func sendRaw( + message: Value, channel: String, + callback: @escaping (AgoraRtmSendChannelMessageErrorCode) -> Void + ) where Value: Codable { + if let channel = self.channels[channel], let data = try? JSONEncoder().encode(message) { + channel.send( + AgoraRtmRawMessage(rawData: data, description: "AgoraUIKit"), completion: callback + ) + } + } + + /// Create raw message from codable object + /// - Parameter codableObj: Codable object to be sent over the Real-time Messaging network. + /// - Returns: AgoraRtmRawMessage that is ready to be sent across the Agora Real-time Messaging network. + public static func createRawRtm(from codableObj: Value) -> AgoraRtmRawMessage? where Value: Codable { + if let data = try? JSONEncoder().encode(codableObj) { + return AgoraRtmRawMessage(rawData: data, description: "AgoraUIKit") + } + AgoraVideoViewer.agoraPrint(.error, message: "Message could not be encoded to JSON") + return nil + } + + /// Send a raw codable message over RTM to the channel + /// - Parameters: + /// - message: Codable message to send over RTM + /// - channel: AgoraRtmChannel to send the message over + /// - callback: Callback, to see if the message was sent successfully. + public func sendRaw( + message: Value, channel: AgoraRtmChannel, + callback: @escaping (AgoraRtmSendChannelMessageErrorCode) -> Void + ) where Value: Codable { + if let rawMsg = AgoraRtmController.createRawRtm(from: message) { + channel.send(rawMsg, completion: callback) + return + } + callback(.invalidMessage) + } + + /// Send a raw codable message over RTM to a member + /// - Parameters: + /// - message: Codable message to send over RTM + /// - channel: member, or RTM ID to send the message to + /// - callback: Callback, to see if the message was sent successfully. + public func sendRaw( + message: Value, member: String, + callback: @escaping (AgoraRtmSendPeerMessageErrorCode) -> Void + ) where Value: Codable { + guard let rawMsg = AgoraRtmController.createRawRtm(from: message) else { + callback(.imcompatibleMessage) + return + } + self.rtmKit.send(rawMsg, toPeer: member, completion: callback) + } + + /// Send a raw codable message over RTM to a member + /// - Parameters: + /// - message: Codable message to send over RTM + /// - channel: member, or RTC User ID to send the message to + /// - callback: Callback, to see if the message was sent successfully. + public func sendRaw( + message: Value, user: UInt, + callback: @escaping (AgoraRtmSendPeerMessageErrorCode) -> Void + ) where Value: Codable { + if let rtmId = self.rtcLookup[user] { + self.sendRaw(message: message, member: rtmId, callback: callback) + } else { + callback(.peerUnreachable) + } + } +} diff --git a/Sources/Agora-UIKit/AgoraRtmController.swift b/Sources/Agora-UIKit/AgoraRtmController.swift index c1bbe9fe..8bfc9591 100644 --- a/Sources/Agora-UIKit/AgoraRtmController.swift +++ b/Sources/Agora-UIKit/AgoraRtmController.swift @@ -66,7 +66,7 @@ open class AgoraRtmController: NSObject { /// Status of the RTM Engine public internal(set) var loginStatus: LoginStatus = .offline // var videoViewer: AgoraVideoViewer - var rtmKit: AgoraRtmKit + public internal(set) var rtmKit: AgoraRtmKit /// Lookup remote user RTM ID based on their RTC ID public internal(set) var rtcLookup: [UInt: String] = [:] /// Get remote user data from their RTM ID @@ -255,134 +255,3 @@ open class AgoraRtmController: NSObject { } } } - -// MARK: Helper Methods -extension AgoraRtmController { - /// Type of decoded message coming from other users - public enum DecodedRtmAction { - /// Mute is when a user is requesting another user to mute or unmute a device - case mute(_: MuteRequest) - /// DecodedRtmAction type containing data about a user (local or remote) - case userData(_: UserData) - /// Message that contains a small action request, such as a ping or requesting a user's data - case genericAction(_: RtmGenericRequest) - } - - /// Decode message to a compatible DecodedRtmMessage type. - /// - Parameters: - /// - data: Raw data input, should be utf8 encoded JSON string of MuteRequest or UserData. - /// - rtmId: Sender Real-time Messaging ID. - /// - Returns: DecodedRtmMessage enum of the appropriate type. - internal static func decodeRawRtmData(data: Data, from rtmId: String) -> DecodedRtmAction? { - let decoder = JSONDecoder() - if let userData = try? decoder.decode(UserData.self, from: data) { - return .userData(userData) - } else if let muteReq = try? decoder.decode(MuteRequest.self, from: data) { - return .mute(muteReq) - } else if let genericRequest = try? decoder.decode(RtmGenericRequest.self, from: data) { - return .genericAction(genericRequest) - } - return nil - } - - /// Share local UserData to all connected channels. - /// Call this method when personal details are updated. - open func broadcastPersonalData() { - for channel in self.channels { self.sendPersonalData(to: channel.value) } - } - - /// Share local UserData to a specific channel - /// - Parameter channel: Channel to share UserData with. - open func sendPersonalData(to channel: AgoraRtmChannel) { - self.sendRaw(message: self.personalData, channel: channel) { sendMsgState in - switch sendMsgState { - case .errorOk: - AgoraVideoViewer.agoraPrint( - .verbose, message: "Personal data sent to channel successfully" - ) - case .errorFailure, .errorTimeout, .tooOften, - .invalidMessage, .errorNotInitialized, .notLoggedIn: - AgoraVideoViewer.agoraPrint( - .error, message: "Could not send message to channel \(sendMsgState.rawValue)" - ) - @unknown default: - AgoraVideoViewer.agoraPrint(.error, message: "Could not send message to channel (unknown)") - } - } - } - - /// Share local UserData to a specific RTM member - /// - Parameter member: Member to share UserData with. - open func sendPersonalData(to member: String) { - self.sendRaw(message: self.personalData, member: member) { sendMsgState in - switch sendMsgState { - case .ok: - AgoraVideoViewer.agoraPrint( - .verbose, message: "Personal data sent to member successfully" - ) - case .failure, .timeout, .tooOften, .invalidMessage, .notInitialized, .notLoggedIn, - .peerUnreachable, .cachedByServer, .invalidUserId, .imcompatibleMessage: - AgoraVideoViewer.agoraPrint( - .error, message: "Could not send message to channel \(sendMsgState.rawValue)" - ) - @unknown default: - AgoraVideoViewer.agoraPrint(.error, message: "Could not send message to channel (unknown)") - } - } - } - - func sendRaw( - message: Value, channel: String, - callback: @escaping (AgoraRtmSendChannelMessageErrorCode) -> Void - ) where Value: Codable { - if let channel = self.channels[channel], let data = try? JSONEncoder().encode(message) { - channel.send( - AgoraRtmRawMessage(rawData: data, description: "AgoraUIKit"), completion: callback - ) - } - } - - /// Create raw message from codable object - /// - Parameter codableObj: Codable object to be sent over the Real-time Messaging network. - /// - Returns: AgoraRtmRawMessage that is ready to be sent across the Agora Real-time Messaging network. - internal static func createRawRtm(from codableObj: Value) -> AgoraRtmRawMessage? where Value: Codable { - if let data = try? JSONEncoder().encode(codableObj) { - return AgoraRtmRawMessage(rawData: data, description: "AgoraUIKit") - } - AgoraVideoViewer.agoraPrint(.error, message: "Message could not be encoded to JSON") - return nil - } - - func sendRaw( - message: Value, channel: AgoraRtmChannel, - callback: @escaping (AgoraRtmSendChannelMessageErrorCode) -> Void - ) where Value: Codable { - if let rawMsg = AgoraRtmController.createRawRtm(from: message) { - channel.send(rawMsg, completion: callback) - return - } - callback(.invalidMessage) - } - - func sendRaw( - message: Value, member: String, - callback: @escaping (AgoraRtmSendPeerMessageErrorCode) -> Void - ) where Value: Codable { - guard let rawMsg = AgoraRtmController.createRawRtm(from: message) else { - callback(.imcompatibleMessage) - return - } - self.rtmKit.send(rawMsg, toPeer: member, completion: callback) - } - - func sendRaw( - message: Value, user: UInt, - callback: @escaping (AgoraRtmSendPeerMessageErrorCode) -> Void - ) where Value: Codable { - if let rtmId = self.rtcLookup[user] { - self.sendRaw(message: message, member: rtmId, callback: callback) - } else { - callback(.peerUnreachable) - } - } -} diff --git a/Sources/Agora-UIKit/AgoraUIKit.swift b/Sources/Agora-UIKit/AgoraUIKit.swift index 3ebaf57b..2d651191 100644 --- a/Sources/Agora-UIKit/AgoraUIKit.swift +++ b/Sources/Agora-UIKit/AgoraUIKit.swift @@ -22,7 +22,7 @@ public struct AgoraUIKit: Codable { /// Framework type of UIKit. "native", "flutter", "reactnative" fileprivate(set) var framework: String /// Version of UIKit being used - static let version = "1.6.4" + static let version = "1.6.5" /// Framework type of UIKit. "native", "flutter", "reactnative" static let framework = "native" #if os(iOS)