KotlinKotlin SDK 5.0.2


<dependency>
  <groupId>com.pubnub</groupId>
  <artifactId>pubnub-gson</artifactId>
  <version>5.0.2</version>
</dependency>

implementation 'com.pubnub:pubnub-kotlin:5.0.2'
To use Pubnub, simply copy the Pubnub-5.0.2 jar file into your project's libs directory.

# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
#   http://developer.android.com/guide/developing/tools/proguard.html

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
#   public *;
#}

# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

-keepattributes Exceptions, InnerClasses, Signature, Deprecated, SourceFile, LineNumberTable, *Annotation*, EnclosingMethod

-keep class com.google.android.gms.ads.identifier.** { *; }

# Joda-Time
-dontwarn org.joda.time.**
-keep class org.joda.time.** { *; }

# Gson
-dontwarn sun.misc.**
-keep class sun.misc.Unsafe { *; }
-keep class com.google.gson.examples.android.model.** { *; }
-keep class * implements com.google.gson.TypeAdapterFactory
-keep class * implements com.google.gson.JsonSerializer
-keep class * implements com.google.gson.JsonDeserializer

# org.json
-keep class org.json.** { *; }

# OkHttp3
-dontwarn okhttp3.**
-dontwarn org.codehaus.mojo.animal_sniffer.*
-keepnames class okhttp3.internal.publicsuffix.PublicSuffixDatabase

# Okio
-dontwarn okio.**

# Retrofit 2.X
-dontwarn retrofit2.**
-dontwarn javax.annotation.**
-keepclassmembers,allowshrinking,allowobfuscation interface * {
    @retrofit2.http.* <methods>;
}
-keepclasseswithmembers class * {
    @retrofit2.http.* <methods>;
}

# Logback and slf4j-api
-dontwarn ch.qos.logback.core.net.*
-dontwarn org.slf4j.**
-keep class ch.qos.** { *; }
-keep class org.slf4j.** { *; }

# PubNub
-dontwarn com.pubnub.**
-keep class com.pubnub.** { *; }


Add PubNub to your project using one of the procedures defined under How To Get It.

 Always set the UUID to uniquely identify the user or device that connects to PubNub. This UUID should be persisted, and should remain unchanged for the lifetime of the user or the device. Not setting the UUID can significantly impact your billing if your account uses the Monthly Active Users (MAUs) based pricing model, and can also lead to unexpected behavior if you have Presence enabled.
import com.google.gson.JsonObject

import com.pubnub.api.PNConfiguration
import com.pubnub.api.PubNub
import com.pubnub.api.callbacks.SubscribeCallback
import com.pubnub.api.enums.PNStatusCategory
import com.pubnub.api.models.consumer.PNStatus
import com.pubnub.api.models.consumer.pubsub.PNMessageResult
import com.pubnub.api.models.consumer.pubsub.PNPresenceEventResult

fun main() {
    val config = PNConfiguration()
    config.subscribeKey = "mySubKey"
    config.publishKey = "myPubKey"
    config.uuid = "myUniqueUuid"

    val pubnub = PubNub(config)

    val myChannel = "awesomeChannel"
    val myMessage = JsonObject().apply {
        addProperty("msg", "hello")
    }

    println("Message to send $myMessage")

    pubnub.addListener(object : SubscribeCallback() {

        override fun status(pubnub: PubNub, status: PNStatus) {
            when (status.category) {
                PNStatusCategory.PNConnectedCategory -> {
                    // Connect event. You can do stuff like publish, and know you'll get it.
                    // Or just use the connected event to confirm you are subscribed for
                    // UI / internal notifications, etc
                }
                PNStatusCategory.PNReconnectedCategory -> {
                    // Happens as part of our regular operation.
                    // This event happens when radio / connectivity is lost, then regained.
                }
                PNStatusCategory.PNUnexpectedDisconnectCategory -> {
                    // This event happens when radio / connectivity is lost
                }
            }
        }

        override fun message(pubnub: PubNub, pnMessageResult: PNMessageResult) {
            if (pnMessageResult.channel == myChannel) {
                println("Received message ${pnMessageResult.message.asJsonObject}")
            }
        }

        override fun presence(pubnub: PubNub, pnPresenceEventResult: PNPresenceEventResult) {
            // handle presence
        }
    })

    pubnub.subscribe().apply {
        channels = listOf(myChannel)
    }.execute()

    pubnub.publish().apply {
        channel = myChannel
        message = myMessage
    }.async { result, status ->
        println(status)
        if (!status.error) {
            println("Message sent, timetoken: ${result!!.timetoken}")
        } else {
            println("Error while publishing")
            status.exception?.printStackTrace()
        }
    }
}
In addition to the Hello World sample code, we also provide some copy and paste snippets of common API functions:

Instantiate a new Pubnub instance. Only the subscribeKey is mandatory. Also include publishKey if you intend to publish from this instance, and the secretKey if you wish to perform PAM administrative operations from this Kotlin instance.

 

It's not best practice to include the secretKey in client-side code for security reasons.
When you initialize with secretKey, you get root permissions for the Access Manager. With this feature you don't have to grant access to your servers to access channel data. The servers get all access on all channels.

 Always set the UUID to uniquely identify the user or device that connects to PubNub. This UUID should be persisted, and should remain unchanged for the lifetime of the user or the device. Not setting the UUID can significantly impact your billing if your account uses the Monthly Active Users (MAUs) based pricing model, and can also lead to unexpected behavior if you have Presence enabled.
val config = PNConfiguration().apply {
    subscribeKey = "mySubKey"
    publishKey = "myPubKey"
    uuid = "myUniqueUuid"
}
val pubnub = PubNub(config)
pubnub.addListener(object : SubscribeCallback() {

    override fun status(pubnub: PubNub, status: PNStatus) {
        println("Status category: ${status.category}")
        // PNConnectedCategory, PNReconnectedCategory, PNDisconnectedCategory

        println("Status operation: ${status.operation}")
        // PNSubscribeOperation, PNHeartbeatOperation

        println("Status error: ${status.error}")
        // true or false
    }

    override fun presence(pubnub: PubNub, pnPresenceEventResult: PNPresenceEventResult) {
        println("Presence event: ${pnPresenceEventResult.event}")
        println("Presence channel: ${pnPresenceEventResult.channel}")
        println("Presence uuid: ${pnPresenceEventResult.uuid}")
        println("Presence timetoken: ${pnPresenceEventResult.timetoken}")
        println("Presence occupancy: ${pnPresenceEventResult.occupancy}")
    }

    override fun message(pubnub: PubNub, pnMessageResult: PNMessageResult) {
        println("Message payload: ${pnMessageResult.message}")
        println("Message channel: ${pnMessageResult.channel}")
        println("Message publisher: ${pnMessageResult.publisher}")
        println("Message timetoken: ${pnMessageResult.timetoken}")
    }

    override fun signal(pubnub: PubNub, pnSignalResult: PNSignalResult) {
        println("Signal payload: ${pnSignalResult.message}")
        println("Signal channel: ${pnSignalResult.channel}")
        println("Signal publisher: ${pnSignalResult.publisher}")
        println("Signal timetoken: ${pnSignalResult.timetoken}")
    }

    override fun messageAction(pubnub: PubNub, pnMessageActionResult: PNMessageActionResult) {
        with(pnMessageActionResult.messageAction) {
            println("Message action type: $type")
            println("Message action value: $value")
            println("Message action uuid: $uuid")
            println("Message action actionTimetoken: $actionTimetoken")
            println("Message action messageTimetoken: $messageTimetoken")
        }

        println("Message action subscription: ${pnMessageActionResult.subscription}")
        println("Message action channel: ${pnMessageActionResult.channel}")
        println("Message action timetoken: ${pnMessageActionResult.timetoken}")
    }
})
val listener = object : SubscribeCallback() {
    override fun status(pubnub: PubNub, pnStatus: PNStatus) {}
    override fun message(pubnub: PubNub, pnMessageResult: PNMessageResult) {}
    // and other callbacks
}

pubnub.addListener(listener)

// some time later
pubnub.removeListener(listener)

The client may disconnect due to unpredictable network conditions.

Automatic reconnection can be configured out of the box:

pubnub.configuration.reconnectionPolicy = PNReconnectionPolicy.LINEAR
// choose between LINEAR and EXPONENTIAL
// default is NONE

pubnub.configuration.maximumReconnectionRetries = 10
// how many times the client will try to reconnect
// until giving up
// default is infinite

Or manually:

pubnub.addListener(object : SubscribeCallback() {

    override fun status(pubnub: PubNub, status: PNStatus) {
        if (status.category == PNStatusCategory.PNUnexpectedDisconnectCategory ||
            status.category == PNStatusCategory.PNTimeoutCategory
        ) {
            pubnub.reconnect()
        }
    }
    
})
CategoriesDescription
PNAcknowledgmentCategoryUsed API report success with this status category.
PNAccessDeniedCategoryRequest failed because of access error (active PAM)
PNTimeoutCategoryUsed API didn't receive response from server in time.
PNConnectedCategorySDK subscribed with a new mix of channels (fired every time the channel / channel group mix changed).
PNReconnectedCategorySubscription loop has been reconnected due some reasons.
PNUnexpectedDisconnectCategoryPreviously started subscribe loop did fail and at this moment client disconnected from real-time data channels.
PNCancelledCategoryRequest was cancelled by user.
PNBadRequestCategoryThe server responded with 400 because the request is malformed.
PNMalformedResponseCategoryRequest received in response non-JSON data. It can be because of publish WiFi hotspot which require authorization or proxy server message.
PNRequestMessageCountExceededCategoryIf requestMessageCountThreshold is set, this status event will arrive each time when the client receives more messages than specified.
PNReconnectionAttemptsExhaustedThe SDK loop has been stopped due maximum reconnection exhausted.
PNNotFoundCategoryThe subscriber gets a 404 from the server.
PNUnknownCategoryThe subscriber gets a 4xx code from the server, other than 400, 403 and 404
Call time() to verify the client connectivity to the origin:
pubnub.time()
    .async { result, _ ->
        println("Server time: ${result?.timetoken}")
    }
pubnub.subscribe().apply { 
    channels = listOf("my_channel")
}.execute()
The response of the call is handled by adding a Listener. Please see the Listeners section for more details.
Publish a message to a channel:
pubnub.publish().apply {
    channel = "my_channel"
    message = "hello"
}.async { result, status ->
    // the result is always of a nullable type
    // it's null if there were errors (status.error)
    // otherwise it's usable

    // handle publish result
    if (!status.error) {
        println("Message timetoken: ${result!!.timetoken}")
    } else {
        // handle error
        status.exception.printStackTrace()
    }
}
Get occupancy of who's here now on the channel by UUID:
Requires you to enable the Presence add-on for your key. Refer to the How do I enable add-on features for my keys? knowledge base article for details on enabling features.
pubnub.hereNow().apply {
    channels = listOf("my_channel")
    includeUUIDs = true
}.async { result, status ->
    if (!status.error) {
        result!!.channels.forEach { (_, v) ->
            println("Channel name: ${v.channelName}")
            println("Occupancy: ${v.occupancy}")
            println("Occupants: ")
            v.occupants.forEach { o ->
                println("UUID ${o.uuid}")
            }
        }
    }
}
Subscribe to realtime Presence events, such as join, leave, and timeout, by UUID. Setting the presence attribute to a callback will subscribe to presents events on my_channel:
Requires you to enable the Presence add-on for your key. Refer to the How do I enable add-on features for my keys? knowledge base article for details on enabling features.
pubnub.subscribe().apply {
    channels = listOf("my_channel")
    withPresence = true
}
The response of the call is handled by adding a Listener. Please see the Listeners section for more details.
Retrieve published messages from archival storage:
Requires that the Storage and Playback add-on is enabled for your key. How do I enable add-on features for my keys? - see http://www.pubnub.com/knowledge-base/discussion/644/how-do-i-enable-add-on-features-for-my-keys
pubnub.history().apply {
    channel = "my_channel" // where to fetch history from
}.async { result, status ->
    result?.messages?.forEach {
        println("Message: ${it.entry}")
    }
}
pubnub.unsubscribe().apply { 
    channels = listOf("my_channel")
}.execute()
The response of the call is handled by adding a Listener. Please see the Listeners section for more details.