Android 개인 정보 보호 Codelab

1. 소개

학습할 내용

  • 사용자의 개인 정보 보호가 점점 더 중요해지고 있는 이유
  • 지난 몇 차례 출시에 걸친 Android 개인 정보 보호 권장사항
  • 개인 정보 보호 권장사항을 기존 앱에 통합하여 개인 정보를 더욱 안전하게 보호하는 방법

빌드할 항목

이 Codelab에서는 사용자가 추억 모음을 저장할 수 있는 샘플 앱으로 시작합니다.

다음 화면에서 시작합니다.

  • 권한 화면: 홈 화면으로 진행하기 전에 사용자에게 모든 권한을 부여하도록 요청하는 화면입니다.
  • 홈 화면: 사용자의 기존 사진 로그가 모두 표시되고 사용자가 새 사진 로그를 추가할 수도 있는 화면입니다.
  • 로그 추가 화면: 사용자가 새 사진 로그를 만들 수 있는 화면입니다. 여기에서 사용자는 라이브러리의 기존 사진을 탐색하고 카메라를 사용하여 새 사진을 찍고 사진 로그에 현재 도시를 추가할 수 있습니다.
  • 카메라 화면: 사용자가 사진을 찍어 사진 로그에 저장할 수 있는 화면입니다.

앱이 작동하지만 함께 개선할 개인 정보 보호 허점이 많이 있습니다.

Codelab을 진행하면서 다음 내용을 알아봅니다.

  • 앱에서 개인 정보 보호가 중요한 이유
  • Android의 개인 정보 보호 기능과 주요 권장사항
  • 다음을 실행하여 기존 앱에서 이러한 권장사항을 구현하는 방법
  • 컨텍스트 내에서 권한 요청
  • 앱의 위치 정보 액세스 권한 줄이기
  • 사진 선택 도구 및 기타 저장소 개선사항 사용
  • 데이터 액세스 분석 API 사용

완료되면 다음과 같은 앱이 생성됩니다.

  • 위에 나열된 개인 정보 보호 권장사항을 구현합니다.
  • 개인 정보를 보호하고 비공개 데이터를 신중히 처리하여 사용자를 보호하므로 사용자 환경을 개선합니다.

필요한 항목

도움이 될 지식

2. 개인 정보 보호가 중요한 이유는 무엇인가요?

연구에 따르면 사람들은 개인 정보 보호를 걱정합니다. Pew Research Institute에서 실시한 설문조사에 따르면 미국인 중 84%가 회사와 앱에서 수집한 데이터에 관한 제어 권한이 거의 없다고 생각합니다. 사용자가 느끼는 가장 큰 문제점은 직접적인 사용 외에 데이터가 어떻게 처리되는지 모른다는 것입니다. 예를 들어 타겟팅 광고를 위한 프로필을 만들거나 다른 당사자에게 판매하는 등의 다른 목적으로 데이터가 사용될까 걱정합니다. 만일 데이터가 유출되었다면 삭제하는 방법이 있을지도 걱정합니다.

이러한 개인 정보 보호에 관한 우려는 사용할 서비스나 앱을 결정하는 데 이미 큰 영향을 미치고 있습니다. 실제로 동일한 Pew Research Institute 연구에 따르면 미국 성인의 절반 이상(52%)이 자신에 관해 수집되는 데이터의 양을 우려하는 등 개인 정보 보호 문제로 인해 제품이나 서비스를 사용하지 않기로 했습니다.

따라서 사용자의 앱 경험을 개선하기 위해 앱의 개인 정보 보호를 강화하고 보여주는 것이 필요하며 연구에 따르면 이를 통해 사용자층도 확장할 수 있습니다.

이 Codelab에서 다룰 기능과 권장사항은 대부분 앱에서 액세스하는 데이터의 양을 줄이거나 비공개 데이터에 관한 사용자의 제어 능력을 향상하는 것과 직접 관련이 있습니다. 이 두 가지 개선사항은 모두 앞서 확인한 연구에서 사용자가 공유한 우려사항을 직접적으로 해결합니다.

3. 환경 설정

Google에서 준비한 시작 프로젝트를 사용하면 신속하게 빌드할 수 있습니다. 이 단계에서는 시작 프로젝트를 포함하여 전체 Codelab의 코드를 다운로드하고 에뮬레이터나 기기에서 시작 앱을 실행합니다.

git을 설치했다면 아래 명령어를 실행하면 됩니다. git이 설치되어 있는지 확인하려면 터미널이나 명령줄에 git –version을 입력하여 올바르게 실행되는지 확인합니다.

git clone https://github.com/android/privacy-codelab

git이 없는 경우 다운로드 링크를 클릭하면 이 Codelab을 위한 모든 코드를 다운로드할 수 있습니다.

Codelab을 설정하려면 다음 단계를 따르세요.

  1. Android 스튜디오의 PhotoLog_Start 디렉터리에서 프로젝트를 엽니다.
  2. Android 12(S) 이상을 실행하는 기기나 에뮬레이터에서 PhotoLog_Start 실행 구성을 실행합니다.

d98ce953b749b2be.png

앱을 실행할 권한을 부여하라는 화면이 표시됩니다. 이는 환경을 성공적으로 설정했다는 의미입니다.

4. 권장사항: 컨텍스트 내에서 권한 요청

대부분의 개발자는 런타임 권한을 통해 우수한 사용자 환경을 제공하는 데 중요한 여러 핵심 기능을 활용할 수 있다는 사실을 알고 있습니다. 그러나 앱에서 런타임 권한을 요청하는 시점과 방식이 사용자 환경에 큰 영향을 미친다는 사실도 알고 있나요?

PhotoLog_Start 앱이 권한을 요청하는 방식을 살펴보고 권한 모델이 최적이 아닌 이유를 알아봅니다.

  1. 실행 직후 사용자에게는 여러 권한을 부여하도록 요청하는 권한 메시지가 즉시 표시됩니다. 이는 사용자에게 혼란을 야기할 수 있으며 앱에 대한 신뢰를 잃거나 최악의 경우 앱을 제거할 수 있습니다.
  2. 앱은 모든 권한이 부여될 때까지 사용자가 계속 진행하도록 허용하지 않습니다. 사용자는 실행 시 이러한 모든 민감한 정보에 대한 액세스 권한을 부여할 정도로 앱을 신뢰하지 않을 수 있습니다.

짐작했겠지만 위의 목록은 앱의 권한 요청 프로세스를 개선하기 위해 함께 개선할 사항을 나타냅니다. 그럼, 시작하겠습니다.

Android의 권장사항에 따르면 사용자가 기능과 처음 상호작용을 시작할 때 컨텍스트 내에서 권한을 요청해야 합니다. 그 이유는 앱이 사용자가 이미 상호작용 중인 기능을 사용 설정하려고 권한을 요청하는 경우 이 요청은 사용자에게 놀랍지 않기 때문입니다. 따라서 사용자 환경이 개선됩니다. PhotoLog 앱에서는 사용자가 카메라 버튼이나 위치 버튼을 처음 클릭할 때까지 기다린 후에 권한을 요청해야 합니다.

먼저 사용자가 홈페이지로 이동하기 전에 모든 권한을 승인하도록 강제하는 권한 화면을 삭제하겠습니다. 이 로직은 현재 MainActivity.kt에 정의되어 있으므로 이 위치로 이동하겠습니다.

val startNavigation =
   if (permissionManager.hasAllPermissions) {
       Screens.Home.route
   } else {
       Screens.Permissions.route
   }

홈페이지로 이동하도록 허용하기 전에 사용자가 모든 권한을 부여했는지 확인합니다. 앞서 언급했듯이 이는 사용자 환경 권장사항을 따르지 않습니다. 다음 코드로 변경하여 사용자가 모든 권한을 부여하지 않고도 앱과 상호작용할 수 있도록 해 보겠습니다.

val startNavigation = Screens.Home.route

이제 권한 화면이 더 이상 필요하지 않으므로 NavHost에서 다음 줄도 삭제할 수 있습니다.

composable(Screens.Permissions.route) { PermissionScreen(navController) }

다음으로 Screens 클래스에서 다음 줄을 삭제합니다.

object Permissions : Screens("permissions")

마지막으로 PermissionsScreen.kt 파일도 삭제하면 됩니다.

이제 앱을 삭제하고 다시 설치합니다. 이전에 부여된 권한을 재설정하는 한 가지 방법입니다. 지금 바로 홈 화면으로 이동할 수 있지만 'Add Log' 화면에서 카메라 버튼이나 위치 버튼을 눌러도 아무 일도 일어나지 않습니다. 앱에 더 이상 사용자에게 권한을 요청하는 로직이 없기 때문입니다. 이 문제를 해결해 보겠습니다.

카메라 권한을 요청하는 로직 추가

카메라 권한부터 시작하겠습니다. 권한 요청 문서에 나와 있는 코드 샘플을 바탕으로 RequestPermission() 계약을 사용하기 위해 먼저 권한 콜백을 등록해야 합니다.

필요한 로직을 평가해 보겠습니다.

  • 사용자가 권한을 허용하면 viewModel에 권한을 등록하고, 사용자가 이미 추가된 사진 수 한도에 아직 도달하지 않은 경우 카메라 화면으로 이동하려고 합니다.
  • 사용자가 권한을 거부하면 권한이 거부되어 기능이 작동하지 않는다고 알릴 수 있습니다.

이 로직을 실행하려면 다음 코드 블록을 // TODO: Step 1. Register ActivityResult to request Camera permission에 추가하면 됩니다.

val requestCameraPermission =
   rememberLauncherForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
       if (isGranted) {
           viewModel.onPermissionChange(CAMERA, isGranted)
           canAddPhoto {
               navController.navigate(Screens.Camera.route)
           }
       }
       else {
           coroutineScope.launch {
               snackbarHostState.showSnackbar("Camera currently disabled due to denied permission.")
           }
       }
   }

이제 카메라 화면으로 이동하기 전에 앱에 카메라 권한이 있는지 확인하고, 사용자가 아직 카메라 권한을 부여하지 않은 경우 권한을 요청하려고 합니다. 이 로직을 구현하려면 다음 코드 블록을 // TODO: Step 2. Check & request for Camera permission before navigating to the camera screen에 추가하면 됩니다.

canAddPhoto {
   when {
       state.hasCameraAccess -> navController.navigate(Screens.Camera.route)
       // TODO: Step 4. Trigger rationale screen for Camera if needed
       else -> requestCameraPermission.launch(CAMERA)
   }
}

이제 앱을 다시 실행하고 'Add Log' 화면에서 카메라 아이콘을 클릭합니다. 카메라 권한을 요청하는 대화상자가 표시됩니다. 훌륭합니다. 이 방법은 사용자가 앱을 사용해 보기도 전에 모든 권한을 승인하도록 요청하는 것보다 훨씬 효과적입니다.

하지만 더 개선할 수 있을까요? 물론입니다. 앱에 카메라 액세스 권한이 필요한 이유를 설명하는 근거를 표시하도록 시스템에서 권장하는지 확인할 수 있습니다. 이렇게 하면 권한 선택률을 높일 수 있으며 좀 더 적절한 시기에 권한을 다시 요청하는 앱의 기능도 유지할 수 있습니다.

이를 위해 앱에 사용자의 카메라 액세스 권한이 필요한 이유를 설명하는 근거 화면을 빌드해 보겠습니다. 다음 코드 블록을 // TODO: Step 3. Add explanation dialog for Camera permission에 추가하면 됩니다.

var showExplanationDialogForCameraPermission by remember { mutableStateOf(false) }
if (showExplanationDialogForCameraPermission) {
   CameraExplanationDialog(
       onConfirm = {
           requestCameraPermission.launch(CAMERA)
           showExplanationDialogForCameraPermission = false
       },
       onDismiss = { showExplanationDialogForCameraPermission = false },
   )
}

이제 대화상자 자체를 만들었으므로 카메라 권한을 요청하기 전에 근거를 표시해야 하는지 확인하기만 하면 됩니다. 이를 위해 ActivityCompat의 shouldShowRequestPermissionRationale() API를 호출합니다. true를 반환하면 설명 대화상자를 표시하기 위해 showExplanationDialogForCameraPermission도 true로 설정하기만 하면 됩니다.

state.hasCameraAccess 사례와 else 사례 사이에 또는 다음 TODO(// TODO: Step 4. Add explanation dialog for Camera permission)가 이전에 안내에서 추가된 위치에 다음 코드 블록을 추가해 보겠습니다.

ActivityCompat.shouldShowRequestPermissionRationale(context.getActivity(),
           CAMERA) -> showExplanationDialogForCameraPermission = true

이제 카메라 버튼의 전체 로직은 다음과 같습니다.

canAddPhoto {
   when {
       state.hasCameraAccess -> navController.navigate(Screens.Camera.route)
       ActivityCompat.shouldShowRequestPermissionRationale(context.getActivity(),
           CAMERA) -> showExplanationDialogForCameraPermission = true
       else -> requestCameraPermission.launch(CAMERA)
   }
}

축하합니다! Android의 모든 권장사항을 준수하면서 카메라 권한을 처리했습니다. 앱을 다시 한번 삭제하고 설치한 후 'Add Log' 페이지에서 카메라 버튼을 눌러 보세요. 권한을 거부하더라도 앱에서 사진 앨범 열기와 같은 다른 기능을 사용하지 못하도록 차단하지 않습니다.

그러나 권한을 거부한 후 다시 카메라 아이콘을 클릭하면 조금 전에 추가한 설명 메시지가 표시됩니다.* 시스템 권한 메시지는 사용자가 설명 메시지에서 '계속'을 클릭한 후에만 표시되며 사용자가 '나중에'를 클릭하면 추가적인 중단 없이 앱을 사용할 수 있게 됩니다. 이렇게 하면 앱에서 사용자의 추가적인 권한 거부를 방지할 수 있으며 사용자가 좀 더 권한을 부여할 준비가 되었을 수 있는 다른 때에 권한을 다시 요청하는 기능을 유지할 수 있습니다.

  • 참고: shouldShowRequestPermissionRationale() API의 정확한 동작은 내부 구현 세부정보이며 변경될 수 있습니다.

위치 정보 액세스 권한을 요청하는 로직 추가

이제 위치에도 동일한 작업을 해 보겠습니다. 먼저 // TODO: Step 5. Register ActivityResult to request Location permissions에 다음 코드 블록을 추가하여 위치 정보 액세스 권한의 ActivityResult를 등록합니다.

val requestLocationPermissions =
   rememberLauncherForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
       if (isGranted) {
           viewModel.onPermissionChange(ACCESS_COARSE_LOCATION, isGranted)
           viewModel.onPermissionChange(ACCESS_FINE_LOCATION, isGranted)
           viewModel.fetchLocation()
       }
       else {
           coroutineScope.launch {
               snackbarHostState.showSnackbar("Location currently disabled due to denied permission.")
           }
       }
   }

그런 다음 // TODO: Step 6. Add explanation dialog for Location permissions에 다음 코드 블록을 추가하여 위치 정보 액세스 권한의 설명 대화상자를 추가합니다.

var showExplanationDialogForLocationPermission by remember { mutableStateOf(false) }
if (showExplanationDialogForLocationPermission) {
   LocationExplanationDialog(
       onConfirm = {
           // TODO: Step 10. Change location request to only request COARSE location.
           requestLocationPermissions.launch(arrayOf(ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION))
           showExplanationDialogForLocationPermission = false
       },
       onDismiss = { showExplanationDialogForLocationPermission = false },
   )
}

이제 위치 정보 액세스 권한을 확인하고 설명한 후(필요한 경우) 요청합니다. 권한이 부여되면 위치 정보를 가져와 사진 로그를 채울 수 있습니다. 다음 코드 블록을 // TODO: Step 7. Check, request, and explain Location permissions에 추가해 보겠습니다.

when {
   state.hasLocationAccess -> viewModel.fetchLocation()
   ActivityCompat.shouldShowRequestPermissionRationale(context.getActivity(),
       ACCESS_COARSE_LOCATION) ||
   ActivityCompat.shouldShowRequestPermissionRationale(
       context.getActivity(), ACCESS_FINE_LOCATION) ->
       showExplanationDialogForLocationPermission = true
   else -> requestLocationPermissions.launch(arrayOf(ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION))
}

이제 이 Codelab의 권한 섹션을 마쳤습니다. 앱을 재설정하고 결과를 확인해 보세요.

사용자 환경을 개선한 방법과 앱의 이점을 요약하면 다음과 같습니다.

  • 앱 실행 직후가 아닌 사용자가 기능과 상호작용할 때 컨텍스트 내에서 권한 요청 → 혼동 및 사용자 이탈 감소
  • 사용자에게 앱이 권한에 액세스해야 하는 이유를 설명하는 설명 화면 제작 → 사용자를 위한 투명성 개선
  • shouldShowRequestPermissionRationale() API를 활용하여 시스템에서 앱이 설명 화면을 표시해야 한다고 판단하는 시점을 결정 → 권한 수락률 증가 및 영구적인 권한 거부 확률 감소

5. 권장사항: 앱의 위치 액세스 줄이기

위치는 가장 민감한 권한 중 하나이므로 Android에서는 개인 정보 대시보드에 이를 포함합니다.

간단히 요약하자면 Android 12에서는 사용자에게 위치에 관한 추가 관리 기능을 제공했습니다. 이제 사용자는 앱에서 위치 액세스를 요청할 때 정확한 위치 대신 대략적인 위치를 선택하여 덜 정확한 위치 데이터를 앱에 공유하도록 명확하게 선택할 수 있습니다.

대략적인 위치는 앱에 사용자 위치 추정치를 3제곱킬로미터 이내로 제공하며 이는 많은 앱 기능에 충분한 정밀도입니다. 위치 액세스가 필요한 앱의 모든 개발자는 사용 사례를 검토하고 사용자가 정확한 위치가 필요한 기능과 활발히 상호작용하고 있는 경우에만 ACCESS_FINE_LOCATION을 요청하는 것이 좋습니다.

ea5cc51fce3f219e.png

캘리포니아 로스앤젤레스 시내 중심에서 대략적인 위치 추정 범위를 시각화한 그래픽

대략적인 위치 액세스만으로도 PhotoLog 앱에 충분합니다. '추억'의 출처를 상기시키는 데는 사용자의 도시만 필요하기 때문입니다. 그러나 앱에서는 현재 사용자에게 ACCESS_COARSE_LOCATIONACCESS_FINE_LOCATION을 모두 요청하고 있습니다. 변경해 보겠습니다.

먼저 위치의 활동 결과를 수정하고 ActivityResultContracts.RequestMultiplePermissions() 대신 ActivityResultContracts.RequestPermission() 함수를 매개변수로 제공하여 ACCESS_COARSE_LOCATION만 요청한다는 사실을 반영해야 합니다.

현재 requestLocationsPermissions 객체(// TODO: Step 8. Change activity result to only request Coarse Location으로 표시됨)를 대신 다음 코드 블록으로 바꿉니다.

val requestLocationPermissions =
   rememberLauncherForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
       if (isGranted) {
           viewModel.onPermissionChange(ACCESS_COARSE_LOCATION, isGranted)
       }
   }

다음으로 두 위치 정보 액세스 권한 대신 ACCESS_COARSE_LOCATION만 요청하도록 launch() 메서드를 변경합니다.

다음을

requestLocationPermissions.launch(arrayOf(ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION))

아래와 같이 바꿉니다.

requestLocationPermissions.launch(ACCESS_COARSE_LOCATION)

PhotoLog에는 변경해야 하는 launch() 메서드의 인스턴스가 2개 있습니다. 하나는 // TODO: Step 9. Change location request to only request COARSE location으로 표시된 LocationExplanationDialogonConfirm() 로직에 있고 하나는 // TODO: Step 10. Change location request to only request COARSE location으로 표시된 'Location' 목록 항목에 있습니다.

마지막으로 이제 더 이상 PhotoLog의 ACCESS_FINE_LOCATION 권한을 요청하지 않으므로 AddLogViewModel.kt의 onPermissionChange() 메서드에서 이 섹션을 삭제합니다.

Manifest.permission.ACCESS_FINE_LOCATION -> {
   uiState = uiState.copy(hasLocationAccess = isGranted)
}

앱의 매니페스트에서 ACCESS_FINE_LOCATION도 삭제해야 합니다.

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

이제 이 Codelab의 위치 섹션을 마쳤습니다. 앱을 제거/재설치한 후 결과를 확인해 보세요.

6. 권장사항: 저장소 권한 사용 최소화

일반적으로 앱은 기기에 저장된 사진과 함께 작동합니다. 사용자가 원하는 이미지와 동영상을 선택할 수 있도록 이러한 앱은 자체 파일 선택 도구를 구현하는 경우가 많으며, 이 경우 앱에서는 광범위한 저장소 액세스 권한을 요청해야 합니다. 사용자는 모든 사진에 대한 액세스 권한을 부여하는 것을 좋아하지 않으며 개발자는 자체 파일 선택 도구를 유지관리하는 것을 원하지 않습니다.

Android 13에서는 사용자가 사용자의 전체 미디어 라이브러리 액세스 권한을 앱에 부여하지 않고도 미디어 파일을 선택할 수 있는 방법을 제공하는 사진 선택 도구가 도입되었습니다. 또한 Google Play 시스템 업데이트를 통해 Android 11 및 12로 백포팅됩니다.

PhotoLog 앱의 기능에는 PickMultipleVisualMedia ActivityResultContract를 사용합니다. 기기에 있는 경우 Android 사진 선택 도구를 사용하며 이전 기기의 ACTION_OPEN_DOCUMENT 인텐트를 사용합니다.

먼저 AddLogScreen 파일에 ActivityResultContract를 등록해 보겠습니다. 등록하려면 이 줄(// TODO: Step 11. Register ActivityResult to launch the Photo Picker) 뒤에 다음 코드 블록을 추가합니다.

val pickImage = rememberLauncherForActivityResult(
   PickMultipleVisualMedia(MAX_LOG_PHOTOS_LIMIT),
    viewModel::onPhotoPickerSelect
)

참고: 여기서 MAX_LOG_PHOTOS_LIMIT는 로그에 추가할 때 설정할 수 있는 사진의 최대 한도(여기서는 3)를 나타냅니다.

이제 앱에 있던 내부 선택 도구를 Android 사진 선택 도구로 대체해야 합니다. 블록(// TODO: Step 12. Replace the below line showing our internal UI by launching the Android Photo Picker instead) 뒤에 다음 코드를 추가합니다.

pickImage.launch(PickVisualMediaRequest(PickVisualMedia.ImageOnly))

이 두 줄의 코드를 추가함으로써 이제 권한 없이 기기 사진에 액세스하는 방법이 생겼습니다. 이 방법을 통해 UX는 훨씬 개선되고 코드를 유지관리하지 않아도 됩니다.

PhotoLog에는 더 이상 사진에 액세스하기 위해 기존 사진 그리드와 저장소 권한이 필요하지 않으므로 이제 매니페스트의 저장소 권한 항목에서 그 뒤에 있는 로직에 이르기까지 기존 사진 그리드를 포함하는 모든 코드를 삭제해야 합니다. 더 이상 앱에 필요하지 않기 때문입니다.

7. 권장: 디버그 빌드에서 데이터 액세스 분석 API 사용

기능과 공동작업자가 많은 큰 앱이 있고(또는 앞으로 큰 앱이 될 것으로 예상함) 그로 인해 앱에서 액세스하는 사용자 데이터의 종류를 추적하기 어렵나요? 데이터 액세스가 한때 사용되었지만 지금은 앱에 남아 있기만 한 API 또는 SDK에서 비롯되더라도 앱은 여전히 데이터 액세스에 대한 책임을 져야 한다는 사실을 알고 있나요?

포함된 모든 SDK와 기타 종속 항목을 비롯하여 앱이 비공개 데이터에 액세스하는 모든 위치를 추적하는 것은 어렵다는 점을 잘 알고 있습니다. 따라서 앱 및 앱의 종속 항목이 사용자의 비공개 데이터에 액세스하는 방식을 더 투명하게 파악할 수 있도록 Android 11에서는 데이터 액세스 분석을 도입합니다. 이 API를 사용하면 개발자는 다음 이벤트 중 하나가 발생할 때마다 로그 파일로 출력하는 등의 특정 작업을 실행할 수 있습니다.

  • 앱의 코드가 비공개 데이터에 액세스합니다.
  • 종속 라이브러리 또는 SDK의 코드가 비공개 데이터에 액세스합니다.

먼저 Android에서 데이터 액세스 분석 API가 작동하는 방식의 기본사항을 살펴보겠습니다. 데이터 액세스 분석을 채택하려면 AppOpsManager.OnOpNotedCallback의 인스턴스를 등록합니다(Android 11 이상을 타겟팅해야 함).

또한 콜백의 세 가지 메서드를 재정의해야 합니다. 이는 앱이 다양한 방식으로 사용자 데이터에 액세스할 때 시스템에서 호출됩니다. 세 가지 메서드는 다음과 같습니다.

  • onNoted(): 앱이 사용자 데이터에 액세스하는 동기(양방향 바인딩) API를 호출할 때 호출됩니다. 이는 일반적으로 콜백이 필요 없는 API 호출입니다.
  • onAsyncNoted(): 앱이 사용자 데이터에 액세스하는 비동기(단방향 바인딩) API를 호출할 때 호출됩니다. 이는 일반적으로 콜백이 필요한 API 호출이며 콜백이 호출될 때 데이터 액세스가 발생합니다.
  • onSelfNoted(): 호출 가능성이 매우 낮습니다. 예를 들어 앱이 자체 UID를 noteOp()에 전달할 때 발생합니다.

이제 이러한 메서드 중 PhotoLog 앱의 데이터 액세스에 적용되는 메서드를 결정해 보겠습니다. PhotoLog는 주로 두 위치에서 사용자 데이터에 액세스합니다. 카메라를 활성화할 때 한 번, 사용자의 위치에 액세스할 때 한 번입니다. 둘 다 비교적 리소스 집약적이므로 모두 비동기 API 호출입니다. 따라서 각 사용자 데이터에 액세스할 때 시스템에서는 onAsyncNoted()를 호출할 것으로 예상됩니다.

PhotoLog용 데이터 액세스 분석 API를 채택하는 방법을 살펴보겠습니다.

먼저 AppOpsManager.OnOpNotedCallback()의​​ 인스턴스를 만들고 위의 세 가지 메서드를 재정의해야 합니다.

객체의 세 가지 메서드에서 모두 비공개 사용자 데이터에 액세스한 특정 작업을 기록해 보겠습니다. 이 작업에는 액세스한 사용자 데이터의 종류에 관한 자세한 정보가 포함됩니다. 또한 앱이 카메라 및 위치 정보에 액세스할 때 onAsyncNoted()가 호출될 것으로 예상되므로 특별하게 위치 액세스용 지도 이모티콘과 카메라 액세스용 카메라 이모티콘을 기록해 보겠습니다. 다음 코드 블록을 // TODO: Step 1. Create Data Access Audit Listener Object에 추가하면 됩니다.

@RequiresApi(Build.VERSION_CODES.R)
object DataAccessAuditListener : AppOpsManager.OnOpNotedCallback() {
   // For the purposes of this codelab, we are just logging to console,
   // but you can also integrate other logging and reporting systems here to track
   // your app's private data access.
   override fun onNoted(op: SyncNotedAppOp) {
       Log.d("DataAccessAuditListener","Sync Private Data Accessed: ${op.op}")
   }

   override fun onSelfNoted(op: SyncNotedAppOp) {
       Log.d("DataAccessAuditListener","Self Private Data accessed: ${op.op}")
   }

   override fun onAsyncNoted(asyncNotedAppOp: AsyncNotedAppOp) {
       var emoji = when (asyncNotedAppOp.op) {
           OPSTR_COARSE_LOCATION -> "\uD83D\uDDFA"
           OPSTR_CAMERA -> "\uD83D\uDCF8"
           else -> "?"
       }

       Log.d("DataAccessAuditListener", "Async Private Data ($emoji) Accessed:
       ${asyncNotedAppOp.op}")
   }
}

그런 다음 방금 만든 콜백 로직을 구현해야 합니다. 최상의 결과를 얻으려면 최대한 이른 시기에 실행하는 것이 좋습니다. 콜백을 등록한 후에만 시스템에서 데이터 액세스 추적을 시작하기 때문입니다. 콜백을 등록하려면 다음 코드 블록을 // TODO: Step 2. Register Data Access Audit Callback.에 추가하면 됩니다.

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
   val appOpsManager = getSystemService(AppOpsManager::class.java) as AppOpsManager
   appOpsManager.setOnOpNotedCallback(mainExecutor, DataAccessAuditListener)
}

8. 결론

지금까지 다룬 내용을 요약하면 다음과 같습니다.

  • 앱에서 개인 정보 보호가 중요한 이유
  • Android의 개인 정보 보호 기능
  • 앱의 다양한 주요 개인 정보 보호 권장사항 구현. 방법은 다음과 같습니다.
  • 컨텍스트 내에서 권한 요청
  • 앱의 위치 정보 액세스 권한 줄이기
  • 사진 선택 도구 및 기타 저장소 개선사항 사용
  • 데이터 액세스 분석 API 사용
  • 기존 앱에서 이러한 권장사항을 구현하여 개인 정보 보호 강화

PhotoLog의 개인 정보 보호 및 사용자 환경을 개선하고 그 과정에서 많은 개념을 학습하는 여정이 즐거웠길 바랍니다.

참조 코드를 찾는 방법은 다음과 같습니다(선택사항).

아직 살펴보지 않았다면 PhotoLog_End 폴더에서 이 Codelab의 솔루션 코드를 살펴볼 수 있습니다. 이 Codelab의 안내를 잘 따랐다면 PhotoLog_Start 폴더의 코드는 PhotoLog_End 폴더의 코드와 동일해야 합니다.

자세히 알아보기

이제 완료됐습니다. 위에서 설명한 권장사항에 관해 자세히 알아보려면 Android 개인 정보 보호 방문 페이지를 확인하세요.