twilio-rn/modules/my-native-module/ios/MyNativeModule.swift

330 lines
10 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import ExpoModulesCore
// Twilio Conversations SDK
import TwilioConversationsClient
public class MyNativeModule: Module, TwilioConversationsClientDelegate {
// Twilio
private var conversationsClient: TwilioConversationsClient?
// Promise
private var initCompletion: PromiseCompletionBlock?
private var createConversationCompletion: PromiseCompletionBlock?
// Each module class must implement the definition function.
public func definition() -> ModuleDefinition {
//
Name("MyNativeModule")
//
Constant("PI") {
Double.pi
}
// JavaScript
Events(
"onChange",
"onClientSynchronized",
"onClientError",
"onConnectionStateChanged",
"onConversationAdded",
"onConversationUpdated",
"onConversationDeleted",
"onMessageAdded",
"onMessageUpdated",
"onMessageDeleted",
"onParticipantAdded",
"onParticipantUpdated",
"onParticipantDeleted"
)
//
Function("hello") {
return "Hello world! 👋"
}
//
AsyncFunction("setValueAsync") { (value: String) in
// Send an event to JavaScript.
self.sendEvent("onChange", [
"value": value
])
}
// Twilio Conversations
AsyncFunction("initialize") { (token: String, completion: @escaping PromiseCompletionBlock) -> Void in
if token.isEmpty {
completion(["error": "Token cannot be empty"])
return
}
//
self.initCompletion = completion
// Twilio
TwilioConversationsClient.conversationsClient(withToken: token, properties: nil, delegate: self) {
result, error in
if let error = error {
self.sendEvent("onClientError", ["error": error.localizedDescription])
self.initCompletion?(nil, error)
return
}
if let client = result {
self.conversationsClient = client
//
self.initCompletion?("Twilio Conversations 客户端已成功初始化", nil)
} else {
self.initCompletion?(["error": "Failed to initialize client"])
}
}
}
//
AsyncFunction("getConversations") { (completion: @escaping PromiseCompletionBlock) -> Void in
guard let client = self.conversationsClient else {
completion(["error": "客户端未初始化"])
return
}
//
client.conversations() { result, error in
if let error = error {
completion(nil, error)
return
}
if let conversations = result {
// JS
let jsConversations = conversations.map { conversation -> [String: Any] in
var conversationDict: [String: Any] = [
"sid": conversation.sid,
"friendlyName": conversation.friendlyName ?? "未命名对话"
]
//
if let dateCreated = conversation.dateCreated {
conversationDict["dateCreated"] = Int(dateCreated.timeIntervalSince1970 * 1000)
}
if let dateUpdated = conversation.dateUpdated {
conversationDict["dateUpdated"] = Int(dateUpdated.timeIntervalSince1970 * 1000)
}
return conversationDict
}
completion(jsConversations, nil)
} else {
completion([], nil)
}
}
}
//
AsyncFunction("createConversation") { (friendlyName: String, completion: @escaping PromiseCompletionBlock) -> Void in
guard let client = self.conversationsClient else {
completion(["error": "客户端未初始化"])
return
}
if friendlyName.isEmpty {
completion(["error": "对话名称不能为空"])
return
}
//
self.createConversationCompletion = completion
//
client.createConversation(options: ["friendlyName": friendlyName]) { result, error in
if let error = error {
completion(nil, error)
return
}
if let conversation = result {
//
completion(["status": "creating", "friendlyName": conversation.friendlyName ?? friendlyName], nil)
//
self.sendEvent("onConversationAdded", [
"sid": conversation.sid,
"friendlyName": conversation.friendlyName ?? friendlyName
])
} else {
completion(["error": "创建对话失败"])
}
}
}
//
AsyncFunction("getClientStatus") { (completion: @escaping PromiseCompletionBlock) -> Void in
guard let client = self.conversationsClient else {
completion("not_initialized")
return
}
//
switch client.connectionState {
case .connecting:
completion("connecting")
case .connected:
completion("connected")
case .disconnected:
completion("disconnected")
case .denied:
completion("denied")
case .error:
completion("error")
@unknown default:
completion("unknown")
}
}
//
AsyncFunction("disconnect") { (completion: @escaping PromiseCompletionBlock) -> Void in
guard let client = self.conversationsClient else {
completion("already_disconnected")
return
}
//
client.shutdown()
self.conversationsClient = nil
completion("disconnected")
}
//
View(MyNativeModuleView.self) {
// urlsetter
Prop("url") { (view: MyNativeModuleView, url: URL) in
if view.webView.url != url {
view.webView.load(URLRequest(url: url))
}
}
Events("onLoad")
}
}
// MARK: - TwilioConversationsClientDelegate
//
public func conversationsClientDidSynchronize(_ client: TwilioConversationsClient) {
sendEvent("onClientSynchronized", ["status": "synchronized"])
}
//
public func conversationsClient(_ client: TwilioConversationsClient, connectionStateChanged state: TwilioConversationsClient.ConnectionState) {
var stateString: String
switch state {
case .connecting:
stateString = "connecting"
case .connected:
stateString = "connected"
case .disconnected:
stateString = "disconnected"
case .denied:
stateString = "denied"
case .error:
stateString = "error"
@unknown default:
stateString = "unknown"
}
sendEvent("onConnectionStateChanged", ["state": stateString])
}
//
public func conversationsClient(_ client: TwilioConversationsClient, conversationAdded conversation: TCHConversation) {
sendEvent("onConversationAdded", [
"sid": conversation.sid,
"friendlyName": conversation.friendlyName ?? "未命名对话"
])
}
//
public func conversationsClient(_ client: TwilioConversationsClient, conversationUpdated conversation: TCHConversation) {
sendEvent("onConversationUpdated", [
"sid": conversation.sid,
"friendlyName": conversation.friendlyName ?? "未命名对话"
])
}
//
public func conversationsClient(_ client: TwilioConversationsClient, conversationDeleted conversation: TCHConversation) {
sendEvent("onConversationDeleted", ["sid": conversation.sid])
}
//
public func conversationsClient(_ client: TwilioConversationsClient, conversation: TCHConversation, messageAdded message: TCHMessage) {
sendEvent("onMessageAdded", [
"conversationSid": conversation.sid,
"messageSid": message.sid
])
}
//
public func conversationsClient(_ client: TwilioConversationsClient, conversation: TCHConversation, messageUpdated message: TCHMessage) {
sendEvent("onMessageUpdated", [
"conversationSid": conversation.sid,
"messageSid": message.sid
])
}
//
public func conversationsClient(_ client: TwilioConversationsClient, conversation: TCHConversation, messageDeleted message: TCHMessage) {
sendEvent("onMessageDeleted", [
"conversationSid": conversation.sid,
"messageSid": message.sid
])
}
//
public func conversationsClient(_ client: TwilioConversationsClient, conversation: TCHConversation, participantAdded participant: TCHParticipant) {
sendEvent("onParticipantAdded", [
"conversationSid": conversation.sid,
"participantIdentity": participant.identity ?? ""
])
}
//
public func conversationsClient(_ client: TwilioConversationsClient, conversation: TCHConversation, participantUpdated participant: TCHParticipant) {
sendEvent("onParticipantUpdated", [
"conversationSid": conversation.sid,
"participantIdentity": participant.identity ?? ""
])
}
//
public func conversationsClient(_ client: TwilioConversationsClient, conversation: TCHConversation, participantDeleted participant: TCHParticipant) {
sendEvent("onParticipantDeleted", [
"conversationSid": conversation.sid,
"participantIdentity": participant.identity ?? ""
])
}
//
public func conversationsClient(_ client: TwilioConversationsClient, synchronizationStatusChanged status: TCHClientSynchronizationStatus) {
//
var statusString: String
switch status {
case .started:
statusString = "started"
case .completed:
statusString = "completed"
case .failed:
statusString = "failed"
@unknown default:
statusString = "unknown"
}
sendEvent("onClientSynchronized", ["status": statusString])
}
}