Notifications with Countdown Interactive
This guide explains how to implement Notification permission handling and Exact Alarm in Storyly Android SDK using modern Activity Result APIs
Android documentation explains how to Set an exact alarm in newer versions of Android versions.
- Starting from Android 12 (API level 31), apps need the
SCHEDULE_EXACT_ALARMpermission to set reminders at specific times. - Starting from Android 13 (API level 33), apps must explicitly request the
POST_NOTIFICATIONSpermission to show reminder notifications.
Manifest Permission Decleration
You need to add the following permissions to your AndroidManifest.xml:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.yourapp">
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"/>
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
</manifest>
Initialize Permission Launchers
You need to register the launchers to handle notification requests and the system alarm settings screen using the Activity Result API in your Activity
private var pendingCountdownComponent: StoryComponent? = null
private var pendingStorylyView: StorylyView? = null
private val notificationPermissionLauncher = registerForActivityResult(
ActivityResultContracts.RequestPermission()
) { isGranted ->
if (!isGranted) {
onFinishAlarmPermissionCheck()
} else {
checkAndRequestExactAlarmPermission()
}
}
private val activityResultListener = registerForActivityResult(
ActivityResultContracts.StartActivityForResult()
) { result ->
onAlarmPermissionResult()
onFinishAlarmPermissionCheck()
}
StoryCountdownReminderAdded Event
StoryCountdownReminderAdded EventYou need to handle the reminder event in your StorylyListener. It is best practice to pause the story immediately when the permission flow begins.
binding.storylyView.storylyListener = object : StorylyListener {
override fun storylyEvent(
storylyView: StorylyView,
event: StorylyEvent,
storyGroup: StoryGroup?,
story: Story?,
storyComponent: StoryComponent?
) {
super.storylyEvent(storylyView, event, storyGroup, story, storyComponent)
if (event == StorylyEvent.StoryCountdownReminderAdded) {
checkPermissionsForCountdown(storyComponent, binding.storylyView)
}
}
}
Implement Permissions Logic
You need to add following methods orchestrate the check for both notification and exact alarm permissions.
private fun checkPermissionsForCountdown(storyComponent: StoryComponent?, storylyView: StorylyView) {
pendingStorylyView = storylyView
pendingCountdownComponent = storyComponent
// Always pause before showing system dialogs
storylyView.pauseStory()
if (!NotificationManagerCompat.from(this).areNotificationsEnabled()) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
notificationPermissionLauncher.launch(android.Manifest.permission.POST_NOTIFICATIONS)
} else {
onFinishAlarmPermissionCheck()
}
} else {
checkAndRequestExactAlarmPermission()
}
}
private fun checkAndRequestExactAlarmPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
val alarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
val canScheduleExactAlarms = alarmManager.canScheduleExactAlarms()
if (!canScheduleExactAlarms) {
val intent = Intent(Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM)
intent.data = Uri.parse("package:${packageName}")
activityResultListener.launch(intent)
} else {
onFinishAlarmPermissionCheck()
}
}
}
Check the Result
You need to trigger the Storyly Android SDKs internal reminder logic and resume the story after the user return from settings or dialog.
private fun onAlarmPermissionResult() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
val alarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
val canScheduleExactAlarms = alarmManager.canScheduleExactAlarms()
if (canScheduleExactAlarms) {
// This triggers the actual reminder scheduling inside the SDK
(pendingCountdownComponent as? StoryCountDownComponent)?.onPermission?.invoke()
}
}
}
private fun onFinishAlarmPermissionCheck() {
pendingCountdownComponent = null
pendingStorylyView?.resumeStory()
pendingStorylyView = null
}
Best Practices
- You must use
pauseStory()before showing a permission dialog andresumeStory()after it is closed for a smooth experience.- You must check
areNotificationsEnabled()before requesting alarm permissions, since reminders need notification visibility to be effective.- You must use
Build.VERSION_CODES.S(API 31) for alarms andBuild.VERSION_CODES.TIRAMISU(API 33) for notifications.- You must clear
pendingCountdownComponentandpendingStorylyViewafter handling the permission result to avoid leaks.
Updated 8 days ago
