Google Play 서비스 및 런타임 권한

Android 6.0 Marshmallow부터 Android는 앱 설치 및 자동 업데이트 프로세스를 간소화하는 권한 모델을 사용합니다. 권한은 앱 설치 전이 아닌 런타임에 요청됩니다. 또한 사용자는 특정 권한을 거부할 수 있습니다. 사용자에게 이러한 유연성을 제공하려면 사용자가 특정 권한을 사용 설정하거나 사용 중지할 때 앱이 예상대로 작동하는지 확인해야 합니다.

Google Play 서비스 자체에는 런타임 권한이 있으며, 사용자는 앱에서 구체적으로 요청한 권한과 별도로 이를 거부할 수 있습니다. Google Play 서비스는 API를 지원하는 데 필요한 모든 권한을 자동으로 가져옵니다. 하지만 앱은 여전히 필요한 경우 런타임 권한을 확인하고 요청해야 하며 사용자가 앱에서 사용하는 API에 필요한 권한을 Google Play 서비스에 거부한 경우에는 오류를 적절하게 처리해야 합니다.

런타임에 필요할 수 있는 권한을 설정할 때 사용자의 기대치를 관리하는 것이 좋습니다. 다음 권장사항을 따르면 잠재적인 문제를 방지할 수 있습니다.

기본 요건

AndroidManifest.xml 파일에서 권한을 선언해야 합니다. 예를 들면 다음과 같습니다.

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

가이드라인

API를 호출하기 전에 권한 확인

AndroidManifest.xml 파일에서 사용하려는 API를 선언한 후에는 API를 호출하기 전에 필요한 권한이 있는지 확인합니다. ActivityCompat 또는 ContextCompatcheckSelfPermission 메서드를 사용하여 이 작업을 실행할 수 있습니다.

호출이 false를 반환하면 권한이 부여되지 않았음을 의미하며 requestPermissions를 사용하여 권한을 요청해야 합니다. 이에 대한 응답은 다음 단계에서 확인할 수 있는 콜백으로 반환됩니다.

예를 들면 다음과 같습니다.

Kotlin

    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
        != PackageManager.PERMISSION_GRANTED) {
            // Request Permissions Now
            ActivityCompat.requestPermissions(
                this,
                arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
                REQUEST_LOCATION_PERMISSION_CODE)
    } else {
        // permission has been granted, continue as usual
        val locationResult = LocationServices
            .getFusedLocationProviderClient(this /* Context */)
            .lastLocation
    }

자바

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

요청 권한 콜백 구현

앱에 필요한 권한이 사용자에 의해 부여되지 않은 경우 requestPermissions 메서드를 호출하여 사용자에게 권한을 부여하도록 요청해야 합니다. 사용자의 응답은 onRequestPermissionsResult 콜백에 캡처됩니다. 요청이 거부되거나 취소될 수 있으므로 앱은 이를 구현하고 항상 반환 값을 확인해야 합니다. 여러 권한을 한 번에 요청하고 확인할 수도 있습니다. 다음 샘플은 단일 권한만 확인합니다.

Kotlin

    fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array,
        grantResults: IntArray
    ) {
        if (requestCode == REQUEST_LOCATION_PERMISSION_CODE) {
            if (grantResults.singleOrNull() == PackageManager.PERMISSION_GRANTED) {
               // We can now safely use the API we requested access to
               val locationResult: Task = LocationServices
                    .getFusedLocationProviderClient(this /* Context */)
                    .lastLocation // Request the last known location.
            } else {
                // Permission was denied or request was cancelled
            }
        }
    }

자바

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

권한 근거 표시

앱에서 요청하는 권한이 앱의 핵심 기능에 필요하고 사용자가 이전에 권한 요청을 거부한 경우 앱은 권한을 다시 요청하기 전에 추가 설명을 표시해야 합니다. 사용자가 권한이 필요한 이유와 즉각적인 이점을 이해하면 권한을 부여할 가능성이 더 높습니다.

이 경우 requestPermissions를 호출하기 전에 shouldShowRequestPermissionRationale를 호출해야 합니다. true를 반환하면 권한에 관한 추가 컨텍스트를 표시하는 UI를 만들어야 합니다.

예를 들어 코드는 다음과 같이 표시될 수 있습니다.

Kotlin

    private const val REQUEST_LOCATION_PERMISSION_CODE = 2
    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
        != PackageManager.PERMISSION_GRANTED) {
        // Check Permissions Now
        if ActivityCompat.shouldShowRequestPermissionRationale(
            this,
            Manifest.permission.ACCESS_FINE_LOCATION
        ) {
            // Display UI and wait for user interaction
        } else {
            ActivityCompat.requestPermissions(
                this,
                arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
                REQUEST_LOCATION_PERMISSION_CODE)
        }
    } else {
        // Permission has already been granted, continue as usual
        val locationResult: Task = LocationServices
            .getFusedLocationProviderClient(this /* Context */)
            .lastLocation
    }

자바

    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
        != PackageManager.PERMISSION_GRANTED) {
        // Check Permissions Now
        private static final int REQUEST_LOCATION_PERMISSION_CODE = 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},
                REQUEST_LOCATION_PERMISSION_CODE);
        }
    } else {
        // permission has been granted, continue as usual
        Task locationResult = LocationServices
            .getFusedLocationProviderClient(this /** Context */)
            .getLastLocation();
    }

Google Play 서비스 API 호출은 사용자가 탭하여 권한 확인 인텐트를 시작할 수 있는 대화상자 (클라이언트가 Activity로 인스턴스화된 경우) 또는 시스템 트레이 알림 (클라이언트가 Context로 인스턴스화된 경우)을 자동으로 표시합니다. 권한이 부여되면 호출이 큐에 추가되고 다시 시도됩니다.