Bỏ qua để đến nội dung

Google Maps

Bài này hướng dẫn bạn tích hợp Google Maps vào ứng dụng Android với Jetpack Compose, từ setup cơ bản đến các tính năng nâng cao.

Google Maps cho phép bạn:

  • Hiển thị bản đồ trong app
  • Đánh dấu vị trí (markers)
  • Hiển thị vị trí hiện tại của user
  • Vẽ đường đi, polylines
  • Tích hợp với Places API để tìm kiếm địa điểm
  1. Truy cập Google Cloud Console
  2. Tạo project mới hoặc chọn project có sẵn
  3. Vào APIs & Services > Library
  4. Enable Maps SDK for Android
  5. Vào APIs & Services > Credentials
  6. Click Create Credentials > API Key
  7. Copy API key
// build.gradle.kts (Module: app)
dependencies {
// Google Maps Compose
implementation("com.google.maps.android:maps-compose:4.3.0")
// Google Maps Services (optional, for places)
implementation("com.google.android.gms:play-services-maps:18.2.0")
implementation("com.google.android.gms:play-services-location:21.1.0")
}
AndroidManifest.xml
<application ...>
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="${MAPS_API_KEY}" />
</application>
// local.properties (KHÔNG commit lên Git!)
MAPS_API_KEY=AIzaSyB...your_api_key_here
build.gradle.kts
android {
defaultConfig {
manifestPlaceholders["MAPS_API_KEY"] =
project.findProperty("MAPS_API_KEY") as String? ?: ""
}
}

Tại sao làm như vậy?

  • API key là thông tin nhạy cảm
  • Không nên commit trực tiếp vào code
  • local.properties đã được ignore bởi .gitignore
@Composable
fun BasicMapScreen() {
// Vị trí mặc định: Hà Nội
val hanoi = LatLng(21.0285, 105.8542)
// Camera state - điều khiển góc nhìn của bản đồ
val cameraPositionState = rememberCameraPositionState {
position = CameraPosition.fromLatLngZoom(hanoi, 12f)
}
GoogleMap(
modifier = Modifier.fillMaxSize(),
cameraPositionState = cameraPositionState
)
}

Giải thích:

  • LatLng(21.0285, 105.8542): Tọa độ (vĩ độ, kinh độ) của Hà Nội
  • zoom = 12f: Mức zoom (1 = thế giới, 20 = tòa nhà)
  • cameraPositionState: Quản lý vị trí camera (có thể animate)
@Composable
fun MapWithMarkers() {
val hanoi = LatLng(21.0285, 105.8542)
val hoGuom = LatLng(21.0288, 105.8525)
val hoTay = LatLng(21.0542, 105.8231)
val cameraPositionState = rememberCameraPositionState {
position = CameraPosition.fromLatLngZoom(hanoi, 13f)
}
GoogleMap(
modifier = Modifier.fillMaxSize(),
cameraPositionState = cameraPositionState
) {
// Marker cơ bản
Marker(
state = MarkerState(position = hoGuom),
title = "Hồ Gươm",
snippet = "Trung tâm Hà Nội"
)
// Marker với icon tùy chỉnh
Marker(
state = MarkerState(position = hoTay),
title = "Hồ Tây",
icon = BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_BLUE)
)
}
}

Giải thích:

  • Marker: Đánh dấu một vị trí trên bản đồ
  • title: Tiêu đề hiển thị khi tap vào marker
  • snippet: Mô tả ngắn bên dưới title
  • icon: Có thể dùng màu khác hoặc icon tùy chỉnh
AndroidManifest.xml
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
@Composable
fun MapWithCurrentLocation() {
val context = LocalContext.current
var currentLocation by remember { mutableStateOf<LatLng?>(null) }
// Request location permission
val permissionState = rememberPermissionState(Manifest.permission.ACCESS_FINE_LOCATION)
LaunchedEffect(permissionState.status.isGranted) {
if (permissionState.status.isGranted) {
// Lấy vị trí hiện tại
val fusedLocationClient = LocationServices.getFusedLocationProviderClient(context)
fusedLocationClient.lastLocation.addOnSuccessListener { location ->
location?.let {
currentLocation = LatLng(it.latitude, it.longitude)
}
}
}
}
// UI
Column {
if (!permissionState.status.isGranted) {
Button(onClick = { permissionState.launchPermissionRequest() }) {
Text("Cho phép truy cập vị trí")
}
}
currentLocation?.let { location ->
val cameraPositionState = rememberCameraPositionState {
position = CameraPosition.fromLatLngZoom(location, 15f)
}
GoogleMap(
modifier = Modifier.fillMaxSize(),
cameraPositionState = cameraPositionState,
properties = MapProperties(isMyLocationEnabled = true)
) {
Marker(
state = MarkerState(position = location),
title = "Vị trí của bạn"
)
}
}
}
}

Giải thích từng bước:

  1. Kiểm tra permission đã được cấp chưa
  2. Nếu chưa → hiển thị button để request
  3. Nếu có → dùng FusedLocationProviderClient để lấy vị trí
  4. isMyLocationEnabled = true hiển thị chấm xanh vị trí hiện tại
@Composable
fun MapWithTapHandler() {
var selectedLocation by remember { mutableStateOf<LatLng?>(null) }
val cameraPositionState = rememberCameraPositionState {
position = CameraPosition.fromLatLngZoom(LatLng(21.0285, 105.8542), 12f)
}
GoogleMap(
modifier = Modifier.fillMaxSize(),
cameraPositionState = cameraPositionState,
onMapClick = { latLng ->
// User tap vào vị trí này
selectedLocation = latLng
}
) {
selectedLocation?.let { location ->
Marker(
state = MarkerState(position = location),
title = "Vị trí đã chọn",
snippet = "Lat: ${location.latitude}, Lng: ${location.longitude}"
)
}
}
}
@Composable
fun MapWithRoute() {
// Các điểm tạo thành đường đi
val routePoints = listOf(
LatLng(21.0285, 105.8542), // Điểm A
LatLng(21.0300, 105.8500), // Điểm B
LatLng(21.0350, 105.8450), // Điểm C
LatLng(21.0400, 105.8400), // Điểm D
)
GoogleMap(...) {
// Vẽ đường nối các điểm
Polyline(
points = routePoints,
color = Color.Blue,
width = 10f
)
// Đánh dấu điểm đầu và cuối
Marker(state = MarkerState(position = routePoints.first()), title = "Điểm đi")
Marker(state = MarkerState(position = routePoints.last()), title = "Điểm đến")
}
}
GoogleMap(
properties = MapProperties(
mapType = MapType.NORMAL // Bản đồ thường
// mapType = MapType.SATELLITE // Ảnh vệ tinh
// mapType = MapType.TERRAIN // Địa hình
// mapType = MapType.HYBRID // Kết hợp
)
)
GoogleMap(
uiSettings = MapUiSettings(
zoomControlsEnabled = true, // Nút +/-
compassEnabled = true, // La bàn
myLocationButtonEnabled = true, // Nút về vị trí hiện tại
mapToolbarEnabled = false // Toolbar Google Maps
)
)

Bước Làm gì
1 Tạo API key trên Google Cloud Console
2 Thêm dependency maps-compose
3 Cấu hình API key trong Manifest
4 Dùng GoogleMap composable
5 Thêm Marker để đánh dấu vị trí
6 Request permission để lấy vị trí user
  • Không commit API key lên GitHub
  • Sử dụng local.properties hoặc environment variables
  • Có thể restrict API key trong Google Cloud Console