Getting started
See how you can get a 1:1 chat app quickly up and running.
You will download a sample Android app that uses two PubNub Chat Components for Android: MessageInput and MessageList. Then, you'll run the app and send your first message by typing it in the message input field. The messages will pile up on the screen as you send them.
Prerequisites
- Android Studio (>= Bumblebee 2021.1.1)
- git
Tools used
This guide uses PubNub Kotlin SDK (>= 7.0.0) for chat components and Jetpack Compose as the UI Toolkit.
Steps
Follow the steps to get your PubNub keys, clone the sample Android project files with chat components, and run the app to send your first message.
Create a PubNub account
Before you start, you need to obtain Publish and Subscribe Keys for your chat app. You need them to initialize the PubNub object in your app to send and receive messages through the PubNub Network. To get both keys, sign in or create an account on the Admin Portal. The autogenerated Demo Keyset in My First App already contains the configuration required to complete this guide.
Clone a sample chat app with components
Clone a sample app from the chat-components-android-examples
repository.
git clone git@github.com:pubnub/chat-components-android-examples.git
Configure PubNub keys
Once you've cloned the repository, open it in Android Studio and wait until it loads.
In the
gradle.properties
file, replace bothPUBNUB_PUBLISH_KEY
andPUBNUB_SUBSCRIBE_KEY
with your Publish and Subscribe Keys from your PubNub account in the Admin Portal:PUBNUB_PUBLISH_KEY="myPublishKey" PUBNUB_SUBSCRIBE_KEY="mySubscribeKey"
Click Sync Now or the Sync Project with Gradle Files icon in the top notification bar to update your Android project.
The rest of the configuration is already provided:
Dependencies to the PubNub Chat Components for Android and the Kotlin SDK are defined in the
Dependencies.kt
file:object PubNub { private const val version = "7.0.0" const val pubnub = "com.pubnub:pubnub-kotlin:$version" object Components { const val chat = "com.pubnub.components:chat-android:0.2.0" } }
In the
ChatActivity
file, the app initializes the PubNub instance in theonCreate()
method:override fun onCreate(savedInstanceState: Bundle?) { ... initializePubNub() ... }
Similarly, the app will destroy the PubNub instance and clean up all related resources once the application is terminated:
override fun onDestroy(){ pubNub.destroy()
To associate a sender/current user with the PubNub messages, it's required to configure the
uuid
parameter that stands for Universally Unique Identifier and refers to your user ID in the database. The app already setsuuid
in theChatActivity
file, under theinitializePubNub()
method. BothpublishKey
andsubscribeKey
are copied from thegradle.properties
file to theBuildConfig
file when the project is built.private fun initializePubNub(){ pubNub = PubNub( PNConfiguration(uuid = "myFirstUser").apply { publishKey = BuildConfig.PUBLISH_KEY subscribeKey = BuildConfig.SUBSCRIBE_KEY ... } ) }
UUID
For simplicity, the getting started app sets a static UUID. However, if you implement chat in your app, you should generate a UUID per user, device, and server and reuse it for their lifetime. Using separate UUIDs in real-life apps is particularly important as it impacts your overall billing and the way your app works.
The app calls
ChatProvider
which initializes all the data components. These components are responsible for providing data to UI, setting the default app theme, and communicating with the PubNub service.ChatProvider
is initialized by modifying the application theme functionality, in theTheme.kt
file. This file is used to facilitate the majority of the functionality provided by PubNub Chat Components for Android.@Composable fun AppTheme( darkTheme: Boolean = isSystemInDarkTheme(), pubNub: PubNub, content: @Composable() () -> Unit ) { val colors = if (darkTheme) DarkColorPalette else LightColorPalette MaterialTheme( colors = colors, typography = Typography, shapes = Shapes, ) { ChatProvider(pubNub) { content() } } }
The
setContent()
method in theChatActivity
file calls theAppTheme()
composable function responsible for setting the visual content of chat components' content on the screen:setContent { AppTheme(pubNub = pubNub) { AddDummyData(channel) Box(modifier = Modifier.fillMaxSize()) { ChannelView(id = channel) } } }
In the
ChatApplication
file, the app initializes the default Android Room persistence library to save data in a local database. This database is used to fill the data for all the chat components.override fun onCreate() { super.onCreate() Database.initialize(this) }
The Room database needs data to display in the sample app. This data is provided in the
AddDummyData
method in theChatActivity
file.@Composable fun AddDummyData(vararg channelId: ChannelId) { // Creates a user object with uuid val memberRepository: DefaultMemberRepository = LocalMemberRepository.current val member: DBMember = DBMember(id = pubNub.configuration.uuid, name = "myFirstUser", profileUrl = "https://picsum.photos/200") // Creates a membership so that the user could subscribe to channels val membershipRepository: DefaultMembershipRepository = LocalMembershipRepository.current val memberships: Array<DBMembership> = channelId.map { id -> DBMembership(channelId = id, memberId = member.id) }.toTypedArray() // Fills the database with member and memberships data val scope = rememberCoroutineScope() LaunchedEffect(null) { scope.launch { memberRepository.add(member) membershipRepository.add(*memberships) } } }
In the same
ChatActivity
file, the app invokes chat components by passing a channel-relatedid
parameter to the composable function.private val channel: ChannelId = "Default"
@Composable fun ChannelView(id: ChannelId) { // region Content data val messageViewModel: MessageViewModel = MessageViewModel.defaultWithMediator(channelId) val messages = remember { messageViewModel.getAll() } // endregion CompositionLocalProvider(LocalChannel provides channelId) { Chat.Content( messages = messages, ) } }
The
Content
function in theChat.kt
file draws theMessageList
andMessageInput
components in a column.@Composable internal fun Content( messages: Flow<PagingData<MessageUi>>, presence: Presence? = null, onMemberSelected: (UserId) -> Unit = {}, ) { val localFocusManager = LocalFocusManager.current Column( modifier = Modifier.fillMaxSize() .pointerInput(Unit) { detectTapGestures(onTap = { localFocusManager.clearFocus() }) } ) { MessageList( messages = messages, presence = presence, onMemberSelected = onMemberSelected, modifier = Modifier .fillMaxSize() .weight(1f, true), ) MessageInput( typingIndicator = true, typingIndicatorRenderer = AnimatedTypingIndicatorRenderer, ) } }
To make sure the app works upon running, it needs internet permissions to connect to the PubNub Network. This is specified in the
AndroidManifest.xml
file.
<uses-permission android:name="android.permission.INTERNET"/>
OkHttp version
The Kotlin SDK that PubNub Chat Components for Android are based on uses OkHttp client in version 4.9.3
to handle all HTTP requests. If your chat app uses a different version of the OkHttp client, make sure to override it in the NetworkImage.kt
file as follows: val url = data.toHttpUrl()
.
Run the chat app
Choose an emulator and run the getting-started
app.
Send your first message
When your application opens up, type and send your first message. The messages will pile up on the screen as you send them.
To verify that the app is connected to the PubNub Network, mock a real-live chat conversation with myFirstUser
. Open the app in a new emulator, send a message from one emulator and reply to it from another.