Skip to main content

Developing App - JVM

This guide will help you create and understand how to develop and deploy a simple Wire Application written in a JVM language (Java, Kotlin, Scala). The SDK you will be using will simplify encryption/decryption, and http client calls to the Wire backend, leaving you to care about your business logic.

Note that the SDK takes care of security in transit and partially for securing cryptographic data stored by the SDK in the filesystem. However, as you will have access to decrypted messages and identifiers of conversations and teams, it is up to you to secure them.

Prerequisites

  • Java 17 or higher
  • Kotlin 2.x.x if you are using Kotlin
  • An application registered with Wire (to obtain an API token)
  • File system access for storing cryptographic keys and data

Adding the SDK to Your Project

dependencies {
implementation("com.wire:wire-apps-jvm-sdk:0.0.1")
}

Initializing the SDK

App registration through Team Management isn’t available yet. For now, create an account manually for your app and configure the required environment variables.

Environment Variables

# Credentials for the Wire account you just created
WIRE_SDK_EMAIL=your_email@domain.com
WIRE_SDK_PASSWORD=dummyPassword

# Open Settings, scroll to Profile link, and copy the user ID and domain
# Example of Profile Link:
# https://account.wire.com/user-profile/?id=abcd-1234-efgh-5678@my.domain.link
WIRE_SDK_USER_ID=abcd-1234-efgh-5678

Since app registration is not implemented yet, set applicationId and apiToken to arbitrary values.

For example:

  • applicationId: UUID.randomUUID()
  • apiToken: myApiToken

Constructor parameters

The SDK needs to be initialized with your application's credentials, the backend host, a key for the cryptographic material and your event handler implementation:

ParameterDescription
applicationId + apiTokenUniversally unique identifier (UUID) of the app and a token that allows access to Wire-server endpoints.
Available in Team Management after registering an app
apiHostURL of the backend that hosts Wire.
For Wire Cloud, use https://prod-nginz-https.wire.com
cryptographyStorageKeyCryptographic key used to encrypt local storage.
See how to generate cryptographically secure key
wireEventsHandlerYour implementation of WireEventsHandler abstract class

Initializing an instance of WireAppSdk is enough to get access to local stored teams and conversations and to send messages or similar actions.

However, to establish a long-lasting connection with the backend and receive all the events targeted to you Application, you need to call the startListening() method. The startListening() method keeps a background thread running until explicitly stopped or the application terminates.

Complete Example

Here's a complete example showing how to initialize the SDK and handle basic received events:

fun main() {
val wireAppSdk = WireAppSdk(
applicationId = UUID.fromString("YOUR_APPLICATION_ID"),
apiToken = "YOUR_API_TOKEN",
apiHost = "YOUR_API_HOST",
cryptographyStorageKey = yourGeneratedSecureKeyByteArray, // Must be 32 bytes
object : WireEventsHandlerSuspending() {
override suspend fun onTextMessageReceived(wireMessage: WireMessage.Text) {
println("Text message received: $wireMessage")

// Add your message handling logic here, like storing the message,
// sending back another message, or triggering some workflow
}
}
)

// Start the SDK
wireAppSdk.startListening()
}

For simplicity the subclassing of WireEventsHandler is done inline as an anonymous class, but you can create a separate class for it, especially if you handle events in a complex way:

class MyWireEventsHandler : WireEventsHandlerSuspending() {
private val logger = LoggerFactory.getLogger(MyWireEventsHandler::class.java)

override suspend fun onTextMessageReceived(wireMessage: WireMessage.Text) {
logger.info("Text message received: $wireMessage")
}
}

Echoing a received message

In your onTextMessageReceived implementation from MyWireEventsHandler you can echo a message as:

override suspend fun onTextMessageReceived(wireMessage: WireMessage.Text) {
val message = WireMessage.Text.createReply(
conversationId = wireMessage.conversationId,
text = "${wireMessage.text} -- Sent from the SDK",
mentions = wireMessage.mentions,
originalMessage = wireMessage
)

// The manager is accessible through the inherited WireEventsHandler class.
// It is used to manage the Wire application's lifecycle and communication with the backend.
manager.sendMessageSuspending(message = message)
}

Conclusion

With this basic setup you now have a simple Wire App.

You can check other events in Wire Events

Troubleshooting

  • Enable DEBUG logging on the SDK if you are developing an Application and want to test it in a safe environment. Set the log level to DEBUG in your logging framework for the package com.wire.sdk (e.g. for Logback <logger name="com.wire.sdk" level="DEBUG" />).
  • If you switch between different Wire environments, you may need to delete the storage/apps.db directory to avoid conflicts
  • For connection issues, verify your API token, host URL and if your deployed app has access to the public network (firewalls, docker ports, etc.)
  • When running into cryptography issues, ensure your storage key is consistent between app restarts
  • The SDK is designed to be thread-safe. The startListening() and stopListening() methods are synchronized to prevent concurrent modifications to the SDK state. However at this moment, only using a single Wire Application instance has been tested.
  • If you are using Spring Boot or similar frameworks that force dependency versions, you might need to add explicit dependency management for the SDK dependencies to avoid version conflicts. For example you might force something like implementation("org.jetbrains.kotlin:kotlin-stdlib:2.2.21") if Spring forces an older version which is incompatible with the SDK.
  • In case you need to build the SDK locally, you can skip the signing option by running: ./gradlew publishToMavenLocal -PskipSigning=true (Keep in mind to include repositories { mavenCentral() } in your build.gradle.kts file in the app where you use the locally built SDK)

Additional Resources

For any issue, requests or improvements, let us know by contacting us or creating a new issue on GitHub