Display User Location
Learn how to show the user's current location on the map with a blue dot indicator that updates as they move.
What You'll Build
An app that displays the user's location on the map with:
- Blue dot showing current position
- Accuracy circle indicating GPS precision (automatic)
- Automatic location updates as the user moves
- Arrow indicator when user is moving (automatic)
Time to complete: ~5 minutes (iOS), ~20 minutes (Android)
Prerequisites
- Completed Your First Map tutorial
- Basic understanding of location permissions on iOS/Android
Choose Your Platform
📱 iOS (Swift)
Step 1: Request Location Permissions
Add permission descriptions to your Info.plist
:
<key>NSLocationWhenInUseUsageDescription</key>
<string>We need your location to show you on the map</string>
For iOS 14+, also add:
<key>NSLocationWhenInUseUsageDescription</key>
<string>We need your location to show you on the map</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>We need your location for navigation features</string>
Step 2: Request Location Permission and Enable Display
GLMapView handles location tracking internally. You only need to request permission:
import UIKit
import GLMap
import GLMapSwift
import CoreLocation
class ViewController: UIViewController {
var mapView: GLMapView!
override func viewDidLoad() {
super.viewDidLoad()
// Setup map view (from previous tutorial)
mapView = GLMapView(frame: view.bounds)
mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
view.addSubview(mapView)
// Request location permission
requestLocationPermission()
// Enable user location display
mapView.showUserLocation = true
}
func requestLocationPermission() {
let status = CLLocationManager.authorizationStatus()
if status == .notDetermined {
// Create a temporary location manager to request permission
let locationManager = CLLocationManager()
locationManager.requestWhenInUseAuthorization()
}
}
}
That's it! GLMapView automatically:
- Creates its own internal location manager
- Starts location updates when
showUserLocation = true
- Displays blue dot with accuracy circle
- Shows arrow indicator when moving
Complete Code
import UIKit
import GLMap
import GLMapSwift
import CoreLocation
class ViewController: UIViewController {
var mapView: GLMapView!
override func viewDidLoad() {
super.viewDidLoad()
// Setup map view
mapView = GLMapView(frame: view.bounds)
mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
view.addSubview(mapView)
// Request permission
if CLLocationManager.authorizationStatus() == .notDetermined {
CLLocationManager().requestWhenInUseAuthorization()
}
// Enable user location - GLMapView handles everything else
mapView.showUserLocation = true
}
}
Run Your App
Build and run. When prompted, allow location access. The map should show a blue dot at your current location!
🤖 Android (Kotlin)
Note: Android API will be simplified in a future release to match iOS simplicity. Currently, displaying user location with a blue dot and accuracy circle requires manual implementation using GLMapImage
and GLMapVectorLayer
.
Here's the complete helper class from our demo app:
package com.example.myapp
import android.content.res.AssetManager
import android.location.Location
import globus.glmap.*
import kotlin.math.cos
import kotlin.math.sin
class CurLocationHelper(private val renderer: GLMapViewRenderer) {
private var userMovementImage: GLMapImage
private var userLocationImage: GLMapImage
private var accuracyCircle: GLMapVectorLayer
private var lastLocation: Location? = null
init {
val manager = renderer.attachedView.context.assets
userLocationImage = createImage(manager, "circle_new.svg")
userMovementImage = createImage(manager, "arrow_new.svg")
accuracyCircle = createAccuracyCircle()
}
private fun createImage(manager: AssetManager, filename: String): GLMapImage {
val image = SVGRender.render(
manager,
filename,
SVGRender.transform(renderer.screenScale.toDouble())
) ?: throw IllegalArgumentException("SVGRender can't render image")
return GLMapImage(100).apply {
setBitmap(image)
isHidden = true
setOffset(image.width / 2, image.height / 2)
renderer.add(this)
image.recycle()
}
}
private fun createAccuracyCircle(): GLMapVectorLayer {
val points = Array(100) {
val f = 2 * Math.PI * it / 100
MapPoint(sin(f) * 2048, cos(f) * 2048)
}
val circleStyle = GLMapVectorCascadeStyle.createStyle(
"area{layer:100; width:1pt; fill-color:#3D99FA26; color:#3D99FA26;}"
)!!
val circle = GLMapVectorObject.createPolygon(arrayOf(points), null)
return GLMapVectorLayer(99).apply {
setTransformMode(GLMapDrawable.TransformMode.Custom)
setVectorObject(circle, circleStyle, null)
renderer.add(this)
}
}
fun onLocationChanged(location: Location) {
val position = MapPoint.CreateFromGeoCoordinates(location.latitude, location.longitude)
// Accuracy radius
val r = renderer.convertMetersToInternal(location.accuracy.toDouble()).toFloat()
// Set initial position
if (lastLocation == null) {
lastLocation = location
userMovementImage.position = position
userLocationImage.position = position
if (location.hasBearing()) userLocationImage.angle = -location.bearing
accuracyCircle.position = position
accuracyCircle.scale = r / 2048.0f.toDouble()
}
// Select what image to display
if (location.hasBearing()) {
userMovementImage.isHidden = false
userLocationImage.isHidden = true
} else {
userLocationImage.isHidden = false
userMovementImage.isHidden = true
}
// Animate position updates
renderer.animate {
it.setTransition(GLMapAnimation.Linear)
it.setDuration(1.0)
userMovementImage.position = position
userLocationImage.position = position
accuracyCircle.position = position
accuracyCircle.scale = r / 2048.0f.toDouble()
if (location.hasBearing()) userLocationImage.angle = -location.bearing
}
}
}
Usage in Activity
import android.Manifest
import android.content.pm.PackageManager
import android.location.Location
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import com.google.android.gms.location.*
import globus.glmap.GLMapView
class MainActivity : AppCompatActivity() {
private lateinit var mapView: GLMapView
private lateinit var fusedLocationClient: FusedLocationProviderClient
private lateinit var locationHelper: CurLocationHelper
private lateinit var locationCallback: LocationCallback
companion object {
private const val LOCATION_PERMISSION_REQUEST_CODE = 1
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
mapView = findViewById(R.id.map_view)
// Create location helper
locationHelper = CurLocationHelper(mapView.renderer)
// Setup location updates
fusedLocationClient = LocationServices.getFusedLocationProviderClient(this)
checkLocationPermission()
}
private fun checkLocationPermission() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED
) {
ActivityCompat.requestPermissions(
this,
arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
LOCATION_PERMISSION_REQUEST_CODE
)
} else {
startLocationUpdates()
}
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == LOCATION_PERMISSION_REQUEST_CODE) {
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
startLocationUpdates()
}
}
}
private fun startLocationUpdates() {
val locationRequest = LocationRequest.Builder(
Priority.PRIORITY_HIGH_ACCURACY,
1000
).build()
locationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult) {
locationResult.lastLocation?.let { location ->
locationHelper.onLocationChanged(location)
}
}
}
if (ActivityCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_FINE_LOCATION
) == PackageManager.PERMISSION_GRANTED
) {
fusedLocationClient.requestLocationUpdates(
locationRequest,
locationCallback,
mainLooper
)
}
}
override fun onDestroy() {
super.onDestroy()
fusedLocationClient.removeLocationUpdates(locationCallback)
}
}
Required Assets
You'll need two SVG icons in your assets
folder:
circle_new.svg
- Static location dotarrow_new.svg
- Movement arrow
See the demo app assets for examples.
Permissions in AndroidManifest.xml
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
Add Google Play Services
In your app's build.gradle
:
dependencies {
implementation 'com.google.android.gms:play-services-location:21.0.1'
}
Understanding the Code
Location Permissions
Both platforms require runtime permissions for location access:
- iOS: Add descriptions to
Info.plist
and request viaCLLocationManager
- Android: Add to manifest and request at runtime via
ActivityCompat
Built-in User Location Support
iOS: GLMapView creates its own internal CLLocationManager
and handles everything automatically:
// iOS - Just enable, GLMapView does the rest
mapView.showUserLocation = true
This automatically:
- Creates location manager
- Requests location updates
- Displays blue dot with accuracy circle
- Shows arrow indicator when moving
Android: Currently requires manual implementation using GLMapImage
and GLMapVectorLayer
(shown in the code above). The API will be simplified in a future release to match iOS simplicity.
For location updates, use FusedLocationProviderClient
:
- More battery efficient than direct GPS
- Combines GPS, Wi-Fi, and cell tower data
- Request with priority (HIGH_ACCURACY, BALANCED_POWER_ACCURACY, etc.)
When to Create Your Own Location Manager (iOS)
The simple approach above works for most apps. Create your own CLLocationManager
only if you need:
- Custom update frequency or accuracy
- Background location updates
- Custom accuracy circles or location markers
- Access to raw location data for other purposes
See the MapViewWithUserLocation demo for an advanced example with custom accuracy circles.
Advanced: Custom User Location Icon
You can customize the user location marker:
iOS - Custom Icons
// Load custom SVG icons
if let locationImagePath = Bundle.main.path(forResource: "custom_dot", ofType: "svg"),
let locationImage = GLMapVectorImageFactory.shared.image(fromSvg: locationImagePath),
let movementImagePath = Bundle.main.path(forResource: "custom_arrow", ofType: "svg"),
let movementImage = GLMapVectorImageFactory.shared.image(fromSvg: movementImagePath) {
mapView.setUserLocationImage(locationImage, movementImage: movementImage)
}
Android - Custom Icons
// Use GLMapImage for custom user location
val locationImage = GLMapImage(100)
val bitmap = SVGRender.render(assets, "custom_dot.svg",
SVGRender.transform(renderer.screenScale))
locationImage.setBitmap(bitmap)
locationImage.setPosition(position)
mapView.renderer.add(locationImage)
Troubleshooting
No location displayed:
- Check permissions are granted
- Ensure device location services are enabled
- Try running on a physical device (simulator may not have location)
iOS: Permission dialog doesn't appear:
- Verify
Info.plist
has location usage description - Check if permission was previously denied (reset in Settings → Privacy → Location)
Android: Location updates slow or inaccurate:
- Check priority level (
PRIORITY_HIGH_ACCURACY
for best GPS) - Increase update interval if battery is a concern
- Ensure Google Play Services is installed
App crashes when requesting location:
- iOS: Verify
showUserLocation
is set after map view is fully initialized - Android: Check permissions before calling
requestLocationUpdates()
What's Next?
Now that you can display user location, try:
- Add Markers – Display points of interest
Related Resources
- Demo: MapViewWithUserLocation – Advanced iOS example with custom accuracy circles
- Demo: CurLocationHelper (Kotlin) – Android location helper (shown above)
- Demo: CurLocationHelper (Java) – Java version
- CLLocationManager Documentation – iOS location services
- FusedLocationProviderClient – Android location API