Giới thiệu
Hướng dẫn tích hợp Google Maps SDK và Fused Location Provider để hiển thị vị trí hiện tại của người dùng trên bản đồ. Sử dụng API hiện đại (Play Services Location 21.x, Maps 18.x) thay vì code cũ deprecated.
Yêu cầu trước khi bắt đầu
- Google Cloud Project với Maps SDK for Android và Places API enabled.
- API Key với restriction (Android app + package name + SHA-1).
minSdk 24+(Android 7.0+).
Các bước thực hiện
Bước 1: Tạo dự án mới
Android Studio → File → New Project → Google Maps Activity (template có sẵn) hoặc Empty View Activity.
Bước 2: Thêm dependencies (build.gradle.kts)
dependencies {
// Google Maps
implementation("com.google.android.gms:play-services-maps:18.2.0")
// Fused Location Provider (hiện đại, thay thế LocationManager cũ)
implementation("com.google.android.gms:play-services-location:21.2.0")
// Runtime permissions handling
implementation("androidx.activity:activity-ktx:1.9.0")
implementation("androidx.fragment:fragment-ktx:1.6.2")
}
Bước 3: Cấu hình AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="https://schemas.android.com/apk/res/android"
package="com.example.maplocation">
<!-- Permissions -->
<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" />
<!-- Foreground service location (Android 10+) nếu cần track liên tục -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.MapLocation">
<!-- Google Maps API Key -->
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="@string/google_maps_key" />
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Bước 4: Thêm API Key vào res/values/strings.xml
<resources>
<string name="app_name">Map Location Demo</string>
<!-- Thay YOUR_API_KEY bằng key thật từ Google Cloud Console -->
<string name="google_maps_key" translatable="false">YOUR_API_KEY_HERE</string>
</resources>
Bước 5: Thiết kế giao diện (res/layout/activity_main.xml)
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:tools="https://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<fragment
android:id="@+id/mapFragment"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<!-- Loading indicator -->
<ProgressBar
android:id="@+id/progressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:visibility="gone" />
</FrameLayout>
Bước 6: Code chính (MainActivity.kt - Kotlin khuyến nghị)
package com.example.maplocation
import android.Manifest
import android.content.pm.PackageManager
import android.location.Location
import android.os.Bundle
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.lifecycle.lifecycleScope
import com.google.android.gms.location.FusedLocationProviderClient
import com.google.android.gms.location.LocationServices
import com.google.android.gms.location.Priority
import com.google.android.gms.maps.CameraUpdateFactory
import com.google.android.gms.maps.GoogleMap
import com.google.android.gms.maps.OnMapReadyCallback
import com.google.android.gms.maps.SupportMapFragment
import com.google.android.gms.maps.model.LatLng
import com.google.android.gms.maps.model.MarkerOptions
import com.google.android.gms.tasks.CancellationTokenSource
import kotlinx.coroutines.launch
class MainActivity : AppCompatActivity(), OnMapReadyCallback {
private lateinit var map: GoogleMap
private lateinit var fusedLocationClient: FusedLocationProviderClient
private val cancellationTokenSource = CancellationTokenSource()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
fusedLocationClient = LocationServices.getFusedLocationProviderClient(this)
val mapFragment = supportFragmentManager.findFragmentById(R.id.mapFragment) as SupportMapFragment
mapFragment.getMapAsync(this)
}
override fun onMapReady(googleMap: GoogleMap) {
map = googleMap
map.uiSettings.isMyLocationButtonEnabled = true
map.uiSettings.isCompassEnabled = true
// Yêu cầu permission và lấy vị trí
requestLocationAndShow()
}
private fun requestLocationAndShow() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
// Request permission dùng ActivityResultContracts (API 33+)
requestPermissionLauncher.launch(Manifest.permission.ACCESS_FINE_LOCATION)
} else {
getCurrentLocation()
}
}
private fun getCurrentLocation() {
binding.progressBar.visibility = View.VISIBLE
// API hiện đại: getCurrentLocation với Priority
fusedLocationClient.getCurrentLocation(Priority.PRIORITY_HIGH_ACCURACY, cancellationTokenSource.token)
.addOnSuccessListener { location: Location? ->
binding.progressBar.visibility = View.GONE
location?.let { showLocationOnMap(it) }
?: Toast.makeText(this, "Không lấy được vị trí", Toast.LENGTH_SHORT).show()
}
.addOnFailureListener { e ->
binding.progressBar.visibility = View.GONE
Toast.makeText(this, "Lỗi GPS: ${e.message}", Toast.LENGTH_SHORT).show()
}
}
private fun showLocationOnMap(location: Location) {
val latLng = LatLng(location.latitude, location.longitude)
val markerOptions = MarkerOptions()
.position(latLng)
.title("Tôi ở đây!")
.snippet("Lat: ${location.latitude}, Lng: ${location.longitude}")
map.addMarker(markerOptions)
map.animateCamera(CameraUpdateFactory.newLatLngZoom(latLng, 15f))
}
// ActivityResultContracts cho permission (API 33+)
private val requestPermissionLauncher = registerForActivityResult(
androidx.activity.result.contract.ActivityResultContracts.RequestPermission()
) { granted ->
if (granted) getCurrentLocation()
else Toast.makeText(this, "Cần quyền vị trí để hiển thị bản đồ", Toast.LENGTH_SHORT).show()
}
override fun onDestroy() {
super.onDestroy()
cancellationTokenSource.cancel()
}
}
Lấy API Key từ Google Cloud Console
- Truy cập Google Cloud Console.
- Tạo project mới hoặc chọn project hiện có.
- Enable APIs: Maps SDK for Android, Places API (tùy chọn).
- Vào APIs & Services → Credentials → Create Credentials → API Key.
- Restrict key: Application restrictions → Android apps → Thêm package name + SHA-1 certificate fingerprint.
- Copy API Key vào
strings.xml.
Lưu ý quan trọng
- Không dùng
getLastLocation()cũ - hay trả về null. DùnggetCurrentLocation()(Play Services Location 21+). - Xử lý permission runtime đúng cách với
ActivityResultContracts. - Luôn cancel location request trong
onDestroy()để tránh leak. - Test trên thiết bị thật (emulator thường không có GPS chính xác).
- API Key phải restrict để tránh bị lạm dụng (quota, billing).