Ошибка: клиент должен иметь ACCESS_COARSE_LOCATION или ACCESS_FINE_LOCATION

android android-permissions

7802 просмотра

1 ответ

32 Репутация автора

Я использую модуль в другом приложении. Перед тем, как реализовать модуль, я установил его на API-уровне 23 (компиляция и цель), как и мой основной проект. Это прекрасно работает, за исключением этой ошибки. Проблема в том, что Google изменил управление разрешениями с момента добавления marshmellow. Наконец, я не знаю, как и где я должен установить разрешения.

Эту ошибку я получаю при запуске приложения:

java.lang.SecurityException: Клиент должен иметь разрешение ACCESS_COARSE_LOCATION или ACCESS_FINE_LOCATION для выполнения любого расположения операций.

Не могли бы вы помочь мне и кратко объяснить (какой код мне нужен и куда вставить), чтобы избежать этой ошибки?

Манифест от Модуля:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.cs.android.weminder">

<!--

android:versionCode="3"
android:versionName="1.2.0" >


<uses-sdk
    android:minSdkVersion="9"
    android:targetSdkVersion="19" />

    -->

<!-- Grant the network access permission -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"           />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<!-- Grant the location access permission -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!-- Allows using PowerManager WakeLocks to keep processor from sleeping or screen from dimming -->
<uses-permission android:name="android.permission.WAKE_LOCK" />
<!-- Permission required to use Alarm Manager -->
<uses-permission android:name="com.android.alarm.permission.SET_ALARM" />
<uses-permission android:name="android.permission.GET_TASKS" />

<application
    android:allowBackup="true"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">

    <!--    android:name="com.cs.android.weminder.MyApplication"
            android:label="@string/app_name">-->

    <!-- This meta-data tag is required to use Google Play Services. -->
    <meta-data
        android:name="com.google.android.gms.version"
        android:value="@integer/google_play_services_version" />
    <!-- Required for creating dialog of the ACRA report -->
    <activity
        android:name="org.acra.CrashReportDialog"
        android:excludeFromRecents="true"
        android:finishOnTaskLaunch="true"
        android:launchMode="singleInstance"
        android:theme="@style/AcraDialog" />
    <activity
        android:name="com.cs.android.weminder.MainActivity"
        android:launchMode="singleTop"
        android:screenOrientation="portrait" >

        <action android:name="android.intent.action.MAIN" />

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

    </activity>
    <activity android:name="com.cs.android.weminder.BaseScreen" />
    <activity android:name="com.cs.android.weminder.LocationBaseScreen" />
    <activity android:name="com.cs.android.weminder.SettingsActivity" />
    <activity android:name="com.cs.android.weminder.WeminderApplication" />


    <!-- Required by the AdMob Ads SDK -->



    <activity
        android:name="com.google.ads.AdActivity"
        android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize" />
    <!-- Include the AdActivity configChanges and theme. -->
    <activity
        android:name="com.google.android.gms.ads.AdActivity"
        android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize"
        android:theme="@android:style/Theme.Translucent" />


    <receiver
        android:name="com.cs.android.weminder.AlarmReceiver"
        android:process=":remote" >
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED" />
        </intent-filter>
    </receiver>

    <service android:name="com.cs.android.weminder.AlarmService" >
    </service>
</application>

Основная деятельность от модуля:

public class MainActivity extends SettingsActivity implements ActionTypes,
    ResultType {




private TextView tvLocation, tvHTemp, tvLTemp, tvCurrentTemp, tvTimestamp,
        tvDate, tvWindSpeed, tvPressure;
private ImageView ivCurrentWeather, ivRefresh, ivUnit, ivSearch, ivRemind,
        ivMyLocation;
private HorizontalViewGallery forecastGallery;
// Search field
private MyCustomEditText etSearch;

// holding different weather icons presenting weather condition
// alternatively.
private IconFinder mIconFinder;

private ApiCallQueue requestsQueue = new ApiCallQueue();

// Ads View
private AdView adView;





private void setupUI(View view) {
    // Set up touch listener for non-text box views to hide keyboard.
    if (!(view instanceof EditText)) {
        view.setOnTouchListener(new OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                // Hide the search field if the user is touching anywhere
                // except the search field
                if (etSearch.isShown()) {
                    etSearch.startDeflation();
                    return true;
                }
                return false;
            }
        });
    }

    // If a layout container, iterate over children and seed recursion.
    if (view instanceof ViewGroup) {
        for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
            View innerView = ((ViewGroup) view).getChildAt(i);
            setupUI(innerView);
        }
    }
}

/**
 * Initial the UI of current screen Initial variables;
 */
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
private void initialActivity() {
    setupUI(findViewById(R.id.parent));
    // display the name of location
    tvLocation = (TextView) findViewById(R.id.tvLocation);
    // Set the location icon
    tvLocation.setCompoundDrawablesWithIntrinsicBounds(getResources()
            .getDrawable(R.drawable.icon_marker), null, null, null);
    // display today highest temperature
    tvHTemp = (TextView) findViewById(R.id.tvHTemp);
    // Set the highest temperature icon
    tvHTemp.setCompoundDrawablesWithIntrinsicBounds(getResources()
            .getDrawable(R.drawable.icon_highest), null, null, null);
    // display today lowest temperature
    tvLTemp = (TextView) findViewById(R.id.tvLTemp);
    // Set the lowest temperature icon
    tvLTemp.setCompoundDrawablesWithIntrinsicBounds(getResources()
            .getDrawable(R.drawable.icon_lowest), null, null, null);
    // display the current temperature
    tvCurrentTemp = (TextView) findViewById(R.id.tvCurrentTemp);
    // display the update time stamp
    tvTimestamp = (TextView) findViewById(R.id.tvTimestamp);
    // display the date of today
    tvDate = (TextView) findViewById(R.id.tvDate);
    // display the wind speed
    tvWindSpeed = (TextView) findViewById(R.id.tvWindSpeed);
    // Set wind speed icon
    tvWindSpeed.setCompoundDrawablesWithIntrinsicBounds(getResources()
            .getDrawable(R.drawable.icon_wind), null, null, null);
    // display the pressure
    tvPressure = (TextView) findViewById(R.id.tvPressure);
    // Set wind speed icon
    tvPressure.setCompoundDrawablesWithIntrinsicBounds(getResources()
            .getDrawable(R.drawable.icon_pressure), null, null, null);
    // visualize the current weather condition
    ivCurrentWeather = (ImageView) findViewById(R.id.ivCurrentWeather);
    // Scrollable forecast
    forecastGallery = (HorizontalViewGallery) findViewById(R.id.gForcast);
    // Search city button
    ivSearch = (ImageView) findViewById(R.id.ivSearch);
    // Setting button
    ivRemind = (ImageView) findViewById(R.id.ivRemind);
    // My location button
    ivMyLocation = (ImageView) findViewById(R.id.ivMyLocation);
    // Temp unit setting Button
    ivUnit = (ImageView) findViewById(R.id.ivUnit);
    if (getTempUnit().equals(PARAM_TEMP_UNIT_C))
        ivUnit.setImageDrawable(getResources().getDrawable(
                R.drawable.button_unit_f));
    else if (getTempUnit().equals(PARAM_TEMP_UNIT_F))
        ivUnit.setImageDrawable(getResources().getDrawable(
                R.drawable.button_unit_c));
    // Refresh button
    ivRefresh = (ImageView) findViewById(R.id.ivRefresh);
    // Search field
    etSearch = (MyCustomEditText) findViewById(R.id.etSearch);
    // set the animation of search field
    // Animation Duration in milliseconds;
    int duration = 500;
    // Inflate animation
    final AnimationSet inflate = new AnimationSet(true);
    ScaleAnimation scaleIn = new ScaleAnimation(0f, 1.0f, 1.0f, 1.0f,
            Animation.RELATIVE_TO_SELF, 1.0f, Animation.RELATIVE_TO_SELF,
            0.5f);
    scaleIn.setDuration(duration);
    inflate.addAnimation(scaleIn);
    inflate.setAnimationListener(new AnimationListener() {

        @Override
        public void onAnimationEnd(Animation animation) {
        }

        @Override
        public void onAnimationRepeat(Animation animation) {
        }

        @Override
        public void onAnimationStart(Animation animation) {
            etSearch.setVisibility(View.VISIBLE);
            etSearch.requestFocus();
            showSoftKeyboard(etSearch);
        }
    });
    // Deflate animation
    final AnimationSet deflate = new AnimationSet(true);
    ScaleAnimation scaleDe = new ScaleAnimation(1.0f, 0f, 1.0f, 1.0f,
            Animation.RELATIVE_TO_SELF, 1.0f, Animation.RELATIVE_TO_SELF,
            0.5f);
    scaleDe.setDuration(duration);
    deflate.addAnimation(scaleDe);
    deflate.setAnimationListener(new AnimationListener() {

        @Override
        public void onAnimationEnd(Animation animation) {
            etSearch.setVisibility(View.INVISIBLE);
        }

        @Override
        public void onAnimationRepeat(Animation animation) {
        }

        @Override
        public void onAnimationStart(Animation animation) {
            hideSoftKeyboard(etSearch);
        }
    });

    etSearch.setInflation(inflate);
    etSearch.setDeflation(deflate);

    // Running the change of digital clock on separate UI thread
    // to avoid any delay of other action on UI.
    runOnUiThread(new Runnable() {
        @Override
        public void run() {
            if (!Utils.androidMinimum(API_JELLY_BEAN_MR1)) {
                // Using the widget class {@code DigitalClock} if the
                // android api is less than 17
                DigitalClock dcClock = (DigitalClock) findViewById(R.id.dcClock);
                dcClock.addTextChangedListener(new TextWatcher() {

                    @Override
                    public void onTextChanged(CharSequence s, int start,
                            int before, int count) {
                    }

                    @Override
                    public void beforeTextChanged(CharSequence s,
                            int start, int count, int after) {
                    }

                    @Override
                    public void afterTextChanged(Editable s) {
                        // Removed seconds
                        if (s.length() >= 5) {
                            if (s.charAt(4) == ':') {
                                s.delete(4, s.length());
                            } else if (s.length() >= 6
                                    && s.charAt(5) == ':') {
                                s.delete(5, s.length());
                            }
                        }
                    }
                });
            } else {
                // Using the widget class {@code TextClock} if the android
                // api is greater than or equal to 17
                TextClock dcClock = (TextClock) findViewById(R.id.dcClock);
                dcClock.addTextChangedListener(new TextWatcher() {

                    @Override
                    public void onTextChanged(CharSequence s, int start,
                            int before, int count) {
                    }

                    @Override
                    public void beforeTextChanged(CharSequence s,
                            int start, int count, int after) {
                    }

                    @Override
                    public void afterTextChanged(Editable s) {
                        // Removed seconds
                        if (s.length() >= 5) {
                            if (s.charAt(4) == ':') {
                                s.delete(4, s.length());
                            } else if (s.length() >= 6
                                    && s.charAt(5) == ':') {
                                s.delete(5, s.length());
                            }
                        }
                    }
                });
            }
        }
    });

    mIconFinder = new IconFinder(this);
}

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);




    /*
     * Create a new location client, using the enclosing class to handle
     * callbacks.
     */
    mLocationClient = new LocationClient(this, this, this);

    // Create the LocationRequest object
    mLocationRequest = LocationRequest.create();
    // Use high accuracy
    mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
    // Set the update interval to 5 seconds
    mLocationRequest.setInterval(UPDATE_INTERVAL);
    // Set the fastest update interval to 1 second
    mLocationRequest.setFastestInterval(FASTEST_INTERVAL);

    setContentView(R.layout.activity_main);
    .
    .
    .

Не могли бы вы объяснить, как лучше всего управлять новой системой разрешений. Пожалуйста, объясните мне простым способом

Автор: BakteriusD Источник Размещён: 18.07.2016 08:09

Ответы (1)


10 плюса

16754 Репутация автора

Решение

Грубое и точное расположение считается «опасным» разрешением. Поэтому вы должны запросить их при запуске приложения (потому что я предполагаю, что у вас Android 6+):

public void checkPermission(){
    if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED ||
                       ContextCompat.checkSelfPermission(this,Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED
                    ){//Can add more as per requirement

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

И для звонков:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ) {
    checkPermission();
}

Вы можете реализовать это где угодно, просто не забудьте спросить разрешения, прежде чем использовать то, что требует их!

РЕДАКТИРОВАТЬ:

Вещи выше должны быть вызваны в деятельности. Это метод onCreate, который вы опубликовали выше:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    /*
    This is called before initializing the map because the map needs permissions(the cause of the crash)
    */
    if (Build.VERSION.SDK_INT == Build.VERSION_CODES.M ) {
        checkPermission();
    }

    /*
     * Create a new location client, using the enclosing class to handle
     * callbacks.
     */
    mLocationClient = new LocationClient(this, this, this);

    // Create the LocationRequest object
    mLocationRequest = LocationRequest.create();
    // Use high accuracy
    mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
    // Set the update interval to 5 seconds
    mLocationRequest.setInterval(UPDATE_INTERVAL);
    // Set the fastest update interval to 1 second
    mLocationRequest.setFastestInterval(FASTEST_INTERVAL);

    setContentView(R.layout.activity_main);
    .
    .
    .

Это «легкий» способ. Вы можете заставить пользователя к этому также.

в onCreate вызовите checkPermissions как обычно.

Однако checkPermissions теперь будет содержать намерение. Это хорошо для вызова при запуске, потому что это изменит активность на это:

import android.Manifest;
import android.app.Activity;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.view.View;
import android.widget.Button;


public class Permissions extends Activity implements View.OnClickListener{
    /**
     * This will handle permissions asking
     */
    Button button;
    //handles ask permissions/continue
    boolean completed = false;
    public void onCreate(Bundle sis){
        super.onCreate(sis);
        /**
         * I'm not going to create the layout for you, but you essentially need two things:
         * a TextView
         * a Button
         *
         * The TextView will explain **why** you need the permissions, while the button
         * will be pressed by the user to ask the permissions. No need to call the textview
         * inside this class
         */
        setContentView(R.layout.yourlayout);
        button = (Button) findViewById(R.id.button);

    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.button:
                if(!completed)
                    askPermissions();
                else{
                    //start the main activity
                }
                break;
        }
    }


    public void askPermissions(){
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED ||
                ContextCompat.checkSelfPermission(this,Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED
                ){//Can add more as per requirement

            ActivityCompat.requestPermissions(this,
                    new String[]{Manifest.permission.ACCESS_FINE_LOCATION,Manifest.permission.ACCESS_COARSE_LOCATION},
                    123);
        }else if(ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED &&
                ContextCompat.checkSelfPermission(this,Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED
                ){
            completed = true;
            button.setText("Permissions supplied. Press to continue");
        }

    }
}

И новый чек Permission в деятельности:

public void checkPermission(){
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED ||
                           ContextCompat.checkSelfPermission(this,Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED
                        ){//Can add more as per requirement

       //start an intent to the class above. Do this because the app does not have enough permissions

    }
}

Это заставит пользователя разрешить доступ к разрешениям, иначе он / она не получит доступ к приложению. Если в разрешениях отказано, пользователь не получит доступ, потому что это приведет к сбою приложения (вы можете написать это в пояснительном текстовом представлении в макете.

Так что я не собираюсь предоставлять вам макет, потому что это действительно ваше дело. Но вам нужны две основные вещи:

  • Кнопка - пользователь нажимает это после прочтения текстового представления (предназначено, вы не можете заставить пользователя прочитать его), и при нажатии кнопки оно либо запрашивает разрешения, либо перенаправляет на
  • TextView - объяснит, какие разрешения вы запрашиваете и зачем они вам нужны

Эта система очень умная, потому что, если все разрешения предоставлены, экран не вызывается. Имейте в виду, что очень важно иметь Build-VERSION.SDK_INT> = Build.VERSION_CODES.M, иначе это вызовет ошибки (потому что запрашивает разрешения на платформах, которые его не поддерживают)

Автор: Zoe the transgirl Размещён: 18.07.2016 08:12
Вопросы из категории :
32x32