启动位置服务时出现java.lang.SecurityException

时间:2015-11-11 16:28:56

标签: java android android-service android-6.0-marshmallow location-aware

我尝试将位置服务作为后台服务运行。它在活动中运行良好,但是当我使用服务时,我得到了java.lang.securityException:客户端必须具有ACCESS_COARSE_LOCATION或ACCESS_FINE_LOCATION权限才能执行任何位置操作。我已经提供了适当的权限,但问题仍然存在。我正在使用nexus 5(Marshmallow)进行测试。

这是我的服务

public class LocationService extends Service implements
    GoogleApiClient.ConnectionCallbacks,
    GoogleApiClient.OnConnectionFailedListener,
    LocationListener {

private static final String TAG = "LocationService";

// use the websmithing defaultUploadWebsite for testing and then check your
// location with your browser here: https://www.websmithing.com/gpstracker/displaymap.php
private String defaultUploadWebsite;

private boolean currentlyProcessingLocation = false;
private LocationRequest locationRequest;
private GoogleApiClient locationClient;
private String username;

@Override
public void onCreate() {
    super.onCreate();
    //defaultUploadWebsite = getString(R.string.default_upload_website);
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    // if we are currently trying to get a location and the alarm manager has called this again,
    // no need to start processing a new location.
    if (!currentlyProcessingLocation) {
        currentlyProcessingLocation = true;
        startTracking();
    }

    return START_NOT_STICKY;
}

private void startTracking() {
    Log.d(TAG, "startTracking");

    if (GooglePlayServicesUtil.isGooglePlayServicesAvailable(this) == ConnectionResult.SUCCESS) {
        locationClient = new GoogleApiClient.Builder(this)
                .addApi(LocationServices.API)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this).build();


        if (!locationClient.isConnected() || !locationClient.isConnecting()) {
            locationClient.connect();
        }
    } else {
        Log.e(TAG, "unable to connect to google play services.");
    }
}

protected void sendLocationDataToWebsite(Location location) {
    // formatted for mysql datetime format
    Log.i(TAG, String.valueOf(location.getLatitude()) + " " + String.valueOf(location.getLongitude()));


}

@Override
public void onDestroy() {
    super.onDestroy();


    stopLocationUpdates();
    stopSelf();

}

@Override
public IBinder onBind(Intent intent) {
    return null;
}

@Override
public void onLocationChanged(Location location) {
    if (location != null) {
        Log.e(TAG, "position: " + location.getLatitude() + ", " + location.getLongitude() + " accuracy: " + location.getAccuracy());

        // we have our desired accuracy of 500 meters so lets quit this service,
        // onDestroy will be called and stop our location uodates
        sendLocationDataToWebsite(location);
    }
}

private void stopLocationUpdates() {
    if (locationClient != null && locationClient.isConnected()) {
        LocationServices.FusedLocationApi.removeLocationUpdates(locationClient, this);
        locationClient.disconnect();
    }
}

/**
 * Called by Location Services when the request to connect the
 * client finishes successfully. At this point, you can
 * request the current location or start periodic updates
 */
@Override
public void onConnected(Bundle bundle) {
    Log.d(TAG, "onConnected");

    locationRequest = new LocationRequest();
    locationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
    locationRequest.setInterval(Constants.UPDATE_INTERVAL);
    locationRequest.setFastestInterval(Constants.FASTEST_INTERVAL);
    LocationServices.FusedLocationApi.requestLocationUpdates(locationClient,
            locationRequest, this);
}

@Override
public void onConnectionSuspended(int i) {
    stopLocationUpdates();
}

/**
 * Called by Location Services if the connection to the
 * location client drops because of an error.
 */

@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
    Log.e(TAG, "onConnectionFailed");

    stopLocationUpdates();
    stopSelf();
}

public String getCurrentTime()
{
    SimpleDateFormat sdf = new SimpleDateFormat("HH:mm");
    String currentTime = sdf.format(new Date());
    return currentTime;
}

public String getDeviceName() {
    String manufacturer = Build.MANUFACTURER;
    String model = Build.MODEL;
    if (model.startsWith(manufacturer)) {
        return capitalize(model);
    } else {
        return capitalize(manufacturer) + " " + model;
    }
}

private String capitalize(String s) {
    if (s == null || s.length() == 0) {
        return "";
    }
    char first = s.charAt(0);
    if (Character.isUpperCase(first)) {
        return s;
    } else {
        return Character.toUpperCase(first) + s.substring(1);
    }
}

这是我的明白

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="app.fikri.com.navigationsystem" >

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!--
     The ACCESS_COARSE/FINE_LOCATION permissions are not required to use
     Google Maps Android API v2, but you must specify either coarse or fine
     location permissions for the 'MyLocation' functionality. 
-->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:supportsRtl="true"
    android:theme="@style/AppTheme" >
    <activity
        android:name=".MainActivity"
        android:label="@string/app_name"
        android:theme="@style/AppTheme.NoActionBar" >
    </activity>
    <activity
        android:name=".SplashScreen"
        android:configChanges="orientation|keyboardHidden|screenSize"
        android:label="@string/title_activity_splash_screen"
        android:theme="@style/FullscreenTheme" >
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
    <!--
         The API key for Google Maps-based APIs is defined as a string resource.
         (See the file "res/values/google_maps_api.xml").
         Note that the API key is linked to the encryption key used to sign the APK.
         You need a different API key for each encryption key, including the release key that is used to
         sign the APK for publishing.
         You can define the keys for the debug and release targets in src/debug/ and src/release/. 
    -->
    <meta-data
        android:name="com.google.android.geo.API_KEY"
        android:value="@string/google_maps_key" />

    <activity
        android:name=".MapsActivity"
        android:label="@string/title_activity_maps" >
    </activity>

    <service android:name=".Service.LocationService">
    </service>

</application>

2 个答案:

答案 0 :(得分:1)

关于如何在定位Android Marshmallow时使用运行时权限,您应该阅读runtime permissionBuilding better apps with Runtime Permissions

答案 1 :(得分:1)

检查此链接在运行时请求权限 http://developer.android.com/training/permissions/index.html