1

我试图将位置服务作为后台服务运行。它在活动中运行良好,但是当我使用服务时,我得到了 java.lang.securityException: Client must have ACCESS_COARSE_LOCATION or 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>

4

1 回答 1

1

您可能应该阅读运行时权限和使用运行时权限构建更好的应用程序,了解如何在针对 Android Marshmallow 时使用运行时权限。

于 2015-11-11T16:34:35.693 回答