Kotlin
PushExpress -- SDK Kotlin
You will need to integrate your Push.Express account with Firebase.
Setup Firebase
Go to Firebase Console and create a new project (or use existing one)
You can use one project for all your apps.
Open Project Settings -> General

Create new Android app or just download
google-services.jsonfrom existing app

If you need to create new app, just:
Register it
Download
google-services.jsonPress next-next-next =)

Put
google-services.jsonto your app dir (like<project>/app/google-services.json)Add the plugin as a dependency to your project-level build.gradle.kts file: Root-level (project-level) Gradle file (/build.gradle.kts)::
// Top-level build file where you can add configuration options common to all sub-projects/modules. plugins { alias(libs.plugins.android.application) apply false alias(libs.plugins.kotlin.android) apply false alias(libs.plugins.kotlin.compose) apply false // Add the dependency for the Google services Gradle plugin id("com.google.gms.google-services") version "4.4.3" apply false }In your module (app-level) Gradle file (
<project>/<app-module>/build.gradle.kts), add the Firebase Cloud Messaging dependency:plugins { alias(libs.plugins.android.application) alias(libs.plugins.kotlin.android) alias(libs.plugins.kotlin.compose) id("com.google.gms.google-services") } dependencies { // Import the Firebase BoM implementation(platform("com.google.firebase:firebase-bom:33.0.0")) // ... }
Full official instructions can be found in Firebase Cloud Messaging Android guide.
Setup Push.Express
Get Firebase Private key
Go to Firebase Console and create a new project (or use existing one)
You can use one project for all your apps.
Open Project Settings

Go to Service accounts, press
Generate new private keyand save it to fileprivate-key.json(you can use same key for all apps)
Integrate your Push.Express App with Firebase
Go to your Push.Express account
Open existing App settings or create a new App
Switch type application Firebase

Paste
private-key.jsonfile to Firebase Admin SDK private key textbox
Add sdk in your application
Before proceeding with the integration, make sure you have already installed the Firebase SDK in your application. If not, follow steps 4-6 in the Firebase Cloud Messaging integration guide
Add the JitPack repository to your build file
Ensure you have the latest Android Studio and Android Gradle Plugin!
In your settings.gradle.kts, add the Jitpack repo to repositories list (only if you use Gradle Centralized Repository Declaration feature, default for new projects since Android Studio Electric Eel):
// settings.gradle (Project Settings) in Android Studio
// ...
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
// ...
maven { url = uri("https://jitpack.io") }
}
}Add Push.Express SDK dependency
In your module (app-level) Gradle file (<project>/<app-module>/build.gradle), add the pushexpress-android-sdk dependency:
// build.gradle (Module :app) in Android Studio
// ...
dependencies {
// ...
implementation ("com.github.pushexpress:pushexpress-android-sdk:v1.4.0")
}Add AndroidManifest.xml
To correctly open links from push notifications in the app, add an Intent filter:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<!-- Permissions -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/Theme.YourApp">
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTask">
<!-- Launcher -->
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<!-- Deep links with your custom scheme -->
<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="yourapp" android:host="open" />
</intent-filter>
<!-- HTTPS URLs for push notifications -->
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="https" android:host="push.express" />
</intent-filter>
<!-- Catch all HTTP/HTTPS (for browser redirect) -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="https" />
<data android:scheme="http" />
</intent-filter>
<!-- Fallback for empty deep links -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<!-- Firebase Messaging Service -->
<service
android:name=".MyFirebaseMessagingService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
</application>
</manifest>Add required code
Get your
PUSHEXPRESS_APP_IDfrom Push.Express account page
Create MyFirebaseMessagingService.kt
package com.yourpackage
import android.util.Log
import com.google.firebase.messaging.FirebaseMessagingService
import com.google.firebase.messaging.RemoteMessage
import com.pushexpress.sdk.main.SdkPushExpress
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel
import kotlinx.coroutines.launch
class MyFirebaseMessagingService : FirebaseMessagingService() {
private val serviceScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
override fun onNewToken(token: String) {
super.onNewToken(token)
Log.d("FCM", "New Firebase token: $token")
serviceScope.launch {
try {
SdkPushExpress.setFirebaseToken(token)
Log.d("FCM", "Firebase token successfully set")
} catch (e: Exception) {
Log.e("FCM", "Error setting Firebase token: ${e.message}", e)
}
}
}
override fun onMessageReceived(remoteMessage: RemoteMessage) {
super.onMessageReceived(remoteMessage)
Log.d("FCM", "Message received from: ${remoteMessage.from}")
if (remoteMessage.data.isNotEmpty()) {
Log.d("FCM", "Message data: ${remoteMessage.data}")
try {
SdkPushExpress.showNotification(remoteMessage.data)
} catch (e: Exception) {
Log.e("FCM", "Error showing notification: ${e.message}", e)
}
}
remoteMessage.notification?.let { notification ->
Log.d("FCM", "Notification title: ${notification.title}")
Log.d("FCM", "Notification body: ${notification.body}")
}
}
override fun onDestroy() {
super.onDestroy()
serviceScope.cancel()
}
}Add code SDK Initialization in MainActivity
package com.com.yourpackage
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.ui.unit.dp
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.core.content.ContextCompat
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import com.google.firebase.messaging.FirebaseMessaging
import com.pushexpress.sdk.main.SdkPushExpress
const val PUSHEXPRESS_APP_ID = "YOUR_APP_ID" // Replace with your App ID
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Log.d("Myapp", "onCreate called")
askNotificationPermission()
if (savedInstanceState == null) {
getFirebaseTokenAndActivate()
}
enableEdgeToEdge()
setContent {
KotlinBug3Theme {
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
Greeting(
name = "Android",
modifier = Modifier.padding(innerPadding),
onLogoutClick = { logout() },
onLoginClick = { login() }
)
}
}
}
handleIntent(intent)
}
private fun getFirebaseTokenAndActivate() {
FirebaseMessaging.getInstance().token.addOnCompleteListener { task ->
if (task.isSuccessful) {
val token = task.result
Log.d("MyApp", "Firebase token: $token")
CoroutineScope(Dispatchers.IO).launch {
SdkPushExpress.setFirebaseToken(token)
initializeSdk()
Log.d("MyApp", "SDK activated with token")
}
} else {
Log.e("MyApp", "Failed to get Firebase token", task.exception)
}
}
}
private fun initializeSdk() {
lifecycleScope.launch {
try {
SdkPushExpress.initialize(PUSHEXPRESS_APP_ID)
SdkPushExpress.setExternalId("some_external_id")
SdkPushExpress.activate()
Log.d("Myapp", "App Instance Token: ${SdkPushExpress.getInstanceToken()}")
Log.d("Myapp", "App External ID: ${SdkPushExpress.getExternalId()}")
} catch (e: Exception) {
Log.e("Myapp", "SDK initialization failed", e)
}
}
}
private val notificationPermissionLauncher = registerForActivityResult(
ActivityResultContracts.RequestPermission()
) { isGranted: Boolean ->
if (isGranted) {
Toast.makeText(this, "Notifications permission granted", Toast.LENGTH_SHORT).show()
} else {
Toast.makeText(
this,
"FCM can't post notifications without POST_NOTIFICATIONS permission",
Toast.LENGTH_LONG
).show()
}
}
private fun askNotificationPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
if (ContextCompat.checkSelfPermission(
this,
android.Manifest.permission.POST_NOTIFICATIONS
) != PackageManager.PERMISSION_GRANTED
) {
notificationPermissionLauncher.launch(
android.Manifest.permission.POST_NOTIFICATIONS
)
}
}
}Login logout functionality
To create different accounts on the same device, use the sdk activation and decoding functionality. To log out of your account, use SdkPushExpress.deactivate(). To log in to another account, create a new setExternalId - SdkPushExpress.setExternalId("new_ext_id") run SdkPushExpress.activate(). Example of the implementation of login logout functions in MainActivity.kt:
private fun logout() {
lifecycleScope.launch {
try {
SdkPushExpress.deactivate()
Toast.makeText(this@MainActivity, "Logout initiated", Toast.LENGTH_SHORT).show()
Log.d("Myapp", "Deactivate called - logout initiated")
} catch (e: Exception) {
Log.e("Myapp", "Logout failed", e)
}
}
}
private fun login() {
lifecycleScope.launch {
try {
SdkPushExpress.deactivate()
val timestamp = System.currentTimeMillis()
SdkPushExpress.setExternalId("ext_id_$timestamp")
Log.d("Myapp", "App External ID: ${SdkPushExpress.getExternalId()}")
SdkPushExpress.activate()
Toast.makeText(this@MainActivity, "Login initiated", Toast.LENGTH_SHORT).show()
Log.d("Myapp", "Activate called - login initiated")
} catch (e: Exception) {
Log.e("Myapp", "Login failed", e)
}
}
}Example processing links from push notifications in MainActivity.kt
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
Log.d("Myapp", "onNewIntent called with: ${intent.data}")
setIntent(intent)
handleIntent(intent)
}
private fun handleIntent(intent: Intent?) {
if (intent == null) {
Log.d("Myapp", "handleIntent: intent is null")
showMainScreen()
return
}
Log.d("Myapp", "handleIntent called, action: ${intent.action}, data: ${intent.data}")
intent.extras?.let { bundle ->
Log.d("Myapp", "Intent extras:")
for (key in bundle.keySet()) {
Log.d("Myapp", " $key: ${bundle.get(key)}")
}
}
try {
when {
// Deep link from URI
intent.action == Intent.ACTION_VIEW && intent.data != null -> {
val uri = intent.data!!
Log.d("Myapp", "Deep Link received: $uri")
// Checking the validity of the URI
if (isValidUri(uri)) {
processDeepLink(uri)
} else {
Log.w("Myapp", "Invalid URI received: $uri")
Toast.makeText(this, "Invalid deep was received link: $uri", Toast.LENGTH_LONG).show()
showMainScreen()
}
return
}
// Deep link from extras
intent.hasExtra("deep_link") -> {
val deepLink = intent.getStringExtra("deep_link")
Log.d("Myapp", "Deep Link from extra: $deepLink")
deepLink?.let {
parseAndProcessDeepLink(it)
}
return
}
// Push notification data
intent.hasExtra("url") || intent.hasExtra("link") -> {
val url = intent.getStringExtra("url") ?: intent.getStringExtra("link")
Log.d("Myapp", "URL from push: $url")
url?.let {
parseAndProcessDeepLink(it)
}
return
}
}
} catch (e: Exception) {
Log.e("Myapp", "Error handling intent", e)
Toast.makeText(this, "Link processing error: ${e.message}", Toast.LENGTH_SHORT).show()
}
// Normal application launch
showMainScreen()
}
private fun isValidUri(uri: Uri): Boolean {
val scheme = uri.scheme
// Check that the URI has a valid scheme
if (scheme.isNullOrBlank()) {
return false
}
// Check that the scheme is supported
val supportedSchemes = listOf("http", "https", "myapp", "yourapp")
return scheme.lowercase() in supportedSchemes
}
private fun parseAndProcessDeepLink(urlString: String) {
try {
// Check that the string is not empty
if (urlString.isBlank()) {
Log.w("Myapp", "Empty URL string")
Toast.makeText(this, "Empty link received", Toast.LENGTH_SHORT).show()
return
}
// Parse URI
val uri = Uri.parse(urlString)
// Check that URI has a valid scheme
val scheme = uri.scheme
if (scheme.isNullOrBlank()) {
Log.w("Myapp", "Invalid URL: no scheme found in '$urlString'")
Toast.makeText(this, "Invalid link format: scheme is missing (http://, https://, myapp://, etc.)", Toast.LENGTH_LONG).show()
showMainScreen()
return
}
// Check that the scheme is supported
val supportedSchemes = listOf("http", "https", "myapp", "yourapp")
if (scheme.lowercase() !in supportedSchemes) {
Log.w("Myapp", "Unsupported URL scheme: $scheme in '$urlString'")
Toast.makeText(this, "Unsupported scheme: $scheme", Toast.LENGTH_SHORT).show()
showMainScreen()
return
}
// If everything is valid, process the deep link
processDeepLink(uri)
} catch (e: Exception) {
Log.e("Myapp", "Error parsing URL: '$urlString'", e)
Toast.makeText(this, "Link parsing error: ${e.message}", Toast.LENGTH_LONG).show()
showMainScreen()
}
}
private fun processDeepLink(uri: Uri) {
Log.d("Myapp", "Processing deep link: $uri")
val scheme = uri.scheme?.lowercase()
val host = uri.host?.lowercase()
// Check if it's an external web URL (not our internal domains)
if ((scheme == "http" || scheme == "https") &&
host != null &&
host != "push.express" &&
host != "yourdomain.com") {
// External URL - redirect to browser
Log.d("Myapp", "Redirecting external URL to browser: $uri")
try {
val browserIntent = Intent(Intent.ACTION_VIEW, uri).apply {
// Remove package restriction to allow system to choose browser
setPackage(null)
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}
startActivity(browserIntent)
finish() // Close MainActivity
return
} catch (e: Exception) {
Log.e("Myapp", "Failed to open browser for: $uri", e)
Toast.makeText(this, "Unable to open link", Toast.LENGTH_SHORT).show()
}
}
// Internal deep link - handle within app
Toast.makeText(this, "Deep link: $uri", Toast.LENGTH_LONG).show()
// Add your deep link processing logic here
// For example, navigation to a specific screen
}
private fun showMainScreen() {
Log.d("Myapp", "Show main screen")
}Example MainActivity.kt
package com.example.kotlinbug3
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.ui.unit.dp
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.core.content.ContextCompat
import com.example.kotlinbug3.ui.theme.KotlinBug3Theme
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import com.google.firebase.messaging.FirebaseMessaging
import com.pushexpress.sdk.main.SdkPushExpress
const val PUSHEXPRESS_APP_ID = "43766"
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Log.d("Myapp", "onCreate called")
askNotificationPermission()
if (savedInstanceState == null) {
getFirebaseTokenAndActivate()
}
enableEdgeToEdge()
setContent {
KotlinBug3Theme {
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
Greeting(
name = "Android",
modifier = Modifier.padding(innerPadding),
onLogoutClick = { logout() },
onLoginClick = { login() }
)
}
}
}
handleIntent(intent)
}
private fun getFirebaseTokenAndActivate() {
FirebaseMessaging.getInstance().token.addOnCompleteListener { task ->
if (task.isSuccessful) {
val token = task.result
Log.d("MyApp", "Firebase token: $token")
CoroutineScope(Dispatchers.IO).launch {
SdkPushExpress.setFirebaseToken(token)
initializeSdk()
Log.d("MyApp", "SDK activated with token")
}
} else {
Log.e("MyApp", "Failed to get Firebase token", task.exception)
}
}
}
private fun initializeSdk() {
lifecycleScope.launch {
try {
SdkPushExpress.initialize(PUSHEXPRESS_APP_ID)
SdkPushExpress.setExternalId("some_external_id")
SdkPushExpress.activate()
Log.d("Myapp", "App Instance Token: ${SdkPushExpress.getInstanceToken()}")
Log.d("Myapp", "App External ID: ${SdkPushExpress.getExternalId()}")
} catch (e: Exception) {
Log.e("Myapp", "SDK initialization failed", e)
}
}
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
Log.d("Myapp", "onNewIntent called with: ${intent.data}")
setIntent(intent)
handleIntent(intent)
}
private fun handleIntent(intent: Intent?) {
if (intent == null) {
Log.d("Myapp", "handleIntent: intent is null")
showMainScreen()
return
}
Log.d("Myapp", "handleIntent called, action: ${intent.action}, data: ${intent.data}")
intent.extras?.let { bundle ->
Log.d("Myapp", "Intent extras:")
for (key in bundle.keySet()) {
Log.d("Myapp", " $key: ${bundle.get(key)}")
}
}
try {
when {
// Deep link from URI
intent.action == Intent.ACTION_VIEW && intent.data != null -> {
val uri = intent.data!!
Log.d("Myapp", "Deep Link received: $uri")
// Checking the validity of the URI
if (isValidUri(uri)) {
processDeepLink(uri)
} else {
Log.w("Myapp", "Invalid URI received: $uri")
Toast.makeText(this, "Invalid deep was received link: $uri", Toast.LENGTH_LONG).show()
showMainScreen()
}
return
}
// Deep link from extras
intent.hasExtra("deep_link") -> {
val deepLink = intent.getStringExtra("deep_link")
Log.d("Myapp", "Deep Link from extra: $deepLink")
deepLink?.let {
parseAndProcessDeepLink(it)
}
return
}
// Push notification data
intent.hasExtra("url") || intent.hasExtra("link") -> {
val url = intent.getStringExtra("url") ?: intent.getStringExtra("link")
Log.d("Myapp", "URL from push: $url")
url?.let {
parseAndProcessDeepLink(it)
}
return
}
}
} catch (e: Exception) {
Log.e("Myapp", "Error handling intent", e)
Toast.makeText(this, "Link processing error: ${e.message}", Toast.LENGTH_SHORT).show()
}
// Normal application launch
showMainScreen()
}
private fun isValidUri(uri: Uri): Boolean {
val scheme = uri.scheme
// Check that the URI has a valid scheme
if (scheme.isNullOrBlank()) {
return false
}
// Check that the scheme is supported
val supportedSchemes = listOf("http", "https", "myapp", "yourapp")
return scheme.lowercase() in supportedSchemes
}
private fun parseAndProcessDeepLink(urlString: String) {
try {
// Check that the string is not empty
if (urlString.isBlank()) {
Log.w("Myapp", "Empty URL string")
Toast.makeText(this, "Empty link received", Toast.LENGTH_SHORT).show()
return
}
// Parse URI
val uri = Uri.parse(urlString)
// Check that URI has a valid scheme
val scheme = uri.scheme
if (scheme.isNullOrBlank()) {
Log.w("Myapp", "Invalid URL: no scheme found in '$urlString'")
Toast.makeText(this, "Invalid link format: scheme is missing (http://, https://, myapp://, etc.)", Toast.LENGTH_LONG).show()
showMainScreen()
return
}
// Check that the scheme is supported
val supportedSchemes = listOf("http", "https", "myapp", "yourapp")
if (scheme.lowercase() !in supportedSchemes) {
Log.w("Myapp", "Unsupported URL scheme: $scheme in '$urlString'")
Toast.makeText(this, "Unsupported scheme: $scheme", Toast.LENGTH_SHORT).show()
showMainScreen()
return
}
// If everything is valid, process the deep link
processDeepLink(uri)
} catch (e: Exception) {
Log.e("Myapp", "Error parsing URL: '$urlString'", e)
Toast.makeText(this, "Link parsing error: ${e.message}", Toast.LENGTH_LONG).show()
showMainScreen()
}
}
private fun processDeepLink(uri: Uri) {
Log.d("Myapp", "Processing deep link: $uri")
val scheme = uri.scheme?.lowercase()
val host = uri.host?.lowercase()
// Check if it's an external web URL (not our internal domains)
if ((scheme == "http" || scheme == "https") &&
host != null &&
host != "push.express" &&
host != "yourdomain.com") {
// External URL - redirect to browser
Log.d("Myapp", "Redirecting external URL to browser: $uri")
try {
val browserIntent = Intent(Intent.ACTION_VIEW, uri).apply {
// Remove package restriction to allow system to choose browser
setPackage(null)
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}
startActivity(browserIntent)
finish() // Close MainActivity
return
} catch (e: Exception) {
Log.e("Myapp", "Failed to open browser for: $uri", e)
Toast.makeText(this, "Unable to open link", Toast.LENGTH_SHORT).show()
}
}
// Internal deep link - handle within app
Toast.makeText(this, "Deep link: $uri", Toast.LENGTH_LONG).show()
// Add your deep link processing logic here
// For example, navigation to a specific screen
}
private fun showMainScreen() {
Log.d("Myapp", "Show main screen")
}
private val notificationPermissionLauncher = registerForActivityResult(
ActivityResultContracts.RequestPermission()
) { isGranted: Boolean ->
if (isGranted) {
Toast.makeText(this, "Notifications permission granted", Toast.LENGTH_SHORT).show()
} else {
Toast.makeText(
this,
"FCM can't post notifications without POST_NOTIFICATIONS permission",
Toast.LENGTH_LONG
).show()
}
}
private fun askNotificationPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
if (ContextCompat.checkSelfPermission(
this,
android.Manifest.permission.POST_NOTIFICATIONS
) != PackageManager.PERMISSION_GRANTED
) {
notificationPermissionLauncher.launch(
android.Manifest.permission.POST_NOTIFICATIONS
)
}
}
}
private fun logout() {
lifecycleScope.launch {
try {
SdkPushExpress.deactivate()
Toast.makeText(this@MainActivity, "Logout initiated", Toast.LENGTH_SHORT).show()
Log.d("Myapp", "Deactivate called - logout initiated")
} catch (e: Exception) {
Log.e("Myapp", "Logout failed", e)
}
}
}
private fun login() {
lifecycleScope.launch {
try {
SdkPushExpress.deactivate()
val timestamp = System.currentTimeMillis()
SdkPushExpress.setExternalId("ext_id_$timestamp")
Log.d("Myapp", "App External ID: ${SdkPushExpress.getExternalId()}")
SdkPushExpress.activate()
Toast.makeText(this@MainActivity, "Login initiated", Toast.LENGTH_SHORT).show()
Log.d("Myapp", "Activate called - login initiated")
} catch (e: Exception) {
Log.e("Myapp", "Login failed", e)
}
}
}
}
@Composable
fun Greeting(
name: String,
modifier: Modifier = Modifier,
onLogoutClick: () -> Unit = {},
onLoginClick: () -> Unit = {}
) {
Column(modifier = modifier.padding(16.dp)) {
Text(
text = "Hello $name!",
modifier = modifier
)
Button(
onClick = onLogoutClick,
modifier = Modifier.padding(top = 16.dp)
) {
Text("Logout")
}
Button(
onClick = onLoginClick,
modifier = Modifier.padding(top = 16.dp)
) {
Text("Login")
}
}
}
@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
KotlinBug3Theme {
Greeting("Android")
}
}Last updated