Build a Prayer Times App for Android with Kotlin
This post walks you through building a native Android prayer times app in Kotlin. You will get the user's GPS location, fetch prayer times from UmmahAPI, display them with Material Design, and schedule local notifications for each prayer.
Project Setup
Create a new Android project in Android Studio. Choose "Empty Activity", set the language to Kotlin, and set the minimum SDK to API 26 (Android 8.0). That gives you access to modern scheduling APIs without extra workarounds.
Open your build.gradle (Module: app) file and add these dependencies:
// build.gradle (Module: app)
dependencies {
// Retrofit for HTTP requests
implementation("com.squareup.retrofit2:retrofit:2.11.0")
implementation("com.squareup.retrofit2:converter-gson:2.11.0")
// Kotlin coroutines
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.1")
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.3")
// Location services
implementation("com.google.android.gms:play-services-location:21.3.0")
// Material Design 3
implementation("com.google.android.material:material:1.12.0")
}
Sync the project after saving. These are all real package names from Maven Central and Google Maven.
Permissions and Manifest
Prayer times depend on location, so you need both location permissions and the exact alarm permission for scheduling. Open AndroidManifest.xml and add:
<!-- AndroidManifest.xml -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<!-- Inside <application> tag -->
<receiver
android:name=".PrayerAlarmReceiver"
android:exported="false" />
At runtime, you must request ACCESS_FINE_LOCATION and POST_NOTIFICATIONS from the user. Android 12 and above also require you to check that the app can schedule exact alarms. Do that before setting any alarm.
Get the Device Location
Use FusedLocationProviderClient to get the last known location. This is faster than requesting a fresh GPS fix and works well for prayer times since precision to two decimal places is more than enough.
// LocationHelper.kt
import android.annotation.SuppressLint
import android.content.Context
import com.google.android.gms.location.LocationServices
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlin.coroutines.resume
data class LatLng(val lat: Double, val lng: Double)
@SuppressLint("MissingPermission")
suspend fun getLastLocation(context: Context): LatLng? {
val client = LocationServices.getFusedLocationProviderClient(context)
return suspendCancellableCoroutine { cont ->
client.lastLocation.addOnSuccessListener { location ->
if (location != null) {
cont.resume(LatLng(location.latitude, location.longitude))
} else {
cont.resume(null)
}
}.addOnFailureListener {
cont.resume(null)
}
}
}
Call this from a coroutine inside your ViewModel or Activity after the location permission is granted.
Fetch Prayer Times from UmmahAPI
The UmmahAPI prayer times endpoint takes a latitude and longitude and returns today's prayer times. Set up a Retrofit service interface for it.
// PrayerTimesService.kt
import retrofit2.http.GET
import retrofit2.http.Query
data class PrayerTimes(
val Fajr: String,
val Sunrise: String,
val Dhuhr: String,
val Asr: String,
val Maghrib: String,
val Isha: String
)
data class PrayerTimesResponse(val data: PrayerTimes)
interface PrayerTimesService {
@GET("api/prayer-times")
suspend fun getTodayTimes(
@Query("lat") lat: Double,
@Query("lng") lng: Double
): PrayerTimesResponse
}
// RetrofitClient.kt
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
object RetrofitClient {
private const val BASE_URL = "https://ummahapi.com/"
val prayerTimesService: PrayerTimesService by lazy {
Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(PrayerTimesService::class.java)
}
}
Now fetch the times from your ViewModel:
// PrayerTimesViewModel.kt
import android.app.Application
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.launch
class PrayerTimesViewModel(app: Application) : AndroidViewModel(app) {
val prayerTimes = MutableLiveData<PrayerTimes?>()
val error = MutableLiveData<String?>()
fun loadTimes(lat: Double, lng: Double) {
viewModelScope.launch {
try {
val response = RetrofitClient.prayerTimesService.getTodayTimes(lat, lng)
prayerTimes.postValue(response.data)
} catch (e: Exception) {
error.postValue(e.message)
}
}
}
}
Tip. Register for a free API key and add it as a query parameter ?key=YOUR_KEY to remove the 5,000 request rate limit. Store the key in your local.properties file and read it through BuildConfig, not hardcoded in source.
Display Times with Material Design
Use a RecyclerView with Material Design 3 cards to show each prayer and its time. First define the card layout in res/layout/item_prayer.xml:
<!-- res/layout/item_prayer.xml -->
<com.google.android.material.card.MaterialCardView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginVertical="6dp"
app:cardCornerRadius="12dp"
app:cardElevation="2dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="16dp">
<TextView
android:id="@+id/prayerName"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textAppearance="@style/TextAppearance.Material3.TitleMedium" />
<TextView
android:id="@+id/prayerTime"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/TextAppearance.Material3.BodyLarge" />
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
// PrayerAdapter.kt
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
class PrayerAdapter(private var items: List<Pair<String, String>>) :
RecyclerView.Adapter<PrayerAdapter.ViewHolder>() {
class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val name: TextView = view.findViewById(R.id.prayerName)
val time: TextView = view.findViewById(R.id.prayerTime)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.item_prayer, parent, false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.name.text = items[position].first
holder.time.text = items[position].second
}
override fun getItemCount() = items.size
fun update(newItems: List<Pair<String, String>>) {
items = newItems
notifyDataSetChanged()
}
}
In your Activity, observe the ViewModel and pass a list of name/time pairs to the adapter:
// MainActivity.kt (excerpt)
viewModel.prayerTimes.observe(this) { times ->
if (times != null) {
val items = listOf(
Pair("Fajr", times.Fajr),
Pair("Sunrise", times.Sunrise),
Pair("Dhuhr", times.Dhuhr),
Pair("Asr", times.Asr),
Pair("Maghrib", times.Maghrib),
Pair("Isha", times.Isha)
)
adapter.update(items)
schedulePrayerAlarms(times)
}
}
Schedule Prayer Notifications with AlarmManager
Parse each prayer time string into a Calendar object and set an exact alarm. The API returns times in HH:mm format, so splitting on ":" gives you the hour and minute.
// AlarmScheduler.kt
import android.app.AlarmManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import java.util.Calendar
fun schedulePrayerAlarms(context: Context, times: PrayerTimes) {
val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
val prayers = mapOf(
"Fajr" to times.Fajr,
"Dhuhr" to times.Dhuhr,
"Asr" to times.Asr,
"Maghrib" to times.Maghrib,
"Isha" to times.Isha
)
prayers.entries.forEachIndexed { index, (name, timeStr) ->
val parts = timeStr.split(":")
if (parts.size < 2) return@forEachIndexed
val hour = parts[0].toIntOrNull() ?: return@forEachIndexed
val minute = parts[1].toIntOrNull() ?: return@forEachIndexed
val calendar = Calendar.getInstance().apply {
set(Calendar.HOUR_OF_DAY, hour)
set(Calendar.MINUTE, minute)
set(Calendar.SECOND, 0)
}
// Skip if the time has already passed today
if (calendar.timeInMillis <= System.currentTimeMillis()) return@forEachIndexed
val intent = Intent(context, PrayerAlarmReceiver::class.java).apply {
putExtra("prayer_name", name)
}
val pendingIntent = PendingIntent.getBroadcast(
context,
index,
intent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
alarmManager.setExactAndAllowWhileIdle(
AlarmManager.RTC_WAKEUP,
calendar.timeInMillis,
pendingIntent
)
}
}
Now create the PrayerAlarmReceiver to show the notification when an alarm fires:
// PrayerAlarmReceiver.kt
import android.app.NotificationChannel
import android.app.NotificationManager
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import androidx.core.app.NotificationCompat
class PrayerAlarmReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val prayerName = intent.getStringExtra("prayer_name") ?: "Prayer"
val channelId = "prayer_times_channel"
val manager = context.getSystemService(Context.NOTIFICATION_SERVICE)
as NotificationManager
val channel = NotificationChannel(
channelId,
"Prayer Times",
NotificationManager.IMPORTANCE_HIGH
)
manager.createNotificationChannel(channel)
val notification = NotificationCompat.Builder(context, channelId)
.setSmallIcon(R.drawable.ic_prayer)
.setContentTitle("$prayerName Time")
.setContentText("It's time for $prayerName.")
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setAutoCancel(true)
.build()
manager.notify(prayerName.hashCode(), notification)
}
}
Tip. On Android 12 and above, call alarmManager.canScheduleExactAlarms() before setting alarms. If it returns false, send the user to Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM so they can grant permission manually.
Fetch a Full Month for Caching
Fetching times every day uses more network calls than needed. UmmahAPI lets you request a full month at once by adding month and year parameters. Store the result in a local database using Room so the app works offline.
// Fetch a full month of prayer times
// GET https://ummahapi.com/api/prayer-times?lat=21.42&lng=39.82&month=11&year=2026
@GET("api/prayer-times")
suspend fun getMonthTimes(
@Query("lat") lat: Double,
@Query("lng") lng: Double,
@Query("month") month: Int,
@Query("year") year: Int
): MonthlyPrayerTimesResponse
The response contains an array of daily prayer time objects. Store each day as a Room entity keyed by date. On app start, check if today's data is already in the database before making a network call. This also keeps you well under the rate limit. See the full API docs for the response shape.
Show Calculation Methods to the User
Different regions use different prayer time calculation methods. UmmahAPI has 23 of them. You can let the user pick from a settings screen and pass the selected method ID in your requests. Fetch the list once and store it as preferences.
// Fetch available calculation methods
// GET https://ummahapi.com/api/prayer-times/methods
@GET("api/prayer-times/methods")
suspend fun getCalculationMethods(): MethodsResponse
Display the methods in a settings screen using a ListPreference or a simple AlertDialog with a radio list. Save the chosen method ID with SharedPreferences and include it in every prayer times request as a method query parameter.
FAQ
How do I get prayer times by GPS location in Android Kotlin?
Use FusedLocationProviderClient from Google Play Services to read the device's latitude and longitude. Then pass those values to https://ummahapi.com/api/prayer-times?lat=LAT&lng=LNG. The API returns Fajr, Sunrise, Dhuhr, Asr, Maghrib, and Isha times for today.
Which HTTP library should I use for API calls in an Android Kotlin app?
Retrofit 2 with the Gson converter is the most common choice. Add com.squareup.retrofit2:retrofit:2.11.0 and com.squareup.retrofit2:converter-gson:2.11.0 to your Gradle file. It works cleanly with Kotlin suspend functions and coroutines.
How do I schedule prayer time notifications in Android?
Parse each prayer time string into a Calendar object and use AlarmManager.setExactAndAllowWhileIdle to fire a BroadcastReceiver at that exact time. Inside the receiver, build and post a notification using NotificationCompat.Builder. Fetch fresh times from UmmahAPI each day and reschedule the alarms.
Does UmmahAPI support different prayer calculation methods for Android apps?
Yes. Call https://ummahapi.com/api/prayer-times/methods to get the full list of 23 methods. Store the user's preferred method ID in SharedPreferences and append it as a method query parameter in your prayer times requests.
Start building with UmmahAPI
UmmahAPI is free to use and gives you prayer times, Quran data, Qibla direction, and more in a single API.
Read the docs