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 locationlat2,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.