Advanced Settings
SDK Initialization
ThreadsLib.init(ConfigBuilder configBuilder)
public static final class ConfigBuilder {
@NonNull
private Context context;
@NonNull
private PendingIntentCreator pendingIntentCreator = (context1, appMarker) -> {
};
@Nullable
private UnreadMessagesCountListener unreadMessagesCountListener = null;
private boolean isDebugLoggingEnabled = false;
private int historyLoadingCount = 50;
public ConfigBuilder(@NonNull Context context) {}
}
historyLoadingCount
- Numbers of messages that are loaded when requesting the chat history (default: 50)
isDebugLoggingEnabled
- Indicates whether to log the message debug (default: false)
The only required parameter is context
.
Configuring Client
ThreadsLib.initUser(UserInfoBuilderuserInfo)
public final class UserInfoBuilder {
@NonNull
String clientId;
@Nullable
String authToken;
@Nullable
String authSchema;
@Nullable
String clientIdSignature;
@Nullable
String userName;
@Nullable
String data;
@Nullable
String appMarker;
/**
* true if client id is encrypted
*/
boolean clientIdEncrypted = false;
public UserInfoBuilder(@NonNull String clientId) {}
}
The only required parameter is clientId.
clientId
- Client's unique ID. This parameter is required.authToken
- String that will be passed in the Authorization http header.authSchema
- String that will be passed in the X-Auth-Schema http header.clientIdSignature
- Authorization signature clientId. The signature must be generated on your authorization server based on clientId using the RSA private key, then encrypted in Base64. For more details, refer to the backend documentation.userName
- Client's name (can be empty)data
- JSON string with custom client data. The following parameters will be displayed in general client info: Example:
{
"name": "Name Surname",
"phone": "+7-999-999-99-99",
"email": "e@mail.com",
"customField":"customValue"
}
appMarker
- App identifier. edna Android supports connecting several apps to the same server. For more details, refer to Appearance and Behavior Configuration). For that, you need to configure the identifier on the server and in the apps. Any unique string can be used asappMarker
.appMarker
must be the same for the corresponding Android and iOS apps.clientIdEncrypted
- Flag indicating thatclientId
is passed encrypted.
Client Logout
ThreadsLib.logoutClient(@NonNull final String clientId)
Use it for when the client logs out (i.e., when the backend stops trying to deliver messages for this client to the device).
clientId
- Unique client ID
Tracking Number of Unread Messages
unreadMessagesCountListener
- Listener of the number of unread messages
To subscribe to the changes in the number of unread messages, set a listener as follows:
ConfigBuilder.setUnreadMessagesCountListener(new ThreadsLib.UnreadMessagesCountListener() {
@Override
public void onUnreadMessagesCountChanged(int count) {
// Do the necessary actions
}
});
Setting Priority for Notification Channel
Starting with API 26, you can set a priority for the notification channel. For more details, refer here: https://developer.android.com/develop/ui/views/notifications/channels.
In the library, you can configure them using the setNotificationImportance(NotificationManager.IMPORTANCE_...)
method when configuring the builder:
ConfigBuilder(this).setNotificationImportance(NotificationManager.IMPORTANCE_HIGH)
Push Notifications Tap-Through and Integration of Several Chats in One App
pendingIntentCreator
- creator of the push tap-through handler intent
If the user tapped the push notification of the library in the system notifications area, the main screen of the library - ChatActivity - will be opened. To change this behavior, you can configure the creation of your own PendingIntent.
To do this, use the ConfigBuilder.setPendingIntentCreator(ThreadsLib.PendingIntentCreator pendingIntentCreator)
method in application of your application.
ConfigBuilder.setPendingIntentCreator(new ThreadsLib.PendingIntentCreator() {
@Override
public PendingIntent createPendingIntent(Context context, String appMarker) {
if (!TextUtils.isEmpty(appMarker)) {
//Start the appropriate chat according to appMarker
}
});
To integrate several chats in the same app, see the appMarker in the createPendingIntent
app. Use it to specify which chat needs to be opened.
To implement a multi-chat, set clientId
and appMarker
before you launch the current chat. For example, for chat 1 to launch:
ThreadsLib.initUser(
new UserInfoBuilder(clientId1)
.setAppMarker(appMarker1)
)
//Configure design & behavior for chat 1
For chat 2 to launch:
ThreadsLib.initUser(
new UserInfoBuilder(clientId2)
.setAppMarker(appMarker2)
)
//Configure design & behavior for chat 2
Important: clientId1
and clientid2
must be different. Currently, multi-chat with the same clientId
is not supported out-of-the-box. However, implementing a multi-chat with one client is possible. To do this, contact your implementation manager.
Using Styles
ThreadsLib.applyChatStyle(ChatStyle chatStyle)
Use styles to customize the chat appearance. For more details, refer to Appearance and Behavior Configuration
Sending Messages
ThreadsLib.sendMessage(@Nullable String message, @Nullable File file)
Use it to send any message from on behalf of the client. At least one of the parameters - message или file - must not be null.
message
- Message textfile
- File
The default server settings allow you to send files up to 30 MB.
SSL Pinning
It allows you to use a specified list of certificates to check whether they match the certificates on the server.
When utilizing this functionality, we do not recommend using only one certificate. If it is revoked or expired, SDK will stop connecting to the server. Use backup certificates and update them timely.
To enable SSL pinning, you need to:
- Place the public certificates in the res/raw folder.
- In the
Application
class in theConfigBuilder
initialization directory, add the list of certificates. For example:
.certificateRawResIds(Collections.singletonList(R.raw.crt));
- In the manifest, register the network config. For example:
android:networkSecurityConfig="@xml/network_security_config"
In the contents of the configuration file, you need to specify or add a network profile. For example:
<network-security-config>
<domain-config cleartextTrafficPermitted="false">
<domain includeSubdomains="true">your_domain/</domain>
<trust-anchors>
<certificates src="@raw/crt"/>
</trust-anchors>
</domain-config>
</network-security-config>
Timeout Customization
For timeout customization of threads, to ConfigBuilder
, the requestConfig(final RequestConfig requestConfig)
method has been added.
RequestConfig contains the following fields with default settings:
socketClientSettings
(type SocketClientSettings) - Socket connection settingspicassoHttpClientSettings
(type HttpClientSettings) - HTTP connection settings for the Picasso image download libraryauthHttpClientSettings
(type HttpClientSettings) - HTTP connection settings for authorizationthreadsApiHttpClientSettings
(type HttpClientSettings) - HTTP connection settings for the Chat Center server API
SocketClientSettings contains the following:
resendIntervalMillis
- Interval of the repeated attempt to send the messageresendPingIntervalMillis
- Interval of requests to maintain an active connection (OkHttpClient.Builder().pingInterval()
)connectTimeoutMillis
- Timeout for establishing a new connection (OkHttpClient.Builder().connectTimeout()
)readTimeoutMillis
- Read operation timeout for a new connection (OkHttpClient.Builder().readTimeout()
)writeTimeoutMillis
- Timeout of write operations for a new connection (OkHttpClient.Builder().writeTimeout()
)
HttpClientSettings contains the following:
connectTimeoutMillis
- Timeout for establishing a new connection (OkHttpClient.Builder().connectTimeout()
)readTimeoutMillis
- Read operation timeout for a new connection (OkHttpClient.Builder().readTimeout()
)writeTimeoutMillis
- Timeout of write operations for a new connection (OkHttpClient.Builder().writeTimeout()
)
Using Internal Deeplinks
The library allows you to use internal deeplinks. For example, if there is text in the following format is in the message:
earth://some.params?code={code}
And if you create Activity that will be launched by Аction.VIEW, then the specified activity will launch when the link is tapped. For that, specify filters for your activity:
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="earth"
android:host="*" />
</intent-filter>
Configuring Backup for App
The library uses the following setting:
<application
android:fullBackupContent="@xml/backup_rules">
...
</application>
The contents of this file is as follows:
<full-backup-content>
<exclude domain="sharedpref" path="im.threads.internal.utils.EncryptedPrefStore.xml"/>
</full-backup-content>
This entry is required so that encrypted SharedPreferences
do not remain in the device's memory after the app is reinstalled.
If you use your own fullBackupContent
file, you need to add exclude
that is defined on our side to your file and override the file with yours:
<application
android:fullBackupContent="@xml/your_backup_rules"
tools:replace="android:fullBackupContent">
...
</application>
Other SDKs might use the android:fullBackupContent
setting as well. In this case, you need to review which exceptions are registered in these SDKs and make a shared file. For example, Vungle and AppsFlyer have their own fullBackupContent
settings. Their exceptions are documented as follows:
To merge their settings with the ones we have, the file should look as follows:
<?xml version="1.0" encoding="utf-8"?>
<full-backup-content>
<exclude domain="sharedpref" path="appsflyer-data"/>
<exclude domain="file" path="vungle" />
<exclude domain="file" path="vungle_cache" />
<exclude domain="external" path="vungle_cache" />
<exclude domain="database" path="vungle_db" />
<exclude domain="sharedpref" path="com.vungle.sdk.xml" />
<exclude domain="sharedpref" path="im.threads.internal.utils.EncryptedPrefStore.xml"/>
</full-backup-content>
Logger
The library uses its own logger that supports recording to a file. It is disabled by default, meaning the logs will not be recorded to a file or to the console.
To enable the logs in the library, you need to enable enableLogging
in ConfigBuilder
and pass the logger builder as follows:
val configBuilder = ConfigBuilder(this) // this - app context
.enableLogging(loggerConfig)
ConfigBuilder configBuilder = new ConfigBuilder(this) // this - app context
.enableLogging(loggerConfig)
To create a logger builder, you need to complete the following command:
LoggerConfig.Builder(this) // this - app context
To enable recording logs to a file, you need to enable this as a feature:
logToFile()
Then, you need to specify the log directory:
dir(File(this.filesDir, "logs"))
The logger supports two types of logging. It can be logging into either a single file or to several files, the name of which will be equal to the start time of the app session. For that, LoggerRetentionPolicy
is used with the FILE_COUNT
value used for sessions and TOTAL_SIZE
used for recording into a single file.
The logging method is specified as:
retentionPolicy(LoggerRetentionPolicy.TOTAL_SIZE)
If you used LoggerRetentionPolicy.TOTAL_SIZE
, then, to limit the max size, specify the following:
maxTotalSize(N) // N - size in bytes
Also, in case with LoggerRetentionPolicy.TOTAL_SIZE
, you can enter your own name for the file (by default, it will be the start time of the first session). For that, specify the following:
fileName("your_file_name")
If you used LoggerRetentionPolicy.FILE_COUNT
, then, to limit the number of files, specify the following:
maxFileCount(N) // N - number of files
To define the minimum level for logs (default - LoggerLevel.VERBOSE), specify the following:
minLogLevel(logLevel) // logLevel - your minimum level for logs
At the end, you need to call build()
. Configuration example:
val loggerConfig = LoggerConfig.Builder(this)
.logToFile()
.dir(File(this.filesDir, "logs"))
.retentionPolicy(LoggerRetentionPolicy.TOTAL_SIZE)
.maxTotalSize(5242880)
.build()
LoggerConfig loggerConfig = new LoggerConfig.Builder(this)
.logToFile()
.dir(File(this.filesDir, "logs"))
.retentionPolicy(LoggerRetentionPolicy.TOTAL_SIZE)
.maxTotalSize(5242880)
.build()