Android 'gps에는 ACCESS_FINE_LOCATION이 필요합니다'오류가 발생하지만 매니페스트 파일에 다음이 포함되어 있습니다.


104

응용 프로그램을 실행할 때마다 SecurityException이 발생하고 디버거의 오류가 다음과 같이 읽습니다.

java.lang.SecurityException : "gps"위치 제공자는 ACCESS_COARSE_LOCATION 또는 ACCESS_FINE_LOCATION 권한이 필요합니다.

이것은 단순한 실수처럼 보이지만 내 매니페스트 파일은 완전히 정확합니다. 여기에 내 MapActivity 코드도 있습니다.

<?xml version="1.0" encoding="utf-8"?>

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
<uses-permission android:name="com.dev.cromer.jason.coverme.permission.MAPS_RECEIVE" />

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme" >
    <activity
        android:name=".MainActivity"
        android:label="@string/app_name" >
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>

    <meta-data
        android:name="com.google.android.gms.version"
        android:value="@integer/google_play_services_version" />
    <meta-data
        android:name="com.google.android.maps.v2.API_KEY"
        android:value= "@string/google_maps_key" />

    <activity
        android:name=".MapActivity"
        android:label="@string/title_activity_map" >
    </activity>
</application>

내 활동 :

    package com.dev.cromer.jason.coverme;

import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.support.v4.app.FragmentActivity;
import android.os.Bundle;
import android.util.Log;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;

public class MapActivity extends FragmentActivity implements LocationListener {

    private GoogleMap mMap; // Might be null if Google Play services APK is not available.

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_map);

        setUpMapIfNeeded();
    }

    @Override
    protected void onResume() {
        super.onResume();
        setUpMapIfNeeded();
    }



    private void setUpMapIfNeeded() {
        // Do a null check to confirm that we have not already instantiated the map.
        if (mMap == null) {
            // Try to obtain the map from the SupportMapFragment.
            mMap = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map))
                    .getMap();

            // Check if we were successful in obtaining the map.
            if (mMap != null) {
                //mMap.setMyLocationEnabled(true);
                //mMap.setOnMyLocationChangeListener(this);
                setUpMap();
            }
        }
    }


    private void setUpMap() {
        mMap.addMarker(new MarkerOptions().position(new LatLng(0, 0)).title("Marker"));
        mMap.setMyLocationEnabled(true);

        LocationManager locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);

        try {
            Location myLocation = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);

            if (myLocation != null) {
                Log.d("TAG", "Not null");
            }
            else {
                Log.d("TAG", "NULL");
                locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);
            }
        }
        catch (SecurityException se) {
            Log.d("TAG", "SE CAUGHT");
            se.printStackTrace();
        }
    }


    @Override
    public void onLocationChanged(Location location) {
        Log.d("CHANGED", "LOCATION UPDATED");

    }

    @Override
    public void onStatusChanged(String provider, int status, Bundle extras) {

    }

    @Override
    public void onProviderEnabled(String provider) {

    }

    @Override
    public void onProviderDisabled(String provider) {

    }
}

어떤 버전의 Android에서 이것을 테스트하고 있습니까?
CommonsWare

4
관련이 없지만 좋은 위치를 요청하는 경우 대략적인 요청을 할 필요가 없습니다. 포함되어 있습니다.
joey_g216

답변:


136

ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATIONWRITE_EXTERNAL_STORAGE모두 Android 6.0 런타임 권한 시스템의 일부입니다 . 당신이로 매니페스트에 그들을 가지고 이외에, 당신은 또한 (사용하여 런타임에 사용자로부터 그들을 요청해야 requestPermissions()합니다 (사용하여이있는 경우) 및 참조 checkSelfPermission()).

단기간에 한 가지 해결 방법은 targetSdkVersion23 미만 으로 낮추는 것 입니다.

그러나 결국에는 런타임 권한 시스템을 사용하도록 앱을 업데이트해야합니다.

예를 들어이 활동은 5 개의 권한으로 작동합니다. 4 개는 런타임 권한이지만 현재는 3 개만 처리하고 있습니다 (이전 WRITE_EXTERNAL_STORAGE에 런타임 권한 목록에 추가 되었음).

/***
 Copyright (c) 2015 CommonsWare, LLC
 Licensed under the Apache License, Version 2.0 (the "License"); you may not
 use this file except in compliance with the License. You may obtain a copy
 of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless required
 by applicable law or agreed to in writing, software distributed under the
 License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
 OF ANY KIND, either express or implied. See the License for the specific
 language governing permissions and limitations under the License.

 From _The Busy Coder's Guide to Android Development_
 https://commonsware.com/Android
 */

package com.commonsware.android.permmonger;

import android.Manifest;
import android.app.Activity;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity {
  private static final String[] INITIAL_PERMS={
    Manifest.permission.ACCESS_FINE_LOCATION,
    Manifest.permission.READ_CONTACTS
  };
  private static final String[] CAMERA_PERMS={
    Manifest.permission.CAMERA
  };
  private static final String[] CONTACTS_PERMS={
      Manifest.permission.READ_CONTACTS
  };
  private static final String[] LOCATION_PERMS={
      Manifest.permission.ACCESS_FINE_LOCATION
  };
  private static final int INITIAL_REQUEST=1337;
  private static final int CAMERA_REQUEST=INITIAL_REQUEST+1;
  private static final int CONTACTS_REQUEST=INITIAL_REQUEST+2;
  private static final int LOCATION_REQUEST=INITIAL_REQUEST+3;
  private TextView location;
  private TextView camera;
  private TextView internet;
  private TextView contacts;
  private TextView storage;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    location=(TextView)findViewById(R.id.location_value);
    camera=(TextView)findViewById(R.id.camera_value);
    internet=(TextView)findViewById(R.id.internet_value);
    contacts=(TextView)findViewById(R.id.contacts_value);
    storage=(TextView)findViewById(R.id.storage_value);

    if (!canAccessLocation() || !canAccessContacts()) {
      requestPermissions(INITIAL_PERMS, INITIAL_REQUEST);
    }
  }

  @Override
  protected void onResume() {
    super.onResume();

    updateTable();
  }

  @Override
  public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.actions, menu);

    return(super.onCreateOptionsMenu(menu));
  }

  @Override
  public boolean onOptionsItemSelected(MenuItem item) {
    switch(item.getItemId()) {
      case R.id.camera:
        if (canAccessCamera()) {
          doCameraThing();
        }
        else {
          requestPermissions(CAMERA_PERMS, CAMERA_REQUEST);
        }
        return(true);

      case R.id.contacts:
        if (canAccessContacts()) {
          doContactsThing();
        }
        else {
          requestPermissions(CONTACTS_PERMS, CONTACTS_REQUEST);
        }
        return(true);

      case R.id.location:
        if (canAccessLocation()) {
          doLocationThing();
        }
        else {
          requestPermissions(LOCATION_PERMS, LOCATION_REQUEST);
        }
        return(true);
    }

    return(super.onOptionsItemSelected(item));
  }

  @Override
  public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    updateTable();

    switch(requestCode) {
      case CAMERA_REQUEST:
        if (canAccessCamera()) {
          doCameraThing();
        }
        else {
          bzzzt();
        }
        break;

      case CONTACTS_REQUEST:
        if (canAccessContacts()) {
          doContactsThing();
        }
        else {
          bzzzt();
        }
        break;

      case LOCATION_REQUEST:
        if (canAccessLocation()) {
          doLocationThing();
        }
        else {
          bzzzt();
        }
        break;
    }
  }

  private void updateTable() {
    location.setText(String.valueOf(canAccessLocation()));
    camera.setText(String.valueOf(canAccessCamera()));
    internet.setText(String.valueOf(hasPermission(Manifest.permission.INTERNET)));
    contacts.setText(String.valueOf(canAccessContacts()));
    storage.setText(String.valueOf(hasPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)));
  }

  private boolean canAccessLocation() {
    return(hasPermission(Manifest.permission.ACCESS_FINE_LOCATION));
  }

  private boolean canAccessCamera() {
    return(hasPermission(Manifest.permission.CAMERA));
  }

  private boolean canAccessContacts() {
    return(hasPermission(Manifest.permission.READ_CONTACTS));
  }

  private boolean hasPermission(String perm) {
    return(PackageManager.PERMISSION_GRANTED==checkSelfPermission(perm));
  }

  private void bzzzt() {
    Toast.makeText(this, R.string.toast_bzzzt, Toast.LENGTH_LONG).show();
  }

  private void doCameraThing() {
    Toast.makeText(this, R.string.toast_camera, Toast.LENGTH_SHORT).show();
  }

  private void doContactsThing() {
    Toast.makeText(this, R.string.toast_contacts, Toast.LENGTH_SHORT).show();
  }

  private void doLocationThing() {
    Toast.makeText(this, R.string.toast_location, Toast.LENGTH_SHORT).show();
  }
}

( 이 샘플 프로젝트에서 )

requestPermissions () 함수의 경우 매개 변수가 "ACCESS_COARSE_LOCATION"이어야합니까? 아니면 "android.permission.ACCESS_COARSE_LOCATION"전체 이름을 포함해야합니까?

Manifest.permission위에 표시된 대로에 정의 된 상수를 사용합니다 .

또한 요청 코드는 무엇입니까?

이는에 대한 첫 번째 매개 변수로 다시 전달 onRequestPermissionsResult()되므로 한 requestPermissions()호출을 다른 호출에 알릴 수 있습니다 .


1
requestPermissions () 함수의 경우 매개 변수가 "ACCESS_COARSE_LOCATION"이어야합니까? 아니면 "android.permission.ACCESS_COARSE_LOCATION"전체 이름을 포함해야합니까?
Jason Cromer

1
감사합니다. 이로 인해 오류가 제거되었습니다. 내 locationManager가 내 위치를 계속 null로 반환하기 때문에 여전히 내 위치에 액세스하는 데 문제가 있지만이 버그와 관련이 없습니다. 솔루션에 감사드립니다!
Jason Cromer

@CommonsWare : '결국'이라는 말은 무슨 뜻입니까? 죄송합니다. 해당 부분이 없습니다.
theapache64

1
@ theapache64 : 언젠가는 무언가가 당신 targetSdkVersion을 23 이상 으로 설정하도록 만들 것 입니다. 이 시점에서 런타임 권한 시스템을 채택해야합니다. 그 때까지 targetSdkVersion23 세 미만 으로 유지 하고 런타임 권한을 무시할 수 있습니다.
CommonsWare

@CommonsWare : 이제 알았습니다. :)
theapache64

39

내 간단한 해결책은

if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) ==
        PackageManager.PERMISSION_GRANTED &&
        ContextCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION) ==
        PackageManager.PERMISSION_GRANTED) {
    googleMap.setMyLocationEnabled(true);
    googleMap.getUiSettings().setMyLocationButtonEnabled(true);
} else {
    Toast.makeText(this, R.string.error_permission_map, Toast.LENGTH_LONG).show();
}

또는 다음과 같이 권한 대화 상자를 열 수 있습니다.

} else {
   ActivityCompat.requestPermissions(this, new String[] {
      Manifest.permission.ACCESS_FINE_LOCATION, 
      Manifest.permission.ACCESS_COARSE_LOCATION }, 
      TAG_CODE_PERMISSION_LOCATION);
}

laways 이동 다른 부분 형제 :(
Ashana.Jackol

2
이 "else"에 권한을 추가하는 대화 상자를 추가하면 좋습니다.
Vasil Valchev

이것은 의심 할 여지없이 Android 6에 대한 수정 사항입니다. 권한 요청을 else에 넣어야합니다.
Keith Adler

이 오류는 Target SDK가 22이고 Android 5.1에서 장치 S plus (GiONEE_WBL7511)입니다. 이 충돌이 발생한 이유에 대해 혼란 스럽습니다. 단서가 있습니까? java.lang.SecurityException : PRIORITY_HIGH_ACCURACY 위치를 요청하려면 클라이언트에 ACCESS_FINE_LOCATION 권한이 있어야합니다.
arpitgoyal2008

5

원인 : "Android 6.0 (API 레벨 23)부터 사용자는 앱을 설치할 때가 아니라 앱이 실행되는 동안 앱에 권한을 부여합니다." 이 경우 "ACCESS_FINE_LOCATION"은 "위험한 권한이며 이러한 이유로 'java.lang.SecurityException :"gps "위치 제공 업체에 ACCESS_FINE_LOCATION 권한이 필요합니다.'가 표시됩니다. 오류 ( https://developer.android.com/training/permissions/requesting.html ).

솔루션 : https://developer.android.com/training/permissions/requesting.html 에서 "필요한 권한 요청"및 "권한 요청 응답 처리"제목 아래에 제공된 코드를 구현합니다 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.