2015-08-18 6 views
74

Ogni volta che esegue l'applicazione, il mio SecurityException viene buttato e l'errore dal debugger recita così:Android "GPS richiede ACCESS_FINE_LOCATION" l'errore, anche se il mio file manifesto contiene questo

java.lang.SecurityException: " il fornitore di posizione GPS richiede l'autorizzazione ACCESS_COARSE_LOCATION o ACCESS_FINE_LOCATION.

Questo sembra un errore semplice, tuttavia, il mio file manifest è completamente corretto. Qui è, e qui è il mio codice MapActivity così:

<?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> 

La mia attività:

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) { 

    } 
} 
+0

Su quale versione di Android stai testando questo? – CommonsWare

+2

La più recente API: 23 –

+2

Non correlata, ma se si richiede la posizione precisa, non è necessario richiedere la ricerca approssimativa. È incluso –

risposta

111

ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION e WRITE_EXTERNAL_STORAGE sono tutti parte di the Android 6.0 runtime permission system. Oltre ad averli nel manifest come fai tu, anche devi richiederli dall'utente in fase di runtime (usando requestPermissions()) e vedere se li hai (usando checkSelfPermission()).

Una soluzione a breve termine è far cadere il vostro targetSdkVersion sotto 23.

Ma, alla fine, si vuole aggiornare la vostra applicazione per utilizzare il sistema dei permessi di esecuzione.

Ad esempio, questa attività funziona con cinque autorizzazioni. Quattro sono permessi di runtime, anche se attualmente ne sta gestendo solo tre (l'ho scritto prima che fosse aggiunto il roster di autorizzazione al runtime allo 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(); 
    } 
} 

(da this sample project)

Per i requestPermissions function(), qualora i parametri di essere solo "ACCESS_COARSE_LOCATION"? O dovrei includere il nome completo "android.permission.ACCESS_COARSE_LOCATION"?

Vorrei utilizzare le costanti definite su Manifest.permission, come mostrato sopra.

Inoltre, qual è il codice di richiesta?

che sarà passato di nuovo a voi come il primo parametro onRequestPermissionsResult(), in modo da poter dire a un requestPermissions() chiamata da un altro.

+1

Per la funzione requestPermissions(), i parametri devono essere solo "ACCESS_COARSE_LOCATION"? O dovrei includere il nome completo "android.permission.ACCESS_COARSE_LOCATION"? –

+0

Inoltre, qual è il codice di richiesta? –

+1

Grazie, ti sei liberato dell'errore. Ho ancora problemi ad accedere alla mia posizione, poiché il mio locationManager continua a restituire la mia posizione come null, ma ciò non è rilevante per questo bug. Grazie per la soluzione! –

30

La mia soluzione più semplice è questo

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(); 
} 

oppure è possibile aprire la finestra di autorizzazione altro come questo

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

passa a un'altra parte :( –

+2

aggiungi finestra di dialogo per aggiungere permessi in questo "altro", e sei a posto. –

+0

Questa è infatti senza dubbio la correzione per Android 6. Va notato che devi mettere le richieste di autorizzazione nel resto. –

2

CAUSA: "A partire dal Android 6.0 (API livello 23), gli utenti concedono autorizzazioni a app mentre l'app è in esecuzione, non quando installano l'app."In questo caso," ACCESS_FINE_LOCATION "è un" permesso pericoloso e per questo motivo, ottieni questo 'java.lang.SecurityException: il provider di posizione "gps" richiede l'autorizzazione ACCESS_FINE_LOCATION. " errore (https://developer.android.com/training/permissions/requesting.html).

SOLUZIONE: implementazione del codice fornito a https://developer.android.com/training/permissions/requesting.html nelle intestazioni "Richiedi le autorizzazioni necessarie" e "Gestisci le richieste di autorizzazione".