330 lines
10 KiB
Swift
330 lines
10 KiB
Swift
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) {
|
||
// 定义url属性的setter
|
||
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])
|
||
}
|
||
}
|