Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> Android

Yêu cầu quyền vị trí (Location) tại runtime Android

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_LOCATION cho 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_LOCATION và ACCESS_COARSE_LOCATION tách biệt

Best Practices

  1. Luôn kiểm tra quyền trước khi sử dụng tính năng
  2. Giải thích lý do cần quyền trước khi xin (shouldShowRequestPermissionRationale)
  3. Xử lý trường hợp user chọn "Don't ask again" → hướng dẫn vào Settings
  4. Chỉ xin quyền khi thực sự cần thiết (lazy permission)