单击以开始位置更新时应用程序崩溃

Posted

技术标签:

【中文标题】单击以开始位置更新时应用程序崩溃【英文标题】:App Crashes On Clicking To Start Location Update 【发布时间】:2017-09-15 20:59:00 【问题描述】:

我正在开发一个应用程序,该应用程序使用指纹身份验证在一定时间内以 10 分钟间隔的形式发送用户的位置,例如 30 分钟。我已经使用某些代码来开发应用程序。但是应用程序在单击开始更新按钮时崩溃。

注意:应用程序崩溃摘要显示 java.lang.SecurityException:客户端必须具有 ACCESS_Fine_LOCATION 权限才能请求 PRIORITY_HIGH_ACCURACY 位置。

以下是代码

清单

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.google.android.gms.location.sample.locationupdates">

<uses-permission android:name="android.permission.USE_FINGERPRINT" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-feature android:name="android.hardware.location.gps" />

<application
    android:allowBackup="true"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme.NoActionBar">
    <meta-data
        android:name="com.google.android.gms.version"
        android:value="@integer/google_play_services_version" />

    <activity
        android:name=".FingerprintActivity"
        android:label="Fingerprint">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

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

</manifest>

FingerprintActivity.java

import android.Manifest; 
import android.annotation.TargetApi;
import android.app.KeyguardManager;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.hardware.fingerprint.FingerprintManager; 
import android.os.Build;
import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyPermanentlyInvalidatedException;
import android.security.keystore.KeyProperties;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import java.io.IOException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;

public class FingerprintActivity extends AppCompatActivity 

private KeyStore keyStore;
// Variable used for storing the key in the Android Keystore container
private static final String KEY_NAME = "androidHive";
private Cipher cipher;
private TextView textView;
public void sendMessage(View view)

    Intent intent = new Intent(FingerprintActivity.this, MainActivity.class);
    startActivity(intent);

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

    // Initializing both Android Keyguard Manager and Fingerprint Manager
    KeyguardManager keyguardManager = (KeyguardManager) getSystemService(KEYGUARD_SERVICE);
    FingerprintManager fingerprintManager = (FingerprintManager) getSystemService(FINGERPRINT_SERVICE);

    textView = (TextView) findViewById(R.id.errorText);

    // Check whether the device has a Fingerprint sensor.
    if(!fingerprintManager.isHardwareDetected())
        /**
         * An error message will be displayed if the device does not contain the fingerprint hardware.
         * However if you plan to implement a default authentication method,
         * you can redirect the user to a default authentication activity from here.
         * Example:
         * Intent intent = new Intent(this, DefaultAuthenticationActivity.class);
         * startActivity(intent);
         */
        textView.setText("Your Device does not have a Fingerprint Sensor");
    else 
        // Checks whether fingerprint permission is set on manifest
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.USE_FINGERPRINT) != PackageManager.PERMISSION_GRANTED) 
            textView.setText("Fingerprint authentication permission not enabled");
        else
            // Check whether at least one fingerprint is registered
            if (!fingerprintManager.hasEnrolledFingerprints()) 
                textView.setText("Register at least one fingerprint in Settings");
            else
                // Checks whether lock screen security is enabled or not
                if (!keyguardManager.isKeyguardSecure()) 
                    textView.setText("Lock screen security not enabled in Settings");
                else
                    generateKey();

                    if (cipherInit()) 
                        FingerprintManager.CryptoObject cryptoObject = new FingerprintManager.CryptoObject(cipher);
                        FingerprintHandler helper = new FingerprintHandler(this);
                        helper.startAuth(fingerprintManager, cryptoObject);
                    
                
            
        
    


@TargetApi(Build.VERSION_CODES.M)
protected void generateKey() 
    try 
        keyStore = KeyStore.getInstance("AndroidKeyStore");
     catch (Exception e) 
        e.printStackTrace();
    

    KeyGenerator keyGenerator;
    try 
        keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
     catch (NoSuchAlgorithmException | NoSuchProviderException e) 
        throw new RuntimeException("Failed to get KeyGenerator instance", e);
    

    try 
        keyStore.load(null);
        keyGenerator.init(new
                KeyGenParameterSpec.Builder(KEY_NAME,
                KeyProperties.PURPOSE_ENCRYPT |
                        KeyProperties.PURPOSE_DECRYPT)
                .setBlockModes(KeyProperties.BLOCK_MODE_CBC)
                .setUserAuthenticationRequired(true)
                .setEncryptionPaddings(
                        KeyProperties.ENCRYPTION_PADDING_PKCS7)
                .build());
        keyGenerator.generateKey();
     catch (NoSuchAlgorithmException |
            InvalidAlgorithmParameterException
            | CertificateException | IOException e) 
        throw new RuntimeException(e);
    


@TargetApi(Build.VERSION_CODES.M)
public boolean cipherInit() 
    try 
        cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/" + KeyProperties.BLOCK_MODE_CBC + "/" + KeyProperties.ENCRYPTION_PADDING_PKCS7);
     catch (NoSuchAlgorithmException | NoSuchPaddingException e) 
        throw new RuntimeException("Failed to get Cipher", e);
    

    try 
        keyStore.load(null);
        SecretKey key = (SecretKey) keyStore.getKey(KEY_NAME,
                null);
        cipher.init(Cipher.ENCRYPT_MODE, key);
        return true;
     catch (KeyPermanentlyInvalidatedException e) 
        return false;
     catch (KeyStoreException | CertificateException | UnrecoverableKeyException | IOException | NoSuchAlgorithmException | InvalidKeyException e) 
        throw new RuntimeException("Failed to init Cipher", e);
    


指纹处理程序

import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.hardware.fingerprint.FingerprintManager;
import android.os.CancellationSignal;
import android.support.v4.app.ActivityCompat;
import android.widget.TextView;

public class FingerprintHandler extends FingerprintManager.AuthenticationCallback 

private Context context;

// Constructor
public FingerprintHandler(Context mContext) 
    context = mContext;


public void startAuth(FingerprintManager manager, FingerprintManager.CryptoObject cryptoObject) 
    CancellationSignal cancellationSignal = new CancellationSignal();
    if (ActivityCompat.checkSelfPermission(context, Manifest.permission.USE_FINGERPRINT) != PackageManager.PERMISSION_GRANTED) 
        return;
    
    manager.authenticate(cryptoObject, cancellationSignal, 0, this, null);


@Override
public void onAuthenticationError(int errMsgId, CharSequence errString) 
    this.update("Fingerprint Authentication error\n" + errString);


@Override
public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) 
    this.update("Fingerprint Authentication help\n" + helpString);


@Override
public void onAuthenticationFailed() 
    this.update("Fingerprint Authentication failed.");


@Override
public void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result) 
    ((Activity) context).finish();
    Intent intent = new Intent(context, MainActivity.class);
    context.startActivity(intent);


private void update(String e)
    TextView textView = (TextView) ((Activity)context).findViewById(R.id.errorText);
    textView.setText(e);



MainActivity

import android.app.Activity;
import android.content.Intent;
import android.content.IntentSender;
import android.location.Location;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.GoogleApiClient.ConnectionCallbacks;
import com.google.android.gms.common.api.GoogleApiClient.OnConnectionFailedListener;
import com.google.android.gms.common.api.ResultCallback;
import com.google.android.gms.common.api.Status;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.location.LocationSettingsRequest;
import com.google.android.gms.location.LocationSettingsResult;
import com.google.android.gms.location.LocationSettingsStatusCodes;

import java.text.DateFormat;
import java.util.Date;

public class MainActivity extends AppCompatActivity implements
    ConnectionCallbacks,
    OnConnectionFailedListener,
    LocationListener 

protected static final String TAG = "MainActivity";

/**
 * Constant used in the location settings dialog.
 */
protected static final int REQUEST_CHECK_SETTINGS = 0x1;


public static final long UPDATE_INTERVAL_IN_MILLISECONDS = 10000;


public static final long FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS =
        UPDATE_INTERVAL_IN_MILLISECONDS / 2;

// Keys for storing activity state in the Bundle.
protected final static String KEY_REQUESTING_LOCATION_UPDATES = "requesting-location-updates";
protected final static String KEY_LOCATION = "location";
protected final static String KEY_LAST_UPDATED_TIME_STRING = "last-updated-time-string";


protected GoogleApiClient mGoogleApiClient;

protected LocationRequest mLocationRequest;


protected LocationSettingsRequest mLocationSettingsRequest;

protected Location mCurrentLocation;

// UI Widgets.
protected Button mStartUpdatesButton;
protected Button mStopUpdatesButton;
protected TextView mLastUpdateTimeTextView;
protected TextView mLatitudeTextView;
protected TextView mLongitudeTextView;
protected TextView mLocationInadequateWarning;

// Labels.
protected String mLatitudeLabel;
protected String mLongitudeLabel;
protected String mLastUpdateTimeLabel;


protected Boolean mRequestingLocationUpdates;


protected String mLastUpdateTime;

@Override
public void onCreate(Bundle savedInstanceState) 
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main_activity);
    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);


    // Locate the UI widgets.
    mStartUpdatesButton = (Button) findViewById(R.id.start_updates_button);
    mStopUpdatesButton = (Button) findViewById(R.id.stop_updates_button);
    mLatitudeTextView = (TextView) findViewById(R.id.latitude_text);
    mLongitudeTextView = (TextView) findViewById(R.id.longitude_text);
    mLastUpdateTimeTextView = (TextView) findViewById(R.id.last_update_time_text);
    mLocationInadequateWarning = (TextView) findViewById(R.id.location_inadequate_warning);

    // Set labels.
    mLatitudeLabel = getResources().getString(R.string.latitude_label);
    mLongitudeLabel = getResources().getString(R.string.longitude_label);
    mLastUpdateTimeLabel = getResources().getString(R.string.last_update_time_label);

    mRequestingLocationUpdates = false;
    mLastUpdateTime = "";

    // Update values using data stored in the Bundle.
    updateValuesFromBundle(savedInstanceState);

    // Kick off the process of building the GoogleApiClient, LocationRequest, and
    // LocationSettingsRequest objects.
    buildGoogleApiClient();
    createLocationRequest();
    buildLocationSettingsRequest();



private void updateValuesFromBundle(Bundle savedInstanceState) 
    if (savedInstanceState != null) 
        // Update the value of mRequestingLocationUpdates from the Bundle, and make sure that
        // the Start Updates and Stop Updates buttons are correctly enabled or disabled.
        if (savedInstanceState.keySet().contains(KEY_REQUESTING_LOCATION_UPDATES)) 
            mRequestingLocationUpdates = savedInstanceState.getBoolean(
                    KEY_REQUESTING_LOCATION_UPDATES);
        

        // Update the value of mCurrentLocation from the Bundle and update the UI to show the
        // correct latitude and longitude.
        if (savedInstanceState.keySet().contains(KEY_LOCATION)) 
            // Since KEY_LOCATION was found in the Bundle, we can be sure that mCurrentLocation
            // is not null.
            mCurrentLocation = savedInstanceState.getParcelable(KEY_LOCATION);
        

        // Update the value of mLastUpdateTime from the Bundle and update the UI.
        if (savedInstanceState.keySet().contains(KEY_LAST_UPDATED_TIME_STRING)) 
            mLastUpdateTime = savedInstanceState.getString(KEY_LAST_UPDATED_TIME_STRING);
        
        updateUI();
    


/**
 * Builds a GoogleApiClient. Uses the @code #addApi method to request the
 * LocationServices API.
 */
protected synchronized void buildGoogleApiClient() 
    Log.i(TAG, "Building GoogleApiClient");
    mGoogleApiClient = new GoogleApiClient.Builder(this)
            .addConnectionCallbacks(this)
            .addOnConnectionFailedListener(this)
            .addApi(LocationServices.API)
            .build();



protected void createLocationRequest() 
    mLocationRequest = new LocationRequest();

    // Sets the desired interval for active location updates. This interval is
    // inexact. You may not receive updates at all if no location sources are available, or
    // you may receive them slower than requested. You may also receive updates faster than
    // requested if other applications are requesting location at a faster interval.
    mLocationRequest.setInterval(UPDATE_INTERVAL_IN_MILLISECONDS);

    // Sets the fastest rate for active location updates. This interval is exact, and your
    // application will never receive updates faster than this value.
    mLocationRequest.setFastestInterval(FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS);

    mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);


/**
 * Uses a @link com.google.android.gms.location.LocationSettingsRequest.Builder to build
 * a @link com.google.android.gms.location.LocationSettingsRequest that is used for checking
 * if a device has the needed location settings.
 */
protected void buildLocationSettingsRequest() 
    LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder();
    builder.addLocationRequest(mLocationRequest);
    mLocationSettingsRequest = builder.build();


/**
 * The callback invoked when
 * @link com.google.android.gms.location.SettingsApi#checkLocationSettings(GoogleApiClient,
 * LocationSettingsRequest) is called. Examines the
 * @link com.google.android.gms.location.LocationSettingsResult object and determines if
 * location settings are adequate. If they are not, begins the process of presenting a location
 * settings dialog to the user.
 */


@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) 
    switch (requestCode) 
        // Check for the integer request code originally supplied to startResolutionForResult().
        case REQUEST_CHECK_SETTINGS:
            switch (resultCode) 
                case Activity.RESULT_OK:
                    Log.i(TAG, "User agreed to make required location settings changes.");
                    // Nothing to do. startLocationupdates() gets called in onResume again.
                    break;
                case Activity.RESULT_CANCELED:
                    Log.i(TAG, "User chose not to make required location settings changes.");
                    mRequestingLocationUpdates = false;
                    updateUI();
                    break;
            
            break;
    


/**
 * Handles the Start Updates button and requests start of location updates. Does nothing if
 * updates have already been requested.
 */
public void startUpdatesButtonHandler(View view) 
    if (!mRequestingLocationUpdates) 
        mRequestingLocationUpdates = true;
        setButtonsEnabledState();
        startLocationUpdates();
    


/**
 * Handles the Stop Updates button, and requests removal of location updates.
 */
public void stopUpdatesButtonHandler(View view) 
    // It is a good practice to remove location requests when the activity is in a paused or
    // stopped state. Doing so helps battery performance and is especially
    // recommended in applications that request frequent location updates.
    stopLocationUpdates();


/**
 * Requests location updates from the FusedLocationApi.
 */
protected void startLocationUpdates() 
    LocationServices.SettingsApi.checkLocationSettings(
            mGoogleApiClient,
            mLocationSettingsRequest
    ).setResultCallback(new ResultCallback<LocationSettingsResult>() 
        @Override
        public void onResult(LocationSettingsResult locationSettingsResult) 
            final Status status = locationSettingsResult.getStatus();
            switch (status.getStatusCode()) 
                case LocationSettingsStatusCodes.SUCCESS:
                    Log.i(TAG, "All location settings are satisfied.");
                    LocationServices.FusedLocationApi.requestLocationUpdates(
                            mGoogleApiClient, mLocationRequest, MainActivity.this);
                    break;
                case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
                    Log.i(TAG, "Location settings are not satisfied. Attempting to upgrade " +
                            "location settings ");
                    try 
                        // Show the dialog by calling startResolutionForResult(), and check the
                        // result in onActivityResult().
                        status.startResolutionForResult(MainActivity.this, REQUEST_CHECK_SETTINGS);
                     catch (IntentSender.SendIntentException e) 
                        Log.i(TAG, "PendingIntent unable to execute request.");
                    
                    break;
                case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
                    String errorMessage = "Location settings are inadequate, and cannot be " +
                            "fixed here. Fix in Settings.";
                    Log.e(TAG, errorMessage);
                    Toast.makeText(MainActivity.this, errorMessage, Toast.LENGTH_LONG).show();
                    mRequestingLocationUpdates = false;
            
            updateUI();
        
    );



/**
 * Updates all UI fields.
 */
private void updateUI() 
    setButtonsEnabledState();
    updateLocationUI();


/**
 * Disables both buttons when functionality is disabled due to insuffucient location settings.
 * Otherwise ensures that only one button is enabled at any time. The Start Updates button is
 * enabled if the user is not requesting location updates. The Stop Updates button is enabled
 * if the user is requesting location updates.
 */
private void setButtonsEnabledState() 
    if (mRequestingLocationUpdates) 
        mStartUpdatesButton.setEnabled(false);
        mStopUpdatesButton.setEnabled(true);
     else 
        mStartUpdatesButton.setEnabled(true);
        mStopUpdatesButton.setEnabled(false);
    


/**
 * Sets the value of the UI fields for the location latitude, longitude and last update time.
 */
private void updateLocationUI() 
    if (mCurrentLocation != null) 
        mLatitudeTextView.setText(String.format("%s: %f", mLatitudeLabel,
                mCurrentLocation.getLatitude()));
        mLongitudeTextView.setText(String.format("%s: %f", mLongitudeLabel,
                mCurrentLocation.getLongitude()));
        mLastUpdateTimeTextView.setText(String.format("%s: %s", mLastUpdateTimeLabel,
                mLastUpdateTime));
    


/**
 * Removes location updates from the FusedLocationApi.
 */
protected void stopLocationUpdates() 
    // It is a good practice to remove location requests when the activity is in a paused or
    // stopped state. Doing so helps battery performance and is especially
    // recommended in applications that request frequent location updates.
    LocationServices.FusedLocationApi.removeLocationUpdates(
            mGoogleApiClient,
            this
    ).setResultCallback(new ResultCallback<Status>() 
        @Override
        public void onResult(Status status) 
            mRequestingLocationUpdates = false;
            setButtonsEnabledState();
        
    );


@Override
protected void onStart() 
    super.onStart();
    mGoogleApiClient.connect();


@Override
public void onResume() 
    super.onResume();
    // Within @code onPause(), we pause location updates, but leave the
    // connection to GoogleApiClient intact.  Here, we resume receiving
    // location updates if the user has requested them.
    if (mGoogleApiClient.isConnected() && mRequestingLocationUpdates) 
        startLocationUpdates();
    
    updateUI();


@Override
protected void onPause() 
    super.onPause();
    // Stop location updates to save battery, but don't disconnect the GoogleApiClient object.
    if (mGoogleApiClient.isConnected()) 
        stopLocationUpdates();
    


@Override
protected void onStop() 
    super.onStop();
    mGoogleApiClient.disconnect();


/**
 * Runs when a GoogleApiClient object successfully connects.
 */
@Override
public void onConnected(Bundle connectionHint) 
    // If the initial location was never previously requested, we use
    // FusedLocationApi.getLastLocation() to get it. If it was previously requested, we store
    // its value in the Bundle and check for it in onCreate(). We
    // do not request it again unless the user specifically requests location updates by pressing
    // the Start Updates button.
    //
    // Because we cache the value of the initial location in the Bundle, it means that if the
    // user launches the activity,
    // moves to a new location, and then changes the device orientation, the original location
    // is displayed as the activity is re-created.
    if (mCurrentLocation == null) 
        mCurrentLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
        mLastUpdateTime = DateFormat.getTimeInstance().format(new Date());
        updateLocationUI();
    
    if (mRequestingLocationUpdates) 
        Log.i(TAG, "in onConnected(), starting location updates");
        startLocationUpdates();
    



/**
 * Callback that fires when the location changes.
 */
@Override
public void onLocationChanged(Location location) 
    mCurrentLocation = location;
    mLastUpdateTime = DateFormat.getTimeInstance().format(new Date());
    updateLocationUI();


@Override
public void onConnectionSuspended(int cause) 
    Log.i(TAG, "Connection suspended");


@Override
public void onConnectionFailed(ConnectionResult result) 
    // Refer to the javadoc for ConnectionResult to see what error codes might be returned in
    // onConnectionFailed.
    Log.i(TAG, "Connection failed: ConnectionResult.getErrorCode() = " + result.getErrorCode());


/**
 * Stores activity data in the Bundle.
 */
public void onSaveInstanceState(Bundle savedInstanceState) 
    savedInstanceState.putBoolean(KEY_REQUESTING_LOCATION_UPDATES, mRequestingLocationUpdates);
    savedInstanceState.putParcelable(KEY_LOCATION, mCurrentLocation);
    savedInstanceState.putString(KEY_LAST_UPDATED_TIME_STRING, mLastUpdateTime);
    super.onSaveInstanceState(savedInstanceState);


@Override
public boolean onCreateOptionsMenu(Menu menu) 
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.menu_main, menu);
    return true;


@Override
public boolean onOptionsItemSelected(MenuItem item) 
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.
    int id = item.getItemId();

    if (id == R.id.action_settings) 
        return true;
    

    return super.onOptionsItemSelected(item);


【问题讨论】:

而不是附加大量不相关的代码,您应该在崩溃后阅读堆栈跟踪 (LogCat),查找“Caused by ....”行,然后检查那里提到的文件和行。跨度> 阅读注释。我已经在崩溃日志中提到了原因。 这个应用的 targetSdk 是什么? minSdkVersion 23 targetSdkVersion 24 ACCESS_FINE_LOCATION permission error emulator only的可能重复 【参考方案1】:

minSdkVersion 23 目标SdkVersion 24

面向 SDK 23+ 要求您支持运行时权限。您的清单是 &lt;uses-permission&gt;s 在这种情况下无关紧要(如果您不针对较低的 SDK,可以将其删除)。由于您不支持运行时权限,因此您的应用未获得 GPS 访问权限,因此与 SecurityException 发生崩溃。

文档:https://developer.android.com/training/permissions/requesting.html

快速解决方案:如果可以,请将 targetSdk(和 minSdk)降低到 23 以下。如果出于任何原因不能,则必须实施运行时权限。有一些库可以帮助完成这项任务 - 只需 google 即可。

【讨论】:

以上是关于单击以开始位置更新时应用程序崩溃的主要内容,如果未能解决你的问题,请参考以下文章

单击侧栏菜单时应用程序崩溃

从 Windows 开始菜单打开 WPF 应用程序时崩溃

在 Fused Location 的帮助下请求位置更新时应用程序崩溃

0x8badf00d 在后台获取监听位置后崩溃

单击注释气泡时应用程序崩溃

C++:当我的应用程序在随机位置崩溃时从哪里开始?