From be08fe209deb6d750504290ef28d1d34ab8df052 Mon Sep 17 00:00:00 2001 From: Andrey Blinov Date: Tue, 11 Feb 2020 17:06:11 +0700 Subject: [PATCH] update --- Example/OnlineChatSdk/DemoController.swift | 2 +- Example/OnlineChatSdk/ViewController.swift | 6 +- Example/Podfile | 3 +- Example/Podfile.lock | 4 +- Example/Pods/Manifest.lock | 4 +- .../OnlineChatSdk/Classes/ChatApi.swift | 55 ++++ .../Classes/ChatController.swift | 253 ++++++++++++++++++ .../OnlineChatSdk/Classes/Command.swift | 17 ++ Example/Pods/OnlineChatSdk/README.md | 141 ++++++++++ .../OnlineChatSdk/OnlineChatSdk-Info.plist | 40 +-- OnlineChatSdk.podspec | 2 +- 11 files changed, 498 insertions(+), 29 deletions(-) create mode 100644 Example/Pods/OnlineChatSdk/OnlineChatSdk/Classes/ChatApi.swift create mode 100644 Example/Pods/OnlineChatSdk/OnlineChatSdk/Classes/ChatController.swift create mode 100644 Example/Pods/OnlineChatSdk/OnlineChatSdk/Classes/Command.swift create mode 100644 Example/Pods/OnlineChatSdk/README.md diff --git a/Example/OnlineChatSdk/DemoController.swift b/Example/OnlineChatSdk/DemoController.swift index e476252..e5c35a3 100644 --- a/Example/OnlineChatSdk/DemoController.swift +++ b/Example/OnlineChatSdk/DemoController.swift @@ -18,7 +18,7 @@ class DemoController: ChatController { } override func onClientId(_ clientId: String) { - + } override func onSendRate(_ data: NSDictionary) { diff --git a/Example/OnlineChatSdk/ViewController.swift b/Example/OnlineChatSdk/ViewController.swift index 127fcd4..3cb22c3 100644 --- a/Example/OnlineChatSdk/ViewController.swift +++ b/Example/OnlineChatSdk/ViewController.swift @@ -15,8 +15,10 @@ class ViewController: UIViewController { // Do any additional setup after loading the view, typically from a nib. } @IBAction func openChat(_ sender: Any) { - let chatController = storyboard?.instantiateViewController(withIdentifier: "DemoChatController") as! DemoController - navigationController?.pushViewController(chatController, animated: true) +// let chatController = storyboard?.instantiateViewController(withIdentifier: "DemoChatController") as! DemoController + let chatController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "DemoChatController") as! DemoController +// navigationController?.pushViewController(chatController, animated: true) + navigationController?.present(chatController, animated: true, completion: nil) } override func didReceiveMemoryWarning() { diff --git a/Example/Podfile b/Example/Podfile index c382aea..3749c4a 100644 --- a/Example/Podfile +++ b/Example/Podfile @@ -1,7 +1,8 @@ use_frameworks! target 'OnlineChatSdk_Example' do - pod 'OnlineChatSdk', :path => '../' + pod 'OnlineChatSdk' +# pod 'OnlineChatSdk', :path => '../' target 'OnlineChatSdk_Tests' do inherit! :search_paths diff --git a/Example/Podfile.lock b/Example/Podfile.lock index 99b6f58..c817ccd 100644 --- a/Example/Podfile.lock +++ b/Example/Podfile.lock @@ -1,5 +1,5 @@ PODS: - - OnlineChatSdk (0.0.1) + - OnlineChatSdk (0.0.2) DEPENDENCIES: - OnlineChatSdk @@ -9,7 +9,7 @@ SPEC REPOS: - OnlineChatSdk SPEC CHECKSUMS: - OnlineChatSdk: fdc87678fced5df5f4ad3f4304d3eec4de6dad4c + OnlineChatSdk: 421b17a804f22c193f81f02a891e7d91128c525b PODFILE CHECKSUM: adee2f574d16e8ed8f504f977cf28d2797543903 diff --git a/Example/Pods/Manifest.lock b/Example/Pods/Manifest.lock index 99b6f58..c817ccd 100644 --- a/Example/Pods/Manifest.lock +++ b/Example/Pods/Manifest.lock @@ -1,5 +1,5 @@ PODS: - - OnlineChatSdk (0.0.1) + - OnlineChatSdk (0.0.2) DEPENDENCIES: - OnlineChatSdk @@ -9,7 +9,7 @@ SPEC REPOS: - OnlineChatSdk SPEC CHECKSUMS: - OnlineChatSdk: fdc87678fced5df5f4ad3f4304d3eec4de6dad4c + OnlineChatSdk: 421b17a804f22c193f81f02a891e7d91128c525b PODFILE CHECKSUM: adee2f574d16e8ed8f504f977cf28d2797543903 diff --git a/Example/Pods/OnlineChatSdk/OnlineChatSdk/Classes/ChatApi.swift b/Example/Pods/OnlineChatSdk/OnlineChatSdk/Classes/ChatApi.swift new file mode 100644 index 0000000..84c380d --- /dev/null +++ b/Example/Pods/OnlineChatSdk/OnlineChatSdk/Classes/ChatApi.swift @@ -0,0 +1,55 @@ +// +// ChatApi.swift +// OnlineChatSdk +// +// Created by Andrew Blinov on 29/03/2019. +// Copyright © 2019 Andrew Blinov. All rights reserved. +// + +import Foundation + +open class ChatApi { + + private func post(_ url: String, _ params: Dictionary, completionHandler: @escaping (Data?, URLResponse?, Error?) -> Void) { + guard let url = URL(string: url) else { return } + var request = URLRequest(url: url) + request.httpMethod = "POST" + request.addValue("application/json", forHTTPHeaderField: "Content-Type") + guard let httpBody = try? JSONSerialization.data(withJSONObject: params, options: []) else { return } + request.httpBody = httpBody + + let session = URLSession.shared + session.dataTask(with: request, completionHandler: completionHandler).resume() + } + + public func send(_ token: String, _ method: String, _ params: Dictionary, callback: @escaping (NSDictionary?) -> Void) { + let url = "https://admin.verbox.ru/api/chat/\(token)/\(method)" + post(url, params) { (data, response, error) in + guard let data = data else { return } + do { + let json = try JSONSerialization.jsonObject(with: data, options: []) as? NSDictionary + callback(json) + } catch {} + } + } + + public func messages(_ token: String, params: Dictionary, callback: @escaping (NSDictionary?) -> Void) { + send(token, "message", params, callback: callback) + } + + public static func getNewMessages(_ token: String, _ clientId: String, callback: @escaping (NSDictionary?) -> Void) { + let dtFormatter = DateFormatter() + dtFormatter.calendar = Calendar(identifier: Calendar.Identifier.iso8601) + dtFormatter.locale = Locale(identifier: "en") + dtFormatter.dateFormat = "yyyy'-'MM'-'dd'" + dtFormatter.timeZone = TimeZone(secondsFromGMT: 10800) + + let params = [ + "client": ["clientId": clientId], + "sender": "operator", + "status": "unreaded", + "dateRange": ["start": dtFormatter.string(from: Date(timeIntervalSince1970: Date().timeIntervalSince1970 - 86400 * 14)), "stop": dtFormatter.string(from: Date())] + ] as [String : Any] + (ChatApi()).messages(token, params: params, callback: callback) + } +} \ No newline at end of file diff --git a/Example/Pods/OnlineChatSdk/OnlineChatSdk/Classes/ChatController.swift b/Example/Pods/OnlineChatSdk/OnlineChatSdk/Classes/ChatController.swift new file mode 100644 index 0000000..9cf7877 --- /dev/null +++ b/Example/Pods/OnlineChatSdk/OnlineChatSdk/Classes/ChatController.swift @@ -0,0 +1,253 @@ +// +// ChatController.swift +// OnlineChatSdk +// +// Created by Andrew Blinov on 22/03/2019. +// Copyright © 2019 Andrew Blinov. All rights reserved. +// + +import UIKit +import WebKit +import AVFoundation + +open class ChatController: UIViewController, WKNavigationDelegate, WKScriptMessageHandler { + + public static let event_operatorSendMessage = "operatorSendMessage"; + public static let event_clientSendMessage = "clientSendMessage"; + public static let event_clientMakeSubscribe = "clientMakeSubscribe"; + public static let event_contactsUpdated = "contactsUpdated"; + public static let event_sendRate = "sendRate"; + public static let event_clientId = "clientId"; + + public static let method_setClientInfo = "setClientInfo"; + public static let method_setTarget = "setTarget"; + public static let method_openReviewsTab = "openReviewsTab"; + public static let method_openTab = "openTab"; + public static let method_sendMessage = "sendMessage"; + public static let method_receiveMessage = "receiveMessage"; + public static let method_setOperator = "setOperator"; + public static let method_getContacts = "getContacts"; + + public var chatView: WKWebView! + private var callJs: Array! + private var didFinish: Bool = false + + override public func loadView() { + let contentController = WKUserContentController() + contentController.add(self, name: "chatInterface") + + let preferences = WKPreferences() + preferences.javaScriptEnabled = true + preferences.javaScriptCanOpenWindowsAutomatically = true + + let config = WKWebViewConfiguration() + config.userContentController = contentController + config.preferences = preferences + + var frame = UIScreen.main.bounds + if self.parent != nil && self.parent?.view != nil && self.parent?.view.bounds != nil { + frame = (self.parent?.view.bounds)! + } + self.chatView = WKWebView(frame: frame, configuration: config) + self.chatView.navigationDelegate = self + self.view = self.chatView + } + + public func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { + self.didFinish = true + if self.callJs != nil && !self.callJs.isEmpty { + for script in self.callJs { + callJs(script) + } + self.callJs = nil + } + } + + private func getCallJsMethod(_ name: String, params: Array) -> String { + var res: String = "window.MeTalk('" + res.append(name) + res.append("'") + if params.count > 0 { + for p in params { + res.append(",") + if p is Int { + res.append(String(describing: p)) + } else if p is Command { + res.append((p as! Command).command) + } else { + res.append("'") + res.append(String(describing: p)) + res.append("'") + } + } + } + res.append(")") + return res + } + + private func callJs(_ script: String) { + self.chatView.evaluateJavaScript(script) + } + + private func toJson(_ jsonObj: AnyObject) -> String { + var data:Data? = nil + do { + data = try JSONSerialization.data(withJSONObject: jsonObj, options: JSONSerialization.WritingOptions()); + } catch {} + if data != nil { + return NSString(data: data!, encoding: String.Encoding.utf8.rawValue)! as String + } + return "{}" + } + + public func load(_ id: String, _ domain: String, _ language: String = "", _ clientId: String = "") { + var setup: Dictionary = [:] + if !language.isEmpty { + setup["language"] = language + } + if !clientId.isEmpty { + setup["clientId"] = clientId + } + let surl = "https://admin.verbox.ru/support/chat/\(id)/\(domain)" + var url = URL(string: surl) + if !setup.isEmpty { + var urlComponents = URLComponents(url: url!, resolvingAgainstBaseURL: false) + urlComponents?.queryItems = [URLQueryItem(name: "setup", value: toJson(setup as AnyObject))] + url = urlComponents!.url! + } + if url == nil { + url = URL(string: surl) + } + + self.chatView.load(URLRequest(url: url!)) + self.chatView.allowsBackForwardNavigationGestures = true + } + + public func callJsMethod(_ name: String, params: Array) { + if self.didFinish { + callJs(getCallJsMethod(name, params: params)) + } else { + if self.callJs == nil { + self.callJs = [] + } + self.callJs.append(getCallJsMethod(name, params: params)) + } + } + + public func callJsSetClientInfo(_ jsonInfo: String) { + callJsMethod(ChatController.method_setClientInfo, params: [jsonInfo]) + } + + public func callJsSetTarget(_ reason: String) { + callJsMethod(ChatController.method_setTarget, params: [reason]) + } + + public func callJsOpenReviewsTab() { + callJsMethod(ChatController.method_openReviewsTab, params: []) + } + + public func callJsOpenTab(_ index: Int) { + callJsMethod(ChatController.method_openTab, params: [index]) + } + + public func callJsSendMessage(_ text: String) { + callJsMethod(ChatController.method_sendMessage, params: [text]) + } + + public func callJsReceiveMessage(_ text: String, _ oper: String, _ simulateTyping: Int) { + callJsMethod(ChatController.method_receiveMessage, params: [text, oper, simulateTyping]) + } + + public func callJsSetOperator(_ login: String) { + callJsMethod(ChatController.method_setOperator, params: [login]) + } + + public func callJsGetContacts() { + callJsMethod(ChatController.method_getContacts, params: [Command("window.getContactsCallback")]) + } + + public func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { + if message.name != "chatInterface" { + return + } + + let jsonBody = (message.body as! String).data(using: .utf8)! + let body = try? (JSONSerialization.jsonObject(with: jsonBody, options: .mutableLeaves) as! NSDictionary) + if body == nil { + return + } + + if body!["name"] == nil { + return + } + var data: NSDictionary? + if body!["data"] != nil { + data = (body!["data"] as! NSDictionary) + } else { + data = [:] + } + let name = body!["name"] as! String + switch name { + case ChatController.event_clientId: + onClientId(data!["clientId"] != nil ? data!["clientId"] as! String : "") + break + case ChatController.event_sendRate: + onSendRate(data!) + break + case ChatController.event_contactsUpdated: + onContactsUpdated(data!) + break + case ChatController.event_clientSendMessage: + onClientSendMessage(data!) + break + case ChatController.event_clientMakeSubscribe: + onClientMakeSubscribe(data!) + break + case ChatController.event_operatorSendMessage: + onOperatorSendMessage(data!) + break + case ChatController.method_getContacts: + getContactsCallback(data!) + break + default: + break + } + onEvent(name, data!) + } + + open func playSound(_ systemSoundId: SystemSoundID) { + AudioServicesPlaySystemSound(systemSoundId) + } + + open func onClientId(_ clientId: String) { + + } + + open func onSendRate(_ data: NSDictionary) { + + } + + open func onContactsUpdated(_ data: NSDictionary) { + + } + + open func onClientSendMessage(_ data: NSDictionary) { + + } + + open func onClientMakeSubscribe(_ data: NSDictionary) { + + } + + open func onOperatorSendMessage(_ data: NSDictionary) { + self.playSound(1315) + } + + open func onEvent(_ name: String, _ data: NSDictionary) { + + } + + open func getContactsCallback(_ data: NSDictionary) { + + } +} diff --git a/Example/Pods/OnlineChatSdk/OnlineChatSdk/Classes/Command.swift b/Example/Pods/OnlineChatSdk/OnlineChatSdk/Classes/Command.swift new file mode 100644 index 0000000..f0f5c7b --- /dev/null +++ b/Example/Pods/OnlineChatSdk/OnlineChatSdk/Classes/Command.swift @@ -0,0 +1,17 @@ +// +// Command.swift +// OnlineChatSdk +// +// Created by Andrew Blinov on 26/03/2019. +// Copyright © 2019 Andrew Blinov. All rights reserved. +// + +import Foundation + +public struct Command { + let command: String + + init(_ command: String) { + self.command = command + } +} \ No newline at end of file diff --git a/Example/Pods/OnlineChatSdk/README.md b/Example/Pods/OnlineChatSdk/README.md new file mode 100644 index 0000000..111cf59 --- /dev/null +++ b/Example/Pods/OnlineChatSdk/README.md @@ -0,0 +1,141 @@ +# OnlineChatSdk-Swift +[![Version](https://img.shields.io/cocoapods/v/OnlineChatSdk.svg?style=flat)](https://cocoapods.org/pods/OnlineChatSdk) +[![License](https://img.shields.io/cocoapods/l/OnlineChatSdk.svg?style=flat)](https://cocoapods.org/pods/OnlineChatSdk) +![Platform](https://img.shields.io/cocoapods/p/SwiftMessages.svg?style=flat) + +## Добавление в проект + +pod 'OnlineChatSdk' + +## Получение id +Перейдите в раздел «Настройки - Установка» и скопируйте значение переменной id. +![](https://github.com/bekannax/OnlineChatSdk-Android/blob/master/images/2019-03-21_16-53-28.png) + +## Пример использования +Добавьте свой **ViewController** с суперклассом `ChatController`. +```swift +class MyController: ChatController { + + override func viewDidLoad() { + super.viewDidLoad() + load("<Ваш id>", "<Домен вашего сайта>") + } +} +``` +Так же при загрузке можно указать **language** и **clientId**. +```swift +load("<Ваш id>", "<Домен вашего сайта>", "en", "newClientId") +``` + +## События + * **operatorSendMessage** - оператор отправил сообщение посетителю. + * **clientSendMessage** - посетитель отправил сообщение оператору. + * **clientMakeSubscribe** - посетитель заполнил форму. + * **contactsUpdated** - посетитель обновил информацию о себе. + * **sendRate** - посетитель отправил новый отзыв. + * **clientId** - уникальный идентификатор посетителя. + +Для каждого события есть персональный обработчик. +```swift +override func onOperatorSendMessage(_ data: NSDictionary) { + +} + +override func onClientSendMessage(_ data: NSDictionary) { + +} + +override func onClientMakeSubscribe(_ data: NSDictionary) { + +} + +override func onContactsUpdated(_ data: NSDictionary) { + +} + +override func onSendRate(_ data: NSDictionary) { + +} + +override func onClientId(_ clientId: String) { + +} +``` +Или можно задать один обработчик на все события. +```swift +override func onEvent(_ name: String, _ data: NSDictionary) { + switch name { + case ChatController.event_operatorSendMessage: + break + case ChatController.event_clientSendMessage: + break + case ChatController.event_clientMakeSubscribe: + break + case ChatController.event_contactsUpdated: + break + case ChatController.event_sendRate: + break + case ChatController.event_clientId: + break + case ChatController.method_getContacts: + break + default: + break + } +} +``` + +## Методы + * **setClientInfo** - изменение информации о посетителе. + * **setTarget** - пометить посетителя целевым. + * **openReviewsTab** - отобразить форму для отзыва. + * **openTab** - отобразить необходимую вкладку. + * **sendMessage** - отправка сообщения от имени клиента. + * **receiveMessage** - отправка сообщения от имени оператора. + * **setOperator** - выбор любого оператора. + * **getContacts** - получение контактных данных. + +```swift +callJsSetClientInfo("{name: \"Имя\", email: \"test@mail.ru\"") + +callJsSetTarget("reason") + +callJsOpenReviewsTab() + +callJsOpenTab(1) + +callJsSendMessage("Здравствуйте! У меня серьёзная проблема!") + +callJsReceiveMessage("Мы уже спешим на помощь ;)", "", 2000) + +callJsSetOperator("Логин оператора") + +callJsGetContacts() // результат прилетает в getContactsCallback +override func getContactsCallback(_ data: NSDictionary) { + +} +``` +Подробное описание методов можно прочесть в разделе «Интеграция и API - Javascript API». + +## Получение token +Перейдите в раздел «Интеграция и API - REST API», скопируйте существующий token или добавьте новый. +![](https://github.com/bekannax/OnlineChatSdk-Android/blob/master/images/2019-04-01_18-32-22.png) + +## ChatApi +**getNewMessages** - получение новых сообщений от оператора. + +```swift +ChatApi.getNewMessages("", "") + {(result) in + if result?["error"] != nil { + print("error : \(String(describing: result?["error"]))") + } else { + print("result : \(result.debugDescription)") + } + } +``` +Подробное описание можно прочесть в разделе «Интеграция и API - REST API - Инструкции по подключению». + +## License + +OnlineChatSdk is available under the MIT license. See the LICENSE file for more info. diff --git a/Example/Pods/Target Support Files/OnlineChatSdk/OnlineChatSdk-Info.plist b/Example/Pods/Target Support Files/OnlineChatSdk/OnlineChatSdk-Info.plist index cba2585..774f87e 100644 --- a/Example/Pods/Target Support Files/OnlineChatSdk/OnlineChatSdk-Info.plist +++ b/Example/Pods/Target Support Files/OnlineChatSdk/OnlineChatSdk-Info.plist @@ -2,25 +2,25 @@ - CFBundleDevelopmentRegion - en - CFBundleExecutable - ${EXECUTABLE_NAME} - CFBundleIdentifier - ${PRODUCT_BUNDLE_IDENTIFIER} - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - ${PRODUCT_NAME} - CFBundlePackageType - FMWK - CFBundleShortVersionString - 0.0.1 - CFBundleSignature - ???? - CFBundleVersion - ${CURRENT_PROJECT_VERSION} - NSPrincipalClass - + CFBundleDevelopmentRegion + en + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 0.0.3 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + diff --git a/OnlineChatSdk.podspec b/OnlineChatSdk.podspec index a549382..44e3c05 100644 --- a/OnlineChatSdk.podspec +++ b/OnlineChatSdk.podspec @@ -8,7 +8,7 @@ Pod::Spec.new do |s| s.name = 'OnlineChatSdk' - s.version = '0.0.2' + s.version = '0.0.3' s.summary = 'A small library containing a wrapper for the WKWebView.' s.swift_versions = '5.0'