Yêu cầu quyền vị trí (Location) tại runtime Android
Hướng dẫn này minh họa cách xin quyền ACCESS_FINE_LOCATION tại runtime (Android 6.0+ API 23+).
Bước 1: Tạo dự án mới
Mở Android Studio, chọn File → New Project và điền thông tin cần thiết.
Bước 2: Thiết kế giao diện (activity_main.xml)
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Request Location permission at Run time!"
android:padding="4dp"
android:layout_centerInParent="true"
android:textSize="36sp"
android:textStyle="bold"/>
</RelativeLayout>
Bước 3: Code MainActivity.java
import android.Manifest;
import android.content.pm.PackageManager;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
private static final int LOCATION_PERMISSION_REQUEST_CODE = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
requestLocationPermission();
}
private void requestLocationPermission() {
// Kiểm tra quyền đã được cấp chưa
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
// Nên hiển thị lý do trước khi xin quyền (best practice)
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.ACCESS_FINE_LOCATION)) {
// Hiển thị dialog giải thích tại sao cần quyền
new AlertDialog.Builder(this)
.setTitle("Cần quyền vị trí")
.setMessage("Ứng dụng cần quyền vị trí để hiển thị vị trí của bạn trên bản đồ")
.setPositiveButton("OK", (dialog, which) ->
requestPermission())
.setNegativeButton("Hủy", null)
.show();
} else {
// Xin quyền trực tiếp
requestPermission();
}
} else {
// Đã có quyền, thực hiện công việc
Toast.makeText(this, "Permission already granted", Toast.LENGTH_SHORT).show();
}
}
private void requestPermission() {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
LOCATION_PERMISSION_REQUEST_CODE);
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == LOCATION_PERMISSION_REQUEST_CODE) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Quyền được cấp
Toast.makeText(this, "Permission Granted", Toast.LENGTH_SHORT).show();
// TODO: Thực hiện công việc cần vị trí
} else {
// Quyền bị từ chối
Toast.makeText(this, "Permission Denied", Toast.LENGTH_SHORT).show();
// Có thể hướng dẫn user vào Settings để bật quyền
}
}
}
}
Bước 4: Cấu hình AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="https://schemas.android.com/apk/res/android" package="app.com.sample">
<uses-permission android:name="android.permission.ACCESS_FINE_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/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Chạy ứng dụng
Kết nối thiết bị Android 6.0+, chạy app. Dialog xin quyền vị trí sẽ hiện ra. Chọn "Allow" hoặc "Deny" để xem kết quả Toast.
Lưu ý quan trọng (Android 10+):
- Android 10 (API 29) thêm quyền
ACCESS_BACKGROUND_LOCATIONcho truy cập vị trí nền - Android 11 (API 30) yêu cầu xin quyền từng bước: foreground trước, background sau
- Android 12 (API 31) thêm
ACCESS_FINE_LOCATIONvàACCESS_COARSE_LOCATIONtách biệt
Best Practices
- Luôn kiểm tra quyền trước khi sử dụng tính năng
- Giải thích lý do cần quyền trước khi xin (
shouldShowRequestPermissionRationale) - Xử lý trường hợp user chọn "Don't ask again" → hướng dẫn vào Settings
- Chỉ xin quyền khi thực sự cần thiết (lazy permission)