How to Build a Qibla Compass App

In Flutter: From Math to Practical App

In an increasingly connected world, mobile apps that serve cultural or spiritual needs have tremendous value. A classic example is an app that helps Muslim users find the Qibla – the direction of the Kaaba in Mecca, required for daily prayers (salat).

In this article, we’ll explore how to create a Qibla compass app using Flutter, combining device sensors and geodesic math. We’ll go through how to calculate the direction manually, show a basic implementation, and finish by recommending a production-ready package.

How Is the Qibla Direction Calculated?

To calculate the Qibla direction from anywhere in the world, you need two things:

  • Your current location (latitude and longitude)
  • The coordinates of the Kaaba: approximately 21.4225° N, 39.8262° E

The goal is to compute the initial bearing (or azimuth) from your location to Mecca, measured clockwise from true north.

Bearing Formula

θ = atan2(
  sin(Δlong) * cos(lat2),
  cos(lat1) * sin(lat2) − sin(lat1) * cos(lat2) * cos(Δlong)
)

Where:

  • lat1, long1: your location
  • lat2, long2: Kaaba’s location

All angles must be in radians. The result θ is converted to degrees and normalized between 0 and 360.

Simple Flutter Example: Qibla Compass From Scratch

Before using specialized packages, let’s go through a basic custom implementation.

1. Required Packages

dependencies:
  flutter:
    sdk: flutter
  geolocator: ^11.0.0
  flutter_compass: ^0.8.0

2. Get the User’s Location

Position position = await Geolocator.getCurrentPosition(
  desiredAccuracy: LocationAccuracy.high,
);

3. Calculate the Qibla Angle

double calculateQiblaDirection(double lat, double lon) {
  const kaabaLat = 21.4225;
  const kaabaLon = 39.8262;

  final lat1 = lat * (pi / 180);
  final lon1 = lon * (pi / 180);
  final lat2 = kaabaLat * (pi / 180);
  final lon2 = kaabaLon * (pi / 180);

  final deltaLon = lon2 - lon1;

  final x = sin(deltaLon) * cos(lat2);
  final y = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(deltaLon);

  double bearing = atan2(x, y);
  bearing = bearing * (180 / pi);
  return (bearing + 360) % 360;
}

4. Show the Compass

CompassEvent event = await FlutterCompass.events!.first;
double direction = event.heading!;

You can then display a needle or arrow pointing toward the Qibla using Transform.rotate, comparing the current heading to the Qibla bearing.

Deep Dive: Using the qiblah Package in Flutter

The qiblah package is a comprehensive tool designed to simplify the process of implementing Qibla direction in your Flutter app. It abstracts away the complexity of compass sensors, geolocation, bearing calculations, and platform-specific behavior.

1. Installation

dependencies:
  qiblah: ^2.1.0

Then run:

flutter pub get

2. Android & iOS Setup

Ensure your app has the correct permissions:

Android:

In AndroidManifest.xml:

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.BODY_SENSORS"/>

iOS:

In Info.plist:

<key>NSLocationWhenInUseUsageDescription</key>
<string>We need your location to determine the Qibla direction.</string>
<key>NSMotionUsageDescription</key>
<string>This app uses motion sensors to detect orientation.</string>

3. QiblahCompass Widget

The easiest way to show the direction to Mecca is using the built-in QiblahCompass widget:

import 'package:qiblah/qiblah.dart';

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(title: Text("Qibla Compass")),
    body: QiblahCompass(),
  );
}

4. Check Sensor Availability

The package allows you to check if the device supports sensors needed for compass navigation:

FutureBuilder(
  future: QiblahPlatform.instance.canUseSensor,
  builder: (context, snapshot) {
    if (snapshot.connectionState == ConnectionState.waiting)
      return CircularProgressIndicator();

    if (snapshot.data == true) {
      return QiblahCompass();
    } else {
      return Center(child: Text("Compass not available on this device"));
    }
  },
)

5. Custom Qibla Indicator

If you want to design your own compass instead of using the built-in UI, you can use QiblahDirection stream:

StreamBuilder<QiblahDirection>(
  stream: QiblahPlatform.instance.qiblahStream,
  builder: (context, snapshot) {
    if (!snapshot.hasData) return CircularProgressIndicator();

    final qiblahDirection = snapshot.data!;
    return Transform.rotate(
      angle: (qiblahDirection.qiblah * (pi / 180) * -1),
      child: Image.asset('assets/needle.png'),
    );
  },
)

6. Handling Permissions

The package automatically requests and handles permissions. You can also check them manually using the LocationPermission status from the geolocator package.

Summary

With qiblah, you get a reliable, customizable, and production-ready way to implement Qibla direction in your Flutter apps. Whether you prefer a quick drop-in widget or a custom design, the package has you covered.

Visit the full documentation on pub.dev/qiblah to explore all the features.