Kiểm tra quyền của Android cho LocationManager


97

Tôi đang cố gắng hiển thị tọa độ GPS khi tôi nhấp vào một nút trong bố cục hoạt động của mình. Sau đây là phương thức được gọi khi tôi nhấp vào nút:

public void getLocation(View view) {
    TextView tv = (TextView) findViewById(R.id.gps_coord_view);
    LocationManager lm = (LocationManager) getSystemService(LOCATION_SERVICE);
    Location loc = lm.getLastKnownLocation(LocationManager.GPS_PROVIDER);
    tv.setText("Latitude: " + loc.getLatitude() + "\nLongitude: " + loc.getLongitude());
}

Tôi gặp một lỗi cho biết

Cuộc gọi yêu cầu quyền và có thể bị người dùng từ chối. Mã nên kiểm tra rõ ràng để xem liệu có quyền hay không.

Tôi đã cấp các quyền này trong của tôi AndroidManifest. Lỗi được xử lý và ứng dụng sẽ biên dịch khi tôi thêm phần sau trước khi gọi lm.getLastKnownLocation:

if (checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
        && checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
    return;
}

Tuy nhiên, ứng dụng bị treo khi tôi nhấn vào nút gọi getLocation khi nó được nhấp. Điều gì đang xảy ra? Có cách nào tốt hơn / đơn giản hơn để lấy tọa độ GPS của thiết bị không?


Có lẽ bạn có thể đính kèm một bản ghi ngoại lệ.
Milan

1
Sử dụng ContextCompat.checkSelfPermission (bối cảnh, cho phép) và chắc chắn rằng bạn đã đề cập đến điều khoản thích hợp trong manifest
Snehal Poyrekar

Câu trả lời:


149

Với cấp API Android (23), chúng tôi bắt buộc phải kiểm tra các quyền. https://developer.android.com/training/permissions/requesting.html

Tôi đã gặp sự cố tương tự của bạn, nhưng cách sau đây đã hiệu quả với tôi và tôi có thể truy xuất thành công dữ liệu Vị trí:

(1) Đảm bảo bạn có các quyền được liệt kê trong Tệp kê khai:

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>

(2) Đảm bảo bạn yêu cầu quyền từ người dùng:

if ( ContextCompat.checkSelfPermission( this, android.Manifest.permission.ACCESS_COARSE_LOCATION ) != PackageManager.PERMISSION_GRANTED ) {

            ActivityCompat.requestPermissions( this, new String[] {  android.Manifest.permission.ACCESS_COARSE_LOCATION  },
                                                LocationService.MY_PERMISSION_ACCESS_COURSE_LOCATION );
        }

(3) Đảm bảo bạn sử dụng ContextCompat vì điều này có khả năng tương thích với các cấp API cũ hơn.

(4) Trong dịch vụ vị trí của bạn hoặc lớp khởi tạo Trình quản lý vị trí của bạn và nhận vị trí đã biết cuối cùng, chúng tôi cần kiểm tra các quyền:

if ( Build.VERSION.SDK_INT >= 23 &&
             ContextCompat.checkSelfPermission( context, android.Manifest.permission.ACCESS_FINE_LOCATION ) != PackageManager.PERMISSION_GRANTED &&
             ContextCompat.checkSelfPermission( context, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            return  ;
        }

(5) Cách tiếp cận này chỉ hoạt động với tôi sau khi tôi bao gồm @TargetApi (23) ở đầu phương thức initLocationService của mình.

(6) Tôi cũng đã thêm cái này vào bản dựng gradle của mình:

compile 'com.android.support:support-v4:23.0.1'

Đây là LocationService của tôi để tham khảo:

public class LocationService implements LocationListener  {

    //The minimum distance to change updates in meters
    private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 0; // 10 meters

    //The minimum time between updates in milliseconds
    private static final long MIN_TIME_BW_UPDATES = 0;//1000 * 60 * 1; // 1 minute

    private final static boolean forceNetwork = false;

    private static LocationService instance = null;

    private LocationManager locationManager;
    public Location location;
    public double longitude;
    public double latitude; 


    /**
     * Singleton implementation
     * @return
     */
    public static LocationService getLocationManager(Context context)     {
        if (instance == null) {
            instance = new LocationService(context);
        }
        return instance;
    }

    /**
     * Local constructor
     */
    private LocationService( Context context )     {

        initLocationService(context); 
        LogService.log("LocationService created");
    }



    /**
     * Sets up location service after permissions is granted
     */
    @TargetApi(23)
    private void initLocationService(Context context) {


        if ( Build.VERSION.SDK_INT >= 23 &&
             ContextCompat.checkSelfPermission( context, android.Manifest.permission.ACCESS_FINE_LOCATION ) != PackageManager.PERMISSION_GRANTED &&
             ContextCompat.checkSelfPermission( context, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            return  ;
        }

        try   {
            this.longitude = 0.0;
            this.latitude = 0.0;
            this.locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);

            // Get GPS and network status
            this.isGPSEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
            this.isNetworkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);

            if (forceNetwork) isGPSEnabled = false;

            if (!isNetworkEnabled && !isGPSEnabled)    {
                // cannot get location
                this.locationServiceAvailable = false;
            }
            //else
            {
                this.locationServiceAvailable = true;

                if (isNetworkEnabled) {
                    locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,
                            MIN_TIME_BW_UPDATES,
                            MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
                    if (locationManager != null)   {
                        location = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
                        updateCoordinates();
                    }
                }//end if

                if (isGPSEnabled)  {
                    locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
                            MIN_TIME_BW_UPDATES,
                            MIN_DISTANCE_CHANGE_FOR_UPDATES, this);

                    if (locationManager != null)  {
                        location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
                        updateCoordinates();
                    }
                }
            }
        } catch (Exception ex)  {
            LogService.log( "Error creating location service: " + ex.getMessage() );

        }
    }       


    @Override
    public void onLocationChanged(Location location)     {
        // do stuff here with location object 
    }
}

Tôi chỉ thử nghiệm với thiết bị Android Lollipop. Hy vọng điều này làm việc cho bạn.


2
Tôi thích giải pháp của bạn, nhưng bạn nên kiểm tra xem locationManager có trống không trước khi sử dụng nó, không phải sau này.
Fer

9
LocationService.MY_PERMISSION_ACCESS_COURSE_LOCATION dòng này không hoạt động phiên bản 23

4
LocationService.MY_PERMISSION_ACCESS_COURSE_LOCATION cũng không hoạt động với tôi.
Kairi San

1
@delive, LocationService.MY_PERMISSION_ACCESS_COURSE_LOCATION -> bạn phải xác định mã int này trong hoạt động của riêng bạn (đã triển khai lớp ActivityCompat.OnRequestPermissionsResultCallback), để biết chi tiết, vui lòng kiểm tra liên kết này .
David Cheung

11
KHÓA HỌC không phải KHÓA HỌC
Chris Cox

46

GIẢI PHÁP ĐƠN GIẢN

Tôi muốn hỗ trợ các ứng dụng trước api 23 và thay vì sử dụng, checkSelfPermissiontôi đã sử dụng thử / bắt

try {
   location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
} catch (SecurityException e) {
   dialogGPS(this.getContext()); // lets the user know there is a problem with the gps
}

39

Phần cuối cùng của thông báo lỗi mà bạn đã trích dẫn cho biết: ...with ("checkPermission") or explicitly handle a potential "SecurityException"

Một cách nhanh hơn / đơn giản hơn nhiều để kiểm tra xem bạn có quyền hay không là bao quanh mã của bạn try { ... } catch (SecurityException e) { [insert error handling code here] }. Nếu bạn có quyền, phần 'thử' sẽ thực thi, nếu bạn không có quyền, phần 'bắt' sẽ thực thi.


1
Hữu ích nếu bạn không có đối tượng Hoạt động hoặc Ngữ cảnh mà bạn có thể kiểm tra quyền.
Nublodeveloper

5

Sử dụng lớp bảo mật của tôi để kiểm tra hoặc yêu cầu quyền

public class Permissons {

        //Request Permisson
        public static void Request_STORAGE(Activity act,int code)
        {

            ActivityCompat.requestPermissions(act, new
                    String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE},code);
        }
        public static void Request_CAMERA(Activity act,int code)
        {
            ActivityCompat.requestPermissions(act, new
                    String[]{Manifest.permission.CAMERA},code);
        }
        public static void Request_FINE_LOCATION(Activity act,int code)
        {
            ActivityCompat.requestPermissions(act, new
                    String[]{Manifest.permission.ACCESS_FINE_LOCATION},code);
        }
        public static void Request_READ_SMS(Activity act,int code)
        {
            ActivityCompat.requestPermissions(act, new
                    String[]{Manifest.permission.READ_SMS},code);
        }
        public static void Request_READ_CONTACTS(Activity act,int code)
        {
            ActivityCompat.requestPermissions(act, new
                    String[]{Manifest.permission.READ_CONTACTS},code);
        }
        public static void Request_READ_CALENDAR(Activity act,int code)
        {
            ActivityCompat.requestPermissions(act, new
                    String[]{Manifest.permission.READ_CALENDAR},code);
        }
        public static void Request_RECORD_AUDIO(Activity act,int code)
        {
            ActivityCompat.requestPermissions(act, new
                    String[]{Manifest.permission.RECORD_AUDIO},code);
        }

        //Check Permisson
        public static boolean Check_STORAGE(Activity act)
        {
            int result = ContextCompat.checkSelfPermission(act,android.Manifest.permission.WRITE_EXTERNAL_STORAGE);
            return result == PackageManager.PERMISSION_GRANTED;
        }
        public static boolean Check_CAMERA(Activity act)
        {
            int result = ContextCompat.checkSelfPermission(act, Manifest.permission.CAMERA);
            return result == PackageManager.PERMISSION_GRANTED;
        }
        public static boolean Check_FINE_LOCATION(Activity act)
        {
            int result = ContextCompat.checkSelfPermission(act, Manifest.permission.ACCESS_FINE_LOCATION);
            return result == PackageManager.PERMISSION_GRANTED;
        }
        public static boolean Check_READ_SMS(Activity act)
        {
            int result = ContextCompat.checkSelfPermission(act, Manifest.permission.READ_SMS);
            return result == PackageManager.PERMISSION_GRANTED;
        }
        public static boolean Check_READ_CONTACTS(Activity act)
        {
            int result = ContextCompat.checkSelfPermission(act, Manifest.permission.READ_CONTACTS);
            return result == PackageManager.PERMISSION_GRANTED;
        }
        public static boolean Check_READ_CALENDAR(Activity act)
        {
            int result = ContextCompat.checkSelfPermission(act, Manifest.permission.READ_CALENDAR);
            return result == PackageManager.PERMISSION_GRANTED;
        }
        public static boolean Check_RECORD_AUDIO(Activity act)
        {
            int result = ContextCompat.checkSelfPermission(act, Manifest.permission.RECORD_AUDIO);
            return result == PackageManager.PERMISSION_GRANTED;
        }
    }

Thí dụ

if(!Permissons.Check_STORAGE(MainActivity.this))
{
   //if not permisson granted so request permisson with request code
   Permissons.Request_STORAGE(MainActivity.this,22);
}

cảm ơn, nhưng tôi muốn hỏi, chức năng của "mã int" là gì?
Hendro Pramono

sử dụng mã này để cho phép kết quả được cấp hoặc từ chối đối với Kết quả hoạt động
milan pithadia

4

nếu bạn đang làm việc trên quyền động và bất kỳ quyền nào như ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION đưa ra lỗi "không thể giải quyết phương pháp PERMISSION_NAME" trong trường hợp này, hãy viết mã cho bạn với tên quyền và sau đó xây dựng lại dự án của bạn, điều này sẽ tạo lại tệp kê khai (Manifest.permission).


0

Nếu bạn chỉ muốn kiểm tra quyền (thay vì yêu cầu quyền), tôi đã viết một tiện ích mở rộng đơn giản như sau:

fun BaseActivity.checkPermission(permissionName: String): Boolean {
        return if (Build.VERSION.SDK_INT >= 23) {
            val granted =
                ContextCompat.checkSelfPermission(this, permissionName)
            granted == PackageManager.PERMISSION_GRANTED
        } else {
            val granted =
                PermissionChecker.checkSelfPermission(this, permissionName)
            granted == PermissionChecker.PERMISSION_GRANTED
        }
    }

Bây giờ, nếu tôi muốn kiểm tra một quyền, tôi có thể chỉ cần chuyển một quyền như sau:

checkPermission(Manifest.permission.READ_CONTACTS)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.