Easily setup a secure chat with the Parley Messaging iOS library. The Parley SDK allows you to fully customize the chat appearance and integrate it seamlessly in your own app for a great user experience.
Pay attention: You need an appSecret
to use this library. The appSecret
can be obtained by contacting Parley.
Empty | Conversation |
---|---|
Firebase
For remote notifications Parley relies on Google Firebase. Configure Firebase (using the installation guide) if you haven't configured Firebase yet.
The Swift Package Manager is a tool for automating the distribution of Swift code and is integrated into the swift compiler.
Once you have your Swift package set up, adding Parley as a dependency is as easy as adding it to the dependencies value of your Package.swift.
dependencies: [
.package(url: "git@github.com:parley-messaging/ios-library.git", .upToNextMajor(from: "4.2.x"))
]
The modules that are available:
Parley
Required:
The core of Parley and is always needed.ParleyNetwork
Optional:
This is a standard provided network implementation of Parley which uses Alamofire to handle network requests.
When not including ParleyNetwork, you'll need to provide your own network implementation (see Advanced - Network layer). Checkout CHANGELOG.md for the latest changes and upgrade notes.
Follow the next steps to get a minimal setup of the library.
ParleyView
to a ViewControllerThe ParleyView
can be initialized manually or directly from the Storyboard.
Manual
Open the ViewController and add the following import:
import Parley
Create an instance of the Parley view (for example) in the viewDidLoad
.
override func viewDidLoad() {
super.viewDidLoad()
let parleyView = ParleyView()
parleyView.frame = self.view.frame
self.view.addSubview(parleyView)
}
Storyboard
Add a view to the View Controller, select the Show the Identity inspector
tab and change the Custom Class
section to:
Class: ParleyView
Module: Parley
Configure Parley with your appSecret
with Parley.configure(_ secret: String)
(for example in your ViewController from step 1).
Parley.configure("appSecret")
Replace appSecret
by your Parley appSecret
. The appSecret
can be obtained by contacting Parley.
Note: calling Parley.configure()
twice is unsupported, make sure to call Parley.configure()
only once for the lifecycle of Parley.
Parley needs the FCM token to successfully handle remote notifications.
FCM Token
After retrieving an FCM token via your Firebase instance, pass it to the Parley instance in order to support remote notifications. This is can be done by using Parley.setPushToken(_:)
.
Parley.setPushToken("pushToken")
Other push types
Parley.setPushToken("pushToken", pushType: .customWebhook)
Parley.setPushToken("pushToken", pushType: .customWebhookBehindOAuth)
Parley.setPushToken("pushToken", pushType: .fcm) // Default
Handle remote notifications
Open your AppDelegate
and add Parley.handle(_ userInfo: [AnyHashable: Any])
to the didReceiveRemoteNotification
method to handle remote notifications.
extension AppDelegate : UNUserNotificationCenterDelegate {
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
_ = Parley.handle(userInfo)
}
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
if UIApplication.applicationState == .active {
completionHandler([]) // Do not show notifications when app is in foreground
} else {
completionHandler([.alert, .sound])
}
}
}
Add a camera and photo library usage description to the Info.plist
file.
<key>NSCameraUsageDescription</key>
<string>We need access to the camera to take photos.</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>We need access to the photo library to select photos.</string>
By default, Parley applies Public Key Pinning on every request executed to the chat api. The certificate(s) should be added to your project.
You can use the certificates in this repository when using the default base url:
/Example/ParleyExample/Supported Files/_.parley.nu_26-Jun-2023.cer
(Expires at: 27 Jun 2024)/Example/ParleyExample/Supported Files/_.parley.nu_27-May-2024.cer
(Expires at: 28 Jul 2025)When a certificate is going to expire you can safely transition by adding the new .cer
to the project. It is important to leave the old .cer
in the app until after the new one is valid. In the next release the old certificate can be removed.
More information about Public Key Pinning can be found on the website of OWASP.
Parley allows the usage of advanced configurations, such as specifying the network, specifying the user information or enabling offline messaging. In all use cases it is recommended to apply the advanced configurations before configuring the chat with Parley.configure(_ secret: String)
.
The network configuration can be set by setting a ParleyNetworkConfig
with the Parley.configure(_ network: ParleyNetwork)
method.
let headers: [String: String] = [
"Custom-Header": "Custom header value"
]
let networkConfig = ParleyNetworkConfig(
url: "https://api.parley.nu/",
path: "clientApi/v1.7",
apiVersion: .v1_7,
headers: headers
)
Parley.configure("appSecret", networkConfig: networkConfig)
Don't forget to add the right certificate to the project.
The standard ParleyNetwork
implementation relies on Alamofire as a dependency which is included in the ParleyNetwork
module.
Parley suppports providing a custom network layer, by doing so you can remove the ParleyNetwork
module dependency and implement your own.
Create your own network session by adhering to the ParleyNetworkSession
protocol:
class CustomNetworkSession : ParleyNetworkSession {
func request(_ url: URL, data: Data?, method: ParleyHTTPRequestMethod, headers: [String : String], completion: @escaping (Result<ParleyHTTPDataResponse, ParleyHTTPErrorResponse>) -> Void) {
// ...
}
func upload(data: Data, to url: URL, method: ParleyHTTPRequestMethod, headers: [String : String], completion: @escaping (Result<ParleyHTTPDataResponse, ParleyHTTPErrorResponse>) -> Void) {
// ...
}
}
Next, configure Parley with the created network session:
let networkSession = CustomNetworkSession()
Parley.configure("appSecret", networkConfig: networkConfig, networkSession: networkSession)
The chat can be identified and encrypted by applying an authorization token to the Parley.setUserInformation(_ authorization: String)
method. The token can easily be generated on a secure location by following the Authorization header documentation.
let authorization = "ZGFhbnw5ZTA5ZjQ2NWMyMGNjYThiYjMxNzZiYjBhOTZmZDNhNWY0YzVlZjYzMGVhNGZmMWUwMjFjZmE0NTEyYjlmMDQwYTJkMTJmNTQwYTE1YmUwYWU2YTZjNTc4NjNjN2IxMmRjODNhNmU1ODNhODhkMmQwNzY2MGYxZTEzZDVhNDk1Mnw1ZDcwZjM5ZTFlZWE5MTM2YmM3MmIwMzk4ZDcyZjEwNDJkNzUwOTBmZmJjNDM3OTg5ZWU1MzE5MzdlZDlkYmFmNTU1YTcyNTUyZWEyNjllYmI5Yzg5ZDgyZGQ3MDYwYTRjZGYxMzE3NWJkNTUwOGRhZDRmMDA1MTEzNjlkYjkxNQ"
Parley.setUserInformation(authorization)
Additional information
Additionally, you can set additional information of the user by using the additionalInformation
parameter in Parley.setUserInformation()
method. The parameter accepts a [String: String]
Dictionary.
let authorization = "ZGFhbnw5ZTA5ZjQ2NWMyMGNjYThiYjMxNzZiYjBhOTZmZDNhNWY0YzVlZjYzMGVhNGZmMWUwMjFjZmE0NTEyYjlmMDQwYTJkMTJmNTQwYTE1YmUwYWU2YTZjNTc4NjNjN2IxMmRjODNhNmU1ODNhODhkMmQwNzY2MGYxZTEzZDVhNDk1Mnw1ZDcwZjM5ZTFlZWE5MTM2YmM3MmIwMzk4ZDcyZjEwNDJkNzUwOTBmZmJjNDM3OTg5ZWU1MzE5MzdlZDlkYmFmNTU1YTcyNTUyZWEyNjllYmI5Yzg5ZDgyZGQ3MDYwYTRjZGYxMzE3NWJkNTUwOGRhZDRmMDA1MTEzNjlkYjkxNQ"
let additionalInformation = [
kParleyAdditionalValueName: "John Doe",
kParleyAdditionalValueEmail: "j.doe@parley.nu",
kParleyAdditionalValueAddress: "Randstad 21 30, 1314, Nederland"
]
Parley.setUserInformation(authorization, additionalInformation: additionalInformation)
Clear user information
Parley.clearUserInformation()
To enable offline messaging, you will have to provide the ParleyMessageDataSource
, ParleyKeyValueDataSource
and ParleyImageDataSource
datasources. These are interfaces you can implement yourself, or use Parley's standard implementations.
Parley provides AES Encrypted implementations, you will have to construct the ParleyCrypter
with a key, you are free to specify the key size yourself.
Then you can construct each of the dataSources with the ParleyCrypter
. Optionally, you can specify the FileManager
and Directory
for each datasource.
When specifying the directory, it is highly recommended to have different directories for each datasource, not doing so would result in two or more datasources working in the same directory, this could cause overwritten or deleted files.
do {
let key = "1234567890123456"
let crypter = try ParleyCrypter(key: key, size: .bits128)
let parleyMessageDataSource = try ParleyEncryptedMessageDataSource(crypter: crypter, directory: .default, fileManager: .default)
let parleyKeyValueDataSource = try ParleyEncryptedKeyValueDataSource(crypter: crypter, directory: .default, fileManager: .default)
let mediaDataSource = try ParleyEncryptedMediaDataSource(crypter: crypter, directory: .default, fileManager: .default)
Parley.enableOfflineMessaging(
messageDataSource: parleyMessageDataSource,
keyValueDataSource: parleyKeyValueDataSource,
mediaDataSource: mediaDataSource
)
} catch {
print(error)
}
Disable offline messaging
Parley.disableOfflineMessaging()
In some cases it may be handy to send a message for the user. You can easily do this by calling;
Parley.send("Lorem ipsum dolar sit amet")
Silent
It is also possible to send silent messages. Those messages are not visible in the chat.
Parley.send("User opened chat", silent: true)
Parley.setReferrer("https://parley.nu/")
By default Parley uses a random UUID as device identifier which will be stored in the user defaults. This can be overridden by passing a custom uniqueDeviceIdentifier
to the configure method:
Parley.configure("appSecret", uniqueDeviceIdentifier: "uniqueDeviceIdentifier")
When passing the uniqueDeviceIdentifier
to the configure method, Parley will not store it. Client applications are responsible for storing it and providing Parley with the same ID in this case.
Parley doesn't need to be reset usually, but in some cases this might be wanted. For example when a user logs out and then logs in with a different account.
Resetting Parley will clear the current user information and chat data that is in memory as well as deregister the device's push token to Parley. This ensures that registered users will not receive push notifications anymore that are not intended for them.
Requires calling the configure()
method again to use Parley.
Parley.reset()
There is also the possibility to only remove the data that is in memory of Parley. The difference with the reset()
method is that this one does not update the backend. In fact, this can be seen as the app going 'inactive' and clearing its memory, while the user keeps being logged in. However, Parley will not be able to recover from this automatically and therefore it is required to call the configure()
method again to use Parley.
Parley.purgeLocalMemory()
By default Parley shows messages directly when they are received via push notifications. Therefore Parley only enables polling when needed, which is when the user disabled notifications in their settings. This check could be ignored to always enable polling instead.
Parley.setAlwaysPolling(true)
Parley provides a ParleyViewDelegate
that can be set on the ParleyView
for receiving callbacks.
self.parleyView.delegate = self
extension ChatViewController: ParleyViewDelegate {
func didSentMessage() {
debugPrint("ChatViewController.didSentMessage")
}
}
Media
Media upload is enabled by default.
self.parleyView.mediaEnabled = false
Appearance
Parley provides a ParleyViewAppearance
that can be set on the ParleyView
to customize the chat appearance. ParleyViewAppearance
can be initialized with a regular, italic and bold font which are customizable. Take a look at ChatViewController.swift for an example of how to use the ParleyViewAppearance
.
let appearance = ParleyViewAppearance(fontRegularName: "Montserrat-Regular", fontItalicName: "Montserrat-Italic", fontBoldName: "Montserrat-Bold")
appearance.offlineNotification.show = true
appearance.pushDisabledNotification.show = true
parleyView.appearance = appearance
By default all texts used by Parley are localized in EN (default) and NL. Overriding the texts can be done by implementing the LocalizationManager
protocol and apply this to Parley.
Parley.setLocalizationManager(manager)
Modern | |
---|---|
Parley is available under the MIT license. See the LICENSE file for more info.