-
-
Save harryhan24/53041cd74401e7dd92e5f37abd11c699 to your computer and use it in GitHub Desktop.
Firebase push handling
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> | |
<manifest xmlns:android="http://schemas.android.com/apk/res/android" | |
xmlns:tools="http://schemas.android.com/tools" | |
package="..."> | |
<uses-permission android:name="android.permission.INTERNET" /> | |
<application | |
android:name="..." | |
android:allowBackup="false" | |
android:icon="@mipmap/ic_launcher" | |
android:label="@string/application_label" | |
android:largeHeap="true" | |
android:networkSecurityConfig="@xml/network_security_config" | |
android:roundIcon="@mipmap/ic_launcher" | |
android:supportsRtl="true" | |
android:theme="@style/AppTheme" | |
android:usesCleartextTraffic="true" | |
tools:ignore="GoogleAppIndexingWarning,UnusedAttribute"> | |
<!-- Standard icon for push notification --> | |
<meta-data | |
android:name="com.google.firebase.messaging.default_notification_icon" | |
android:resource="@drawable/ic_push_white_24" /> | |
<!-- Standard icon color for push notification --> | |
<meta-data | |
android:name="com.google.firebase.messaging.default_notification_color" | |
android:resource="@color/colorAccent" /> | |
<!-- Standard notification channel for push notification --> | |
<meta-data | |
android:name="com.google.firebase.messaging.default_notification_channel_id" | |
android:value="@string/notification_channel" /> | |
<service | |
android:name=".FcmService" | |
android:enabled="true" | |
android:exported="true" | |
android:permission="false"> | |
<intent-filter> | |
<action android:name="com.google.firebase.MESSAGING_EVENT" /> | |
</intent-filter> | |
</service> | |
</application> | |
</manifest> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
object FcmChannelHandler { | |
@RequiresApi(Build.VERSION_CODES.O) | |
fun initBroadcastChannel(context: Context) = | |
NotificationChannel( | |
BROADCAST_CHANNEL_ID, | |
context.getString(R.string.push_notifications_category_broadcast_title), | |
NotificationManager.IMPORTANCE_HIGH | |
).apply { | |
description = | |
context.getString(R.string.push_notifications_category_broadcast_description) | |
enableLights(true) | |
lightColor = Color.YELLOW | |
enableVibration(true) | |
setShowBadge(true) | |
} | |
@RequiresApi(Build.VERSION_CODES.O) | |
fun initTenantChannel(context: Context) = | |
NotificationChannel( | |
TENANT_CHANNEL_ID, | |
context.getString(R.string.push_notifications_category_tenant_title), | |
NotificationManager.IMPORTANCE_HIGH | |
).apply { | |
description = context.getString(R.string.push_notifications_category_tenant_description) | |
enableLights(true) | |
lightColor = Color.YELLOW | |
enableVibration(true) | |
setShowBadge(true) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
object FcmConstants { | |
const val TENANT_PREFIX = "android_tenant_" | |
const val DEBUG_POSTFIX = "_debug" | |
const val BROADCAST_CHANNEL_ID = "BROADCAST_CHANNEL_ID" | |
const val TENANT_CHANNEL_ID = "TENANT_CHANNEL_ID" | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class FcmService : FirebaseMessagingService() { | |
@Suppress("UNUSED") | |
companion object { | |
const val TAG = "FcmService" | |
fun retrieveFcmRegistrationToken() { | |
FirebaseInstanceId.getInstance().instanceId | |
.addOnCompleteListener { task -> | |
if (task.isSuccessful && task.result?.token != null) { | |
SharedPreferencesProvider.putFcmToken(task.result!!.token) | |
log("PUSH Fcm getInstanceId successful, ${task.result!!.token}") | |
} else { | |
log("PUSH Fcm getInstanceId failed, ${task.exception}") | |
} | |
} | |
} | |
} | |
override fun onMessageReceived(p0: RemoteMessage) { | |
log("PUSH Received FCM From: ${p0.from}") | |
log("PUSH Message contains data: ${p0.data}") | |
log("PUSH Message contains notification : ${p0.notification?.body}, ${p0.notification?.title}") | |
NotificationProvider.notificator.receiveMessage(p0) | |
} | |
override fun onNewToken(p0: String) { | |
log("PUSH Refreshed token: $p0") | |
SharedPreferencesProvider.putFcmToken(p0) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
object FcmTopicHandler { | |
fun getTenantTopic(tenantId: String) = "${TENANT_PREFIX}$tenantId" | |
fun getBroadcastTopic() = "android_broadcast" | |
fun subscribeToTopic(topic: String) { | |
//подписываемся на оба топика, отображаем только подходящий сборке | |
try { | |
FirebaseMessaging.getInstance().subscribeToTopic(topic) | |
.addOnCompleteListener { task -> | |
if (!task.isSuccessful) { | |
Logger.log("PUSH subscribe unsuccessful, topic $topic") | |
} else { | |
Logger.log("PUSH subscribe successful, topic $topic, task $task") | |
} | |
} | |
FirebaseMessaging.getInstance().subscribeToTopic("$topic${DEBUG_POSTFIX}") | |
.addOnCompleteListener { task -> | |
if (!task.isSuccessful) { | |
Logger.log("PUSH subscribe unsuccessful, topic $topic${DEBUG_POSTFIX}") | |
} else { | |
Logger.log("PUSH subscribe successful, topic $topic${DEBUG_POSTFIX}, task $task") | |
} | |
} | |
} catch (e: IllegalArgumentException) { | |
Logger.log("forbidden symbols in topic name") | |
} | |
} | |
fun unsubscribeFromTopic(topic: String) { | |
FirebaseMessaging.getInstance().unsubscribeFromTopic(topic) | |
Logger.log("topic $topic") | |
FirebaseMessaging.getInstance().unsubscribeFromTopic("$topic${DEBUG_POSTFIX}") | |
Logger.log("topic $topic${DEBUG_POSTFIX}") | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Notificator( | |
private val context: Context, | |
private val splashActivityClass: Class<*> | |
) : INotificationProvider { | |
companion object { | |
private const val KEY_TITLE = "title" | |
private const val KEY_BODY = "body" | |
private const val KEY_ID = "id" | |
private const val KEY_TENANT = "tenant" | |
private const val KEY_KIND = "notification_kind" | |
} | |
private var messageId = 0 | |
private val notificationManager = | |
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager | |
/**создаем каналы для нотификаций*/ | |
init { | |
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { | |
notificationManager.createNotificationChannel(initBroadcastChannel(context)) | |
notificationManager.createNotificationChannel(initTenantChannel(context)) | |
} | |
} | |
override fun getTenantTopic(tenantId: String) = FcmTopicHandler.getTenantTopic(tenantId) | |
override fun getBroadcastTopic() = FcmTopicHandler.getBroadcastTopic() | |
override fun subscribeToTopic(topic: String) = FcmTopicHandler.subscribeToTopic(topic) | |
override fun unsubscribeFromTopic(topic: String) = FcmTopicHandler.unsubscribeFromTopic(topic) | |
override fun receiveMessage(message: RemoteMessage) { | |
/**показываем пуш, | |
* если мы авторизованы | |
* если тест или продакт топик совпадает с тест или продакт версией апи*/ | |
if (SharedPreferencesProvider.getIsAuthorized()) { | |
if (message.from?.contains(DEBUG_POSTFIX) == true) { | |
if (CURRENT_BASE_URL == AppConstants.TEST_BASE_URL) preparePush(message) | |
else log("PUSH : product api, but test push, skip") | |
} else { | |
if (CURRENT_BASE_URL == AppConstants.PRODUCT_BASE_URL) preparePush(message) | |
else log("PUSH: test api, but product push, skip") | |
} | |
} else log("PUSH skipped: user not logged in") | |
} | |
private fun preparePush(message: RemoteMessage) { | |
val tenantId = message.from.orEmpty() | |
val tenantTitle = message.data[KEY_TENANT].orEmpty() | |
val messageTitle = message.data[KEY_TITLE].orEmpty() | |
val messageBody = message.data[KEY_BODY].orEmpty() | |
val id = message.data[KEY_ID].orEmpty() | |
when (message.data[KEY_KIND].orEmpty()) { | |
FcmKind.BROADCAST -> showBroadcastNotification(tenantTitle, messageTitle, messageBody) | |
FcmKind.TENANT -> showTenantNotification(tenantTitle, messageTitle, messageBody, tenantId) | |
FcmKind.POLL -> showPollNotification(tenantTitle, messageTitle, messageBody, tenantId, id) | |
else -> {} | |
} | |
} | |
private fun showBroadcastNotification( | |
tenantTitle: String, | |
messageTitle: String, | |
messageBody: String | |
) { | |
showNotification(tenantTitle, messageTitle, messageBody, null, BROADCAST_CHANNEL_ID) | |
} | |
private fun showTenantNotification( | |
tenantTitle: String, | |
messageTitle: String, | |
messageBody: String, | |
tenantId: String | |
) { | |
val tenant = tenantId.substringAfter(TENANT_PREFIX).substringBefore(DEBUG_POSTFIX) | |
val pendingIntent = PendingIntent.getActivity( | |
context, 0, | |
Intent(context, splashActivityClass).apply { | |
putExtra(TENANT_FROM_FCM, tenant) | |
flags = Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP | |
/*Intent.FLAG_ACTIVITY_NEW_TASK */ | |
}, PendingIntent.FLAG_UPDATE_CURRENT | |
) | |
showNotification(tenantTitle, messageTitle, messageBody, pendingIntent, TENANT_CHANNEL_ID) | |
} | |
private fun showPollNotification( | |
tenantTitle: String, | |
messageTitle: String, | |
messageBody: String, | |
tenantId: String, | |
pollId: String | |
) { | |
val tenant = tenantId.substringAfter(TENANT_PREFIX).substringBefore(DEBUG_POSTFIX) | |
val pendingIntent = PendingIntent.getActivity( | |
context, 0, | |
Intent(context, splashActivityClass).apply { | |
putExtra(TENANT_FROM_FCM, tenant) | |
putExtra(KIND_FROM_FCM, FcmKind.POLL) | |
putExtra(ID_FROM_FCM, pollId) | |
flags = Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP | |
/*Intent.FLAG_ACTIVITY_NEW_TASK */ | |
}, PendingIntent.FLAG_UPDATE_CURRENT | |
) | |
showNotification(tenantTitle, messageTitle, messageBody, pendingIntent, TENANT_CHANNEL_ID) | |
} | |
private fun showNotification( | |
tenantTitle: String, | |
messageTitle: String, | |
messageBody: String, | |
intent: PendingIntent?, | |
channelId: String | |
) { | |
val notificationBuilder = | |
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { | |
NotificationCompat.Builder(context, channelId) | |
} else { | |
NotificationCompat.Builder( | |
context, | |
context.getString(R.string.notification_channel) | |
) | |
} | |
notificationBuilder | |
.setSmallIcon(R.drawable.ic_push_white_24) | |
.setLargeIcon( | |
BitmapFactory.decodeResource( | |
context.resources, | |
R.mipmap.ic_launcher | |
) | |
) | |
.setColor(ContextCompat.getColor(context, R.color.colorAccent)) | |
.setDefaults(DEFAULT_ALL) | |
.setAutoCancel(true) | |
.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)) | |
.setContentTitle(messageTitle) //+ заголовок пуша | |
.setContentText(messageBody) //+ текст пуша | |
.setSubText(tenantTitle) //+ добавит доп текст в шапку | |
.setTicker(messageTitle) //- текст в систембаре (accessibility) | |
// .setContentInfo(tenantTitle) //-добавит доп текст (справа или сверху) | |
.setStyle(NotificationCompat.BigTextStyle().bigText(messageBody)) | |
if (intent != null) { | |
notificationBuilder.setContentIntent(intent) | |
} | |
notificationManager.notify(messageId++, notificationBuilder.build()) // показываем пуш | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment