Google Play Hizmetleri ve Çalışma Zamanı İzinleri

Android 6.0 Marshmallow sürümünden beri Android, uygulama yükleme ve otomatik güncelleme işlemlerini kolaylaştıran bir izin modeli kullanır. İzinler, uygulama yüklenmeden önce değil, çalışma zamanında istenir. Ayrıca kullanıcılar belirli izinleri reddetmeyi tercih edebilir. Kullanıcılara bu esnekliği sağlamak için, kullanıcı belirli bir izni etkinleştirdiğinde veya devre dışı bıraktığında uygulamanızın beklendiği gibi çalıştığından emin olmanız gerekir.

Google Play hizmetlerinin kendisinde, kullanıcıların uygulamanız tarafından özel olarak istenen izinlerden ayrı olarak reddetmeyi seçebilecekleri çalışma zamanı izinleri bulunur. Google Play Hizmetleri, API'lerini desteklemek için gereken tüm izinleri otomatik olarak alır. Bununla birlikte, uygulamanız yine de çalışma zamanı izinlerini gerekli şekilde kontrol edip istemeli ve bir kullanıcının, uygulamanızın kullandığı bir API için gereken bir izni Google Play Hizmetleri'ni reddettiği durumlarda hataları uygun şekilde ele almalıdır.

Kullanıcının, çalışma zamanının ihtiyaç duyabileceği izinleri ayarlarken beklentilerini yönetmek iyi bir uygulamadır. Aşağıdaki en iyi uygulamalar, olası sorunlardan kaçınmanıza yardımcı olacaktır.

Ön koşullar

AndroidManifest.xml dosyanızda izinleri beyan etmeniz gerekiyor. Örneğin:

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

Yönergeler

API'leri çağırmadan önce izinleri doğrulayın

AndroidManifest.xml dosyanızda kullanmak istediğiniz API'leri beyan ettikten sonra, API çağırmadan önce gerekli izne sahip olduğunuzdan emin olun. Bu, checkSelfPermission ActivityCompat veya ContextCompat yöntemi kullanılarak yapılabilir.

Çağrı "false" değerini döndürürse bu, izinlerin verilmediği ve izin istemek için requestPermissions işlevini kullanmanız gerektiği anlamına gelir. Buna verilen yanıt, bir sonraki adımda göreceğiniz geri çağırmada döndürülür.

Örneğin:

if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
    != PackageManager.PERMISSION_GRANTED) {
  // Check Permissions Now
  ActivityCompat.requestPermissions(this,
      new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
      REQUEST_LOCATION);
} else {
  // permission has been granted, continue as usual
  Task<Location> locationResult = LocationServices
      .getFusedLocationProviderClient(this /** Context */)
      .getLastLocation();
}

İstek izni geri çağırma işlemini uygulayın

Kullanıcı, uygulamanıza ihtiyaç duyduğu izni vermediyse kullanıcıdan bu izni vermesini istemek için requestPermissions yöntemi çağrılmalıdır. Kullanıcının yanıtı onRequestPermissionsResult geri çağırmasında yakalanır. Uygulamanız bunu uygulamalı ve istek reddedilebileceği veya iptal edilebileceği için döndürülen değerleri her zaman kontrol etmelidir. Ayrıca, bir defada birden çok izin isteyip kontrol edebilirsiniz. Aşağıdaki örnek, yalnızca tek bir izni kontrol eder.

public void onRequestPermissionsResult(int requestCode,
                                       String[] permissions,
                                       int[] grantResults) {
    if (requestCode == REQUEST_LOCATION) {
        if(grantResults.length == 1
           && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            // We can now safely use the API we requested access to
            Task<Location> locationResult = LocationServices
                .getFusedLocationProviderClient(this /** Context */)
                .getLastLocation();
        } else {
            // Permission was denied or request was cancelled
        }
    }
}

İzin gerekçesini göster

Uygulamanızın istediği izinler uygulamanın temel özellikleri için gerekiyorsa ve kullanıcı daha önce izin isteğini reddetmişse uygulamanızın izni tekrar istemeden önce ek bir açıklama göstermesi gerekir. Kullanıcıların, iznin neden gerekli olduğunu ve anında faydasını anladıklarında izin verme olasılıkları artar.

Bu durumda, requestPermissions numaralı telefondan önce shouldShowRequestPermissionRationale numarasını aramanız gerekir. Doğru döndürülürse izinle ilgili ek bağlam görüntülemek için bazı kullanıcı arayüzü oluşturmanız gerekir.

Örneğin, kodunuz aşağıdaki gibi görünebilir:

if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
    != PackageManager.PERMISSION_GRANTED) {
    // Check Permissions Now
    private static final int REQUEST_LOCATION = 2;

    if (ActivityCompat.shouldShowRequestPermissionRationale(this,
            Manifest.permission.ACCESS_FINE_LOCATION)) {
        // Display UI and wait for user interaction
    } else {
        ActivityCompat.requestPermissions(
            this, new String[]{Manifest.permission.LOCATION_FINE},
            ACCESS_FINE_LOCATION);
    }
} else {
    // permission has been granted, continue as usual
    Task<Location> locationResult = LocationServices
        .getFusedLocationProviderClient(this /** Context */)
        .getLastLocation();
}

Bağlantı hatalarını işleme

Uygulamanız kullanımdan kaldırılan GoogleApiClient sürümünü kullanıyorsa connect() aracını aradığınızda Google Play Hizmetleri, uygulamanın gerekli tüm izinlere sahip olduğunu doğrular. Google Play Hizmetleri'nin ihtiyaç duyduğu izin grupları eksik olduğunda connect() başarısız olur.

connect() çağrısı başarısız olursa uygulamanızın bağlantı hatasını doğru şekilde ele aldığından emin olun. Google Play Hizmetleri'nin kendisinde izinler yoksa startResolutionForResult() yöntemini çağırarak bu izinleri düzeltecek kullanıcı akışını başlatabilirsiniz.

Örneğin:

@Override
public void onConnectionFailed(ConnectionResult result) {
    if (mResolvingError) {
        // Already attempting to resolve an error.
        return;
    } else if (result.hasResolution()) {
        try {
            mResolvingError = true;
            result.startResolutionForResult(this, REQUEST_RESOLVE_ERROR);
        } catch (SendIntentException e) {
            // There was an error with the resolution intent. Try again.
            mGoogleApiClient.connect();
        }
    } else {
        // Show dialog using GooglePlayServicesUtil.getErrorDialog()
        showErrorDialog(result.getErrorCode());
        mResolvingError = true;
    }
}

Daha yeni GoogleApi tabanlı API çağrıları, kullanıcının izin çözümleme amacını başlatmak için dokunabileceği bir iletişim kutusu (istemci bir Activity ile örneklendiyse) veya sistem tepsisi bildirimi (istemci bir Context ile örneklendiyse) görüntüler. Aramalar sıraya alınır ve izin verildikten sonra yeniden denenir.