1. 소개
최종 업데이트: 2023년 1월 4일
Play Integrity란 무엇인가요?
Play Integrity API를 사용하면 잠재적으로 위험하고 허위일 가능성이 있는 상호작용으로부터 앱과 게임을 보호할 수 있습니다. Play Integrity API를 사용하여 앱과 기기에 관한 무결성 확인 결과를 얻을 수 있으므로 적절한 조치를 취해 사기, 속임수, 무단 액세스와 같은 공격과 악용을 줄일 수 있습니다.
이전 솔루션
Play Integrity API는 이전의 두 가지 솔루션인 앱 라이선스 라이브러리와 SafetyNet Attestation API를 대체합니다. 새로운 애플리케이션에는 Play Integrity를 사용하는 것이 좋습니다. 이전 솔루션을 사용하는 기존 애플리케이션은 Play Integrity를 사용하도록 업데이트하는 것이 좋습니다.
경로 선택
Play Integrity에는 다음과 같이 다양한 종류의 앱을 위한 라이브러리 옵션이 포함되어 있습니다.
- C/C++로 작성된 게임 또는 기타 앱
- Kotlin 또는 Java 프로그래밍 언어로 작성된 앱
- Unity 엔진으로 개발된 게임
이 Codelab에는 세 가지 옵션 모두의 경로가 포함되어 있습니다. 개발 요구사항과 관련된 경로를 선택할 수 있습니다. 이 Codelab에는 백엔드 서버를 빌드하고 배포하는 방법이 포함됩니다. 이 서버는 세 가지 앱 유형에서 모두 공유됩니다.
빌드할 항목
이 Codelab에서는 Play Integrity를 샘플 앱에 통합하고 API를 사용하여 기기 및 앱 무결성을 확인합니다. 무결성 확인 프로세스를 지원하는 데 사용되는 소형 백엔드 서버 애플리케이션을 배포합니다.
학습할 내용
- Play Integrity 라이브러리를 앱에 통합하는 방법
- Play Integrity API를 사용하여 무결성 검사를 실행하는 방법
- 서버를 사용하여 무결성 확인 결과를 안전하게 처리하는 방법
- 무결성 확인 결과를 해석하는 방법
이 Codelab에서는 Play Integrity에 중점을 둡니다. 관련 없는 개념과 코드 블록은 자세히 설명되지 않으며 복사하여 붙여넣을 수 있도록 제공됩니다.
필요한 항목
- 활성 Android 개발자 등록이 있고 Play Console에 액세스할 수 있으며 Google Cloud 콘솔에 액세스할 수 있는 Google 계정
- C++ 또는 Kotlin 경로의 경우 Android 스튜디오 2021.1.1 이상
- Unity 경로의 경우 Unity 2020 LTS 이상
- 컴퓨터에 연결되어 있고 개발자 옵션 및 USB 디버깅이 사용 설정된 Android 지원 기기
이 Codelab에는 Play Console에서 빌드에 서명하고 업로드하는 방법에 관한 리소스 링크가 포함되어 있지만 이 프로세스에 어느 정도 익숙하다고 가정합니다.
2. 코드 가져오기
이 Codelab 프로젝트는 Git 저장소에서 제공됩니다. 저장소의 상위 디렉터리에는 다음과 같은 4개의 디렉터리가 있습니다.
server
디렉터리: 배포할 예시 서버의 코드가 포함되어 있습니다.cpp
디렉터리: C++ 게임 또는 앱에 Play Integrity를 추가하는 Android 스튜디오 프로젝트가 포함되어 있습니다.kotlin
디렉터리: 표준 Android 앱에 Play Integrity를 추가하는 Android 스튜디오 프로젝트가 포함되어 있습니다.unity
디렉터리: Unity 프로젝트에 Play Integrity를 추가하기 위해 Unity 엔진의 2020 LTS 버전으로 만든 프로젝트가 포함되어 있습니다.
각 클라이언트 샘플 디렉터리에는 다음과 같이 하위 디렉터리가 두 개 있습니다.
start
디렉터리: 이 Codelab에서 수정할 프로젝트 버전이 있습니다.final
디렉터리: 이 Codelab을 마쳤을 때 표시되는 프로젝트와 일치하는 프로젝트 버전이 있습니다.
저장소 클론
명령줄에서 루트 add-play-integrity-codelab
디렉터리를 포함할 디렉터리로 변경한 후 다음 문법을 사용하여 GitHub에서 프로젝트를 클론합니다.
git clone https://github.com/android/add-play-integrity-codelab.git
종속 항목 추가(C++만 해당)
C++ 경로를 사용하려면 저장소 하위 모듈을 초기화하여, 사용자 인터페이스에 사용되는 Dear ImGui 라이브러리를 설정해야 합니다. 이렇게 하려면 명령줄에서 다음을 실행합니다.
- 작업 디렉터리를
add-play-integrity-codelab/cpp/start/third-party
로 변경합니다. git submodule update --init
3. 클라이언트 및 서버 기능 이해
Play Integrity 보안 모델의 핵심 요소는 유효성 검사 작업을 기기에서 개발자가 제어하는 보안 서버로 이동하는 것입니다. 서버에서 이러한 작업을 실행하면 보안 침해된 기기가 재전송 공격을 시도하거나 메시지 콘텐츠를 조작하는 등의 시나리오로부터 보호할 수 있습니다.
이 Codelab 샘플 서버는 예시용이며 편의상 프로덕션 환경에 바람직한 많은 기능이 포함되어 있지 않습니다. 생성된 값의 목록은 메모리에만 저장되며 영구 스토리지로 지원되지 않습니다. 서버 엔드포인트는 인증을 요구하도록 구성되어 있지 않습니다.
performCommand 엔드포인트
서버는 HTTP POST
요청을 통해 액세스되는 /performCommand
엔드포인트를 제공합니다. 요청 본문은 다음 키-값 쌍이 있는 JSON 페이로드여야 합니다.
{
"commandString": "command-here",
"tokenString": "token-here"
}
/performCommand
엔드포인트는 다음 키-값 쌍이 포함된 JSON 페이로드를 반환합니다.
{
"commandSuccess": true/false,
"diagnosticMessage": "summary text",
"expressToken": "token-here"
}
commandString
매개변수의 실제 콘텐츠는 중요하지 않습니다. Play Integrity를 사용할 때 서버에서 commandString
의 무결성을 검사하지만 명령어 값은 사용하지 않습니다. 모든 클라이언트 버전은 "TRANSFER FROM alice TO bob CURRENCY gems QUANTITY 1000"
값을 사용합니다.
tokenString
매개변수의 값은 다음 중 하나여야 합니다.
- Play Integrity API에서 생성한 토큰
- 이전에
/performCommand
를 호출한 후 반환된 익스프레스 토큰
서버는 Play Integrity API에서 제공하는 토큰을 복호화하고 검증합니다. 복호화 결과는 무결성 신호의 JSON 페이로드입니다. 신호의 값에 따라 서버에서 명령어를 승인하거나 거부할 수 있습니다. 토큰이 성공적으로 복호화되면 신호의 요약 설명이 diagnosticMessage
에서 반환됩니다. 이 정보는 일반적으로 프로덕션 애플리케이션에서 클라이언트에 반환하지 않지만 서버 로그를 확인하지 않고 작업 결과를 표시하기 위해 Codelab 클라이언트에서 사용합니다. 토큰을 처리하는 동안 오류 조건이 발생하면 diagnosticMessage
에서 오류가 반환됩니다.
nonce 생성
Play Integrity 요청을 하려면 nonce를 생성하고 이를 요청에 연결해야 합니다. nonce는 무결성 요청이 고유하고 한 번만 처리되도록 하는 데 사용됩니다. nonce는 무결성 요청과 연결된 메시지 콘텐츠가 조작되지 않았음을 확인하는 데도 사용됩니다. Play Integrity nonce에 관한 자세한 내용은 문서를 참고하세요.
이 Codelab에서는 nonce가 다음 두 값을 결합하여 생성됩니다.
- 암호화 방식으로 안전한 랜덤 숫자 생성기에서 생성된 128비트 랜덤 숫자
commandString
값의 SHA-256 해시
Play Integrity API는 nonce가 URL로 인코딩되고 패딩되지 않은 Base64 문자열일 것으로 예상합니다. 이 Codelab에서는 nonce 문자열을 만들기 위해 랜덤 숫자 및 해시 값의 바이트 배열을 16진수 문자열로 변환하여 연결합니다. 결과 문자열은 유효한 Base64 문자열이지만 그렇게 인코딩되거나 디코딩되지 않습니다.
Codelab 클라이언트는 HTTP GET
요청으로 서버에서 /getRandom
엔드포인트를 호출하여 랜덤 숫자를 가져옵니다. 이는 가장 안전한 무작위 생성 방법입니다. 서버가 명령 요청에 사용된 랜덤 숫자의 소스임을 확인할 수 있기 때문입니다. 하지만 이 경우 서버에 대한 추가 왕복이 필요합니다. 클라이언트는 보안에 대한 절충안으로 랜덤 숫자를 직접 생성함으로써 이러한 왕복을 제거할 수 있습니다.
익스프레스 토큰
PIA를 호출하는 것은 비용이 많이 들므로 서버는 익스프레스 토큰도 제공합니다. 보다 저렴한 비용으로 낮은 보안을 제공하는 대체 인증 방법입니다. 무결성 검사 통과와 함께 /serverCommand
호출이 성공하면 expressToken
필드에 익스프레스 토큰이 반환됩니다. Play Integrity API를 호출하는 것은 계산 비용이 많이 들며 중요한 작업을 보호하는 데 사용됩니다. 익스프레스 토큰을 반환하면 서버에서는 Play Integrity API로 전체 유효성 검사를 정당화하기에는 덜 중요하거나 너무 자주 발생할 수 있는 작업을 실행하기 위해 보안 수준이 낮은 인증을 제공합니다. /serverCommand
를 호출할 때 Play Integrity 토큰 대신 익스프레스 토큰을 사용할 수 있습니다. 각 익스프레스 토큰은 일회용입니다. 유효한 익스프레스 토큰을 사용하여 /serverCommand
를 성공적으로 호출하면 새 익스프레스 토큰이 반환됩니다.
Codelab 구현에서는 익스프레스 토큰이 서버에서 고유하게 생성되므로 명령어가 재전송 공격으로부터 계속 보호됩니다. 하지만 익스프레스 토큰은 명령어 수정에 대한 해싱 보호를 생략하고 Play Integrity API를 처음 호출한 후 발생한 기기 수정을 감지할 수 없으므로 보안 수준이 낮습니다.
Codelab 서버 아키텍처
이 Codelab에서는 Ktor 프레임워크를 사용하여 Kotlin으로 작성된, 포함된 샘플 서버 프로그램을 사용하여 서버를 인스턴스화할 수 있습니다. 프로젝트에는 Google Cloud App Engine에 배포할 구성 파일이 포함됩니다. 이 Codelab의 안내에서는 App Engine에 빌드하고 배포하는 방법을 설명합니다. 다른 클라우드 제공업체를 사용하는 경우 Ktor에 여러 클라우드 서비스에 관한 배포 안내가 있습니다. 적절하게 프로젝트를 수정하여 원하는 서비스에 배포하면 됩니다. 자체 로컬 서버 인스턴스에 배포하는 것은 추가 옵션입니다.
서버에 샘플 코드를 사용할 필요는 없습니다. 선호하는 웹 애플리케이션 프레임워크가 있다면 Codelab 샘플 서버를 가이드로 사용하여 자체 프레임워크에서 /getRandom
및 /performCommand
엔드포인트를 구현할 수 있습니다.
클라이언트 설계
세 가지 클라이언트 버전인 C++, Kotlin, Unity 엔진은 모두 유사한 사용자 인터페이스를 제공합니다.
Request random 버튼은 서버에서 /getRandom
엔드포인트를 호출합니다. 결과가 텍스트 필드에 표시됩니다. 이는 Play Integrity 통합을 추가하기 전에 서버 연결 및 기능을 확인하는 데 사용할 수 있습니다.
Call server with integrity check 버튼은 Codelab을 시작할 때 아무것도 하지 않습니다. 다음 작업의 코드를 추가하는 단계를 따릅니다.
/getRandom
을 호출하여 랜덤 숫자 얻기- nonce 생성
- nonce를 사용하여 Play Integrity 요청 만들기
- Play Integrity 요청으로 생성된 토큰을 사용하여
/performCommand
호출 /performCommand
결과 표시
명령어 결과는 텍스트 필드에 표시됩니다. 성공적인 명령어의 경우 이것은 Play Integrity 검사에서 반환된 기기 확인 결과 정보의 요약입니다.
Call server with integrity check 작업이 완료되면 Call server with express token 버튼이 표시됩니다. 이전 /performCommand
의 익스프레스 토큰을 사용하여 /performCommand
를 호출합니다. 텍스트 필드는 명령어의 성공 또는 실패를 표시하는 데 사용됩니다. 반환된 익스프레스 토큰의 값은 랜덤 숫자에 사용되는 텍스트 필드에 표시됩니다.
오류를 보고하는 Play Integrity API 기능은 오류 코드를 반환하여 이를 실행합니다. 이러한 오류 코드에 관한 자세한 내용은 Play Integrity 문서를 참고하세요. 일부 오류는 불안정한 인터넷 연결이나 과부하된 기기와 같은 환경 조건으로 인해 발생할 수 있습니다. 이러한 오류의 경우 지수 백오프로 재시도 옵션을 포함하는 것이 좋습니다. 이 Codelab에서는 Play Integrity 오류가 Logcat에 출력됩니다.
4. Google Cloud App Engine 설정
Google Cloud를 사용하려면 다음 단계를 따르세요.
- Google Cloud Platform에 등록합니다. Play Console에 등록된 동일한 Google 계정을 사용합니다.
- 결제 계정을 만듭니다.
- Google Cloud SDK를 설치하고 초기화합니다.
새로 설치된 Google Cloud CLI를 사용하여 다음 명령어를 실행하세요.
- Java용 App Engine 확장 프로그램(
gcloud components install app-engine-java
)을 설치합니다. - 새 Cloud 프로젝트를 만들어 다음 명령어의
$yourname
을 고유 식별자로 바꿉니다.gcloud projects create $yourprojectname --set-as-default
- Cloud 프로젝트에서 App Engine 애플리케이션을 만듭니다.
gcloud app create
5. 서버 배포
애플리케이션 패키지 이름 설정
이 단계에서는 서버 코드에 애플리케이션 패키지 이름을 추가합니다. 텍스트 편집기에서 ValidateCommand.kt
소스 파일을 엽니다. 다음 디렉터리에 있습니다.
add-play-integrity-codelab/server/src/main/kotlin/com/google/play/integrity/codelab/server/util
다음 줄을 찾아 자리표시자 텍스트를 고유한 패키지 식별자로 바꾼 후 파일을 저장합니다.
const val APPLICATION_PACKAGE_IDENTIFIER = "com.your.app.package"
나중에 Play Console에 앱을 업로드하기 전에 클라이언트 프로젝트에서 이 식별자를 설정합니다.
서버 빌드 및 App Engine에 배포
Google Cloud CLI를 사용하여 add-play-integrity/server
디렉터리에서 다음 명령어를 실행해 서버를 빌드하고 배포합니다.
Linux 또는 macOS:
./gradlew appengineDeploy
Microsoft Windows:
gradlew.bat appengineDeploy
배포 성공 시 출력에서 배포된 서비스 위치를 기록해 둡니다. 클라이언트가 서버와 통신하도록 구성하려면 이 URL이 필요합니다.
배포 확인
Google Cloud CLI를 사용하여 다음 명령어를 실행하면 서버가 올바르게 작동하는지 확인할 수 있습니다.
gcloud app browse
이 명령어를 통해 웹브라우저가 열리고 기준 URL이 열립니다. 기준 URL에서 액세스 시 샘플 서버에는 Hello World! 메시지가 표시됩니다.
6. Play Console에서 앱 구성
Play Console에서 앱 무결성 구성
Play Console에 기존 앱 항목이 있는 경우 이 Codelab에서 사용할 수 있습니다. 또는 Play Console에서 새 앱을 만드는 단계를 따릅니다. Play Console에서 앱을 선택하거나 만들고 나면 앱 무결성을 구성해야 합니다. Play Console의 왼쪽 메뉴에서 출시 섹션의 앱 무결성으로 이동합니다.
Google Cloud 프로젝트 만들기 및 연결
Cloud 프로젝트 연결 버튼을 클릭합니다. 서버에서 사용한 Google Cloud 프로젝트를 선택하고 프로젝트 연결 버튼을 클릭합니다.
서버의 Google Cloud 액세스
백엔드 서버는 Play Integrity API에 의해 클라이언트에서 생성된 무결성 토큰을 복호화해야 합니다. Play Integrity는 두 가지 키 관리 옵션을 제공합니다. Google에서 생성하고 관리하는 키와 개발자가 제공하는 키입니다. 이 Codelab에서는 Google 관리 키의 권장되는 기본 동작을 사용합니다.
Google 관리 키를 사용하면 백엔드 서버가 복호화를 위해 암호화된 무결성 토큰을 Google Play 서버에 전달합니다. Codelab 서버는 Google API 클라이언트 라이브러리를 사용하여 Google Play 서버와 통신합니다.
서버가 가동되고 Play Console에서 앱을 구성했으므로 선택한 플랫폼에 해당하는 클라이언트를 맞춤설정할 수 있습니다. 특정 플랫폼의 모든 단계는 함께 그룹화되므로 사용하지 않는 플랫폼의 안내는 건너뛸 수 있습니다.
7. 클라이언트 빌드 및 실행(C++)
Android 스튜디오를 실행합니다. Welcome to Android Studio 창에서 Open 버튼을 클릭하고 add-play-integrity-codelab/cpp/start
에 있는 Android 스튜디오 프로젝트를 엽니다.
애플리케이션 ID 업데이트
Google Play에 빌드를 업로드하기 전에 애플리케이션 ID를 기본값에서 고유한 값으로 변경해야 합니다. 다음 단계를 따르세요.
- Android 스튜디오의 Project 창에서
start/app
아래의build.gradle
파일을 찾아 엽니다. applicationId
문을 찾습니다.com.google.play.integrity.codelab.cpp
를 서버 배포 시 선택한 패키지 이름으로 변경한 후 파일을 저장합니다.- 파일 상단에 Gradle 파일이 변경되었음을 알려주는 배너가 표시됩니다. Sync Now를 클릭하여 파일을 새로고침하고 다시 동기화합니다.
- Android 스튜디오의 Project 창에서
start/app/src/main
아래의AndroidManifest.xml
파일을 엽니다. package="com.example.google.codelab.playintegritycpp"
문을 찾습니다.com.example.google.codelab.playintegritycpp
를 고유한 패키지 이름으로 바꾸고 파일을 저장합니다.- Android 스튜디오의 Project 창에서
start/app/src/main/java/com.example.google.codelab.playintegritycpp
아래의PlayIntegrityCodelabActivity
파일을 엽니다. package com.example.google.codelab.playintegritycpp
문을 찾습니다.com.example.google.codelab.playintegritycpp
를 고유한 패키지 이름으로 바꿉니다.- 새 패키지 이름을 마우스 오른쪽 버튼으로 클릭하고 Show Context Actions를 선택합니다.
- Move to(새 패키지 이름)를 선택합니다.
- 파일 상단의 Sync Now 버튼을 선택합니다.
서버 URL 업데이트
서버를 배포한 URL 위치를 가리키도록 프로젝트를 업데이트해야 합니다.
- Android 스튜디오의 Project 창에서
start/app/src/main/cpp
아래의server_urls.hpp
파일을 엽니다. - 서버를 배포할 때 표시된 기준 URL을
GET_RANDOM_URL
및PERFORM_COMMAND_URL
정의에 추가한 후 파일을 저장합니다.
다음과 유사한 결과가 표시됩니다.
constexpr char GET_RANDOM_URL[] = "https://your-play-integrity-server.uc.r.appspot.com/getRandom";
constexpr char PERFORM_COMMAND_URL[] = "https://your-play-integrity-server.uc.r.appspot.com/performCommand";
구체적인 URL은 프로젝트 이름과 서버를 배포하는 데 사용한 Google Cloud 리전에 따라 다릅니다.
빌드와 실행
개발용으로 구성된 Android 기기를 연결합니다. Android 스튜디오에서 프로젝트를 빌드하고 연결된 기기에서 실행합니다. 앱은 다음과 같이 표시됩니다.
Request Random 버튼을 터치하여 랜덤 숫자를 요청하기 위해 서버에 HTTP 요청을 전송하는 코드를 실행합니다. 잠시 후 화면에 랜덤 숫자가 표시됩니다.
오류 메시지가 표시되면 Logcat 창 출력에 자세한 내용이 포함될 수 있습니다.
랜덤 값을 성공적으로 검색하여 서버와 통신 중임을 확인하고 나면 Play Integrity API 통합을 시작할 수 있습니다.
8. 프로젝트에 Play Integrity 추가(C++)
SDK 다운로드
Play Core SDK를 다운로드하고 추출해야 합니다. 다음 단계를 따르세요.
- Play Core Native SDK 페이지에서 .zip 파일로 패키징된 Play Core SDK를 다운로드합니다.
- ZIP 파일의 압축을 풉니다.
- 새로 추출된 디렉터리의 이름을
play-core-native-sdk
로 지정하고add-play-integrity-codelab/cpp/start
디렉터리로 복사하거나 이동합니다.
build.gradle 업데이트
Android 스튜디오의 Project 창에서 start/app
디렉터리의 모듈 수준 build.gradle
파일을 엽니다.
apply plugin: 'com.android.application'
줄 아래에 다음 줄을 추가합니다.
def playcoreDir = file("../play-core-native-sdk")
defaultConfig
블록에서 externalNativeBuild
블록을 찾아 cmake
블록 내의 arguments
문을 다음과 같이 변경합니다.
arguments "-DANDROID_STL=c++_shared",
"-DPLAYCORE_LOCATION=$playcoreDir"
끝에 있는 android
블록 내에 다음을 추가합니다.
buildTypes {
release {
proguardFiles getDefaultProguardFile("proguard-android.txt"),
"proguard-rules.pro",
"$playcoreDir/proguard/common.pgcfg",
"$playcoreDir/proguard/integrity.pgcfg"
}
}
끝의 dependencies
블록 내에 다음 줄을 추가합니다.
implementation files("$playcoreDir/playcore.aar")
변경사항을 저장합니다. 파일 상단에 Gradle 파일이 변경되었음을 알려주는 배너가 표시됩니다. Sync Now를 클릭하여 파일을 새로고침하고 다시 동기화합니다.
CMakeList.txt 업데이트
Android 스튜디오의 Project 창에서 start/app/src/main/cpp
디렉터리의 CMakeLists.txt
파일을 엽니다.
find_package
명령어 아래에 다음 줄을 추가합니다.
include("${PLAYCORE_LOCATION}/playcore.cmake")
add_playcore_static_library()
target_include_directories(game PRIVATE
줄을 찾아 그 아래에 다음 줄을 추가합니다.
${PLAYCORE_LOCATION}/include
target_link_libraries(game
줄을 찾아 그 아래에 다음 줄을 추가합니다.
playcore
파일을 저장합니다. 파일 상단에 외부 빌드 파일이 변경되었음을 알려주는 배너가 표시됩니다. Sync Now를 클릭하여 파일을 새로고침하고 다시 동기화합니다.
Build 메뉴에서 Make Project를 선택하고 프로젝트가 성공적으로 빌드되는지 확인합니다.
9. 무결성 요청(C++)
앱은 Play Integrity API를 사용하여 토큰을 요청해 무결성 정보를 얻습니다. 그러면 개발자는 이를 복호화 및 확인을 위해 서버로 전송합니다. 이제 프로젝트에 코드를 추가하여 Play Integrity API를 초기화하고 이를 사용해 무결성을 요청합니다.
명령어 버튼 추가
실제 앱이나 게임에서는 스토어 구매 또는 멀티플레이어 게임 세션 참여와 같은 특정 활동 전에 무결성 검사를 실행할 수 있습니다. 이 Codelab에서는 UI에 버튼을 추가하여 무결성 검사를 수동으로 트리거하고 서버를 호출하여, 생성된 Play Integrity 토큰을 전달합니다.
Codelab 프로젝트에는 client_manager.cpp
및 client_manager.hpp
소스 파일에 정의된 ClientManager
클래스가 포함되어 있습니다. 편의를 위해 이 파일은 이미 프로젝트에 추가되어 있지만 구현 코드는 없으며 이제 추가할 것입니다.
UI 버튼을 추가하려면 먼저 Android 스튜디오의 Project 창에서 start/app/src/main/cpp
디렉터리에 있는 demo_scene.cpp
파일을 엽니다. 우선 빈 DemoScene::GenerateCommandIntegrity()
함수를 찾아 다음 코드를 추가하세요.
const auto commandResult =
NativeEngine::GetInstance()->GetClientManager()->GetOperationResult();
if (commandResult != ClientManager::SERVER_OPERATION_PENDING) {
if (ImGui::Button("Call server with integrity check")) {
DoCommandIntegrity();
}
}
그런 다음 빈 DemoScene::DoCommandIntegrity()
함수를 찾아 다음 코드를 추가합니다.
ClientManager *clientManager = NativeEngine::GetInstance()->GetClientManager();
clientManager->StartCommandIntegrity();
mServerRandom = clientManager->GetCurrentRandomString();
파일을 저장합니다. 이제 샘플의 ClientManager
클래스를 업데이트하여 실제 Play Integrity 기능을 추가합니다.
관리자 헤더 파일 업데이트
Android 스튜디오 Project 창에서 start/app/src/main/cpp
디렉터리에 있는 client_manager.hpp
파일을 엽니다.
#include "util.hpp"
줄 아래에 다음 줄을 추가하여 Play Integrity API의 헤더 파일을 포함합니다.
#include "play/integrity.h"
ClientManager
클래스는 IntegrityTokenRequest
및 IntegrityTokenResponse
객체 참조를 보유해야 합니다. 다음과 같이 ClientManager
클래스 정의 하단에 다음 줄을 추가합니다.
IntegrityTokenRequest *mTokenRequest;
IntegrityTokenResponse *mTokenResponse;
파일을 저장합니다.
Play Integrity 초기화 및 종료
Android 스튜디오 Project 창에서 start/app/src/main/cpp
디렉터리에 있는 client_manager.cpp
파일을 엽니다.
ClientManager::ClientManager()
생성자를 찾습니다. mInitialized = false;
문을 다음 코드로 교체합니다.
mTokenRequest = nullptr;
mTokenResponse = nullptr;
const android_app *app = NativeEngine::GetInstance()->GetAndroidApp();
const IntegrityErrorCode errorCode = IntegrityManager_init(app->activity->vm,
app->activity->javaGameActivity);
if (errorCode == INTEGRITY_NO_ERROR) {
mInitialized = true;
} else {
mInitialized = false;
ALOGE("Play Integrity initialization failed with error: %d", errorCode);
ALOGE("Fatal Error: Play Integrity is unavailable and cannot be used.");
}
다음 코드를 ClientManager::~ClientManager()
소멸자에 추가합니다.
if (mInitialized) {
IntegrityManager_destroy();
mInitialized = false;
}
무결성 토큰 요청
Play Integrity API에서 무결성 토큰을 요청하는 것은 비동기 작업입니다. 토큰 요청 객체를 만들고 이 객체에 nonce 값을 할당하고 토큰 요청을 해야 합니다. 이렇게 하려면 빈 ClientManager::StartCommandIntegrity()
함수에 다음 코드를 추가합니다.
// Only one request can be in-flight at a time
if (mStatus != CLIENT_MANAGER_REQUEST_TOKEN) {
mResult = SERVER_OPERATION_PENDING;
// Request a fresh random
RequestRandom();
if (mValidRandom) {
GenerateNonce();
IntegrityTokenRequest_create(&mTokenRequest);
IntegrityTokenRequest_setNonce(mTokenRequest, mCurrentNonce.c_str());
const IntegrityErrorCode errorCode =
IntegrityManager_requestIntegrityToken(mTokenRequest, &mTokenResponse);
if (errorCode != INTEGRITY_NO_ERROR) {
// Log the error, in a real application, for potentially
// transient errors such as network connectivity, you should
// add retry with an exponential backoff
ALOGE("Play Integrity returned error: %d", errorCode);
CleanupRequest();
mStatus = CLIENT_MANAGER_IDLE;
} else {
mStatus = CLIENT_MANAGER_REQUEST_TOKEN;
}
}
}
토큰 요청은 비동기식으로 작동하므로 완료 여부를 확인해야 합니다. ClientManager
클래스에는 앱 업데이트 루프의 일부로 호출되는 Update()
함수가 있습니다. 다음 코드를 ClientManager::Update()
함수에 추가하여 토큰 요청 상태를 확인하고 완료되면 결과를 처리합니다.
if (mStatus == CLIENT_MANAGER_REQUEST_TOKEN) {
IntegrityResponseStatus responseStatus = INTEGRITY_RESPONSE_UNKNOWN;
const IntegrityErrorCode errorCode =
IntegrityTokenResponse_getStatus(mTokenResponse, &responseStatus);
if (errorCode != INTEGRITY_NO_ERROR) {
// Log the error, in a real application, for potentially
// transient errors such as network connectivity, you should
// add retry with an exponential backoff
ALOGE("Play Integrity returned error: %d", errorCode);
CleanupRequest();
mStatus = CLIENT_MANAGER_IDLE;
} else if (responseStatus == INTEGRITY_RESPONSE_COMPLETED) {
std::string tokenString = IntegrityTokenResponse_getToken(mTokenResponse);
SendCommandToServer(tokenString);
CleanupRequest();
mStatus = CLIENT_MANAGER_RESPONSE_AVAILABLE;
}
}
요청 객체 정리
토큰 요청 및 응답 객체를 완료하면 객체를 소멸하고 리소스를 회수할 수 있도록 Play Integrity API에 알려야 합니다. 다음 코드를 ClientManager::CleanupRequest()
함수에 추가합니다.
if (mTokenResponse != nullptr) {
IntegrityTokenResponse_destroy(mTokenResponse);
mTokenResponse = nullptr;
}
if (mTokenRequest != nullptr) {
IntegrityTokenRequest_destroy(mTokenRequest);
mTokenRequest = nullptr;
}
Build 메뉴에서 Make Project를 선택하고 프로젝트가 성공적으로 빌드되는지 확인합니다.
10. 서버로 토큰 전송(C++)
이제 무결성 토큰이 포함된 서버에 명령어를 전송하는 코드를 추가합니다. 결과를 처리하는 코드도 추가합니다.
다음 코드를 ClientManager::SendCommandToServer()
함수에 추가합니다.
// Note that for simplicity, we are doing HTTP operations as
// synchronous blocking instead of managing them from a
// separate network thread
HTTPClient client;
std::string errorString;
// Manually construct the json payload for ServerCommand
std::string payloadString = COMMAND_JSON_PREFIX;
payloadString += TEST_COMMAND;
payloadString += COMMAND_JSON_TOKEN;
payloadString += token;
payloadString += COMMAND_JSON_SUFFIX;
auto result = client.Post(PERFORM_COMMAND_URL, payloadString, &errorString);
if (!result) {
ALOGE("SendCommandToServer Curl reported error: %s", errorString.c_str());
mResult = SERVER_OPERATION_NETWORK_ERROR;
} else {
ALOGI("SendCommandToServer result: %s", (*result).c_str())
// Preset to success, ParseResult will set a failure result if the parsing
// errors.
mResult = SERVER_OPERATION_SUCCESS;
ParseResult(*result);
}
다음 코드를 ClientManager::ParseResult()
함수에 추가합니다.
bool validJson = false;
JsonLookup jsonLookup;
if (jsonLookup.ParseJson(resultJson)) {
// Look for all of our needed fields in the returned json
auto commandSuccess = jsonLookup.GetBoolValueForKey(COMMANDSUCCESS_KEY);
if (commandSuccess) {
auto diagnosticString = jsonLookup.GetStringValueForKey(DIAGNOSTICMESSAGE_KEY);
if (diagnosticString) {
auto expressString = jsonLookup.GetStringValueForKey(EXPRESSTOKEN_KEY);
if (expressString) {
if (*commandSuccess) {
// Express token only valid if the server reports the command succeeded
mValidExpressToken = true;
} else {
mValidExpressToken = false;
mResult = SERVER_OPERATION_REJECTED_VERDICT;
}
mCurrentSummary = *diagnosticString;
mCurrentExpressToken = *expressString;
validJson = true;
}
}
}
}
if (!validJson) {
mResult = SERVER_OPERATION_INVALID_RESULT;
}
이제 서명된 App Bundle을 생성하여 Play Console에 업로드하고 앱을 테스트합니다.
11. 빌드 및 업로드(C++)
앱의 키 저장소 생성 및 설정
Android에서는 기기에 설치되거나 업데이트되기 전에 모든 앱이 인증서를 사용하여 디지털 방식으로 서명되어야 합니다.
이 Codelab에서는 앱의 키 저장소를 만듭니다. 기존 게임의 업데이트를 게시한다면 이전 버전의 앱을 출시할 때 사용한 동일한 키 저장소를 재사용하세요.
키 저장소 만들기 및 출시 App Bundle 빌드
Android 스튜디오의 키 저장소의 단계에 따라 키 저장소를 만들고, 이를 사용하여 게임의 서명된 출시 빌드를 생성합니다. Android 스튜디오의 Build 메뉴에서 Generate Signed Bundle / APK를 선택하여 빌드 프로세스를 시작합니다. Android App Bundle 또는 APK를 선택하라는 메시지가 표시되면 App Bundle 옵션을 선택합니다. 프로세스가 끝나면 Google Play Console에 업로드하기에 적합한 .aab 파일이 생성됩니다.
Play Console에 업로드
App Bundle 파일을 만든 후 Play Console에 업로드합니다. 빌드에 빠르게 액세스하려면 내부 테스트 트랙을 사용하는 것이 좋습니다.
테스트 빌드 실행
이제 Play 스토어에서 테스트 빌드를 다운로드하고 실행합니다. 현재는 서버에 무결성 토큰을 전송하는 자리표시자 성공 코드가 함수에 있으므로 무결성 검사를 시작하면 성공하고 다음과 같이 표시됩니다.
축하합니다. Play Integrity를 C++ 애플리케이션에 통합했습니다. 다른 클라이언트 예시로 계속 진행하거나 이 Codelab의 끝부분으로 건너뛰세요.
12. 클라이언트 빌드 및 실행(Unity)
Codelab Unity 프로젝트는 Unity 2020 LTS(2020.3.31f1)를 사용하여 생성되었지만 상위 버전의 Unity와 호환됩니다. Unity용 Play Integrity 플러그인은 Unity 2018 LTS 이상과 호환됩니다.
프로젝트 설정
다음 단계를 따르세요.
- Unity Hub 또는 Unity Editor에서
add-play-integrity-codelab/unity/start
에 있는 Unity 프로젝트를 엽니다. - 프로젝트가 로드되면 Unity File(파일) 메뉴에서 Build Settings...(빌드 설정)을 선택합니다.
- Build Settings(빌드 설정) 창에서 플랫폼을 Android로 변경합니다.
- Build Settings(빌드 설정) 창에서 Player Settings...(플레이어 설정...) 버튼을 클릭합니다.
- Player(플레이어) 카테고리가 선택된 Project Settings(프로젝트 설정) 창에서 Settings for Android(Android 설정) 섹션을 찾습니다. Other Settings(기타 설정) 목록을 펼칩니다.
- Identification(식별)에서 Package Name(패키지 이름) 항목을 찾습니다.
- 패키지 이름을 서버를 배포할 때 선택한 식별자로 변경합니다.
- Project Settings(프로젝트 설정) 창을 닫습니다.
- Unity File(파일) 메뉴에서 Save Project(프로젝트 저장)를 선택합니다.
서버 URL 업데이트
서버를 배포한 URL 위치를 가리키도록 프로젝트를 업데이트해야 합니다. 이렇게 하려면 다음 단계를 따르세요.
- IDE 또는 텍스트 편집기의
Scripts
폴더에서PlayIntegrityController.cs
파일을 엽니다. URL_GETRANDOM
및URL_PERFORMCOMMAND
변수의 값이 서버를 가리키도록 변경합니다.- 파일을 저장합니다.
다음과 유사한 결과가 표시됩니다.
private readonly string URL_GETRANDOM = "https://your-play-integrity-server.uc.r.appspot.com/getRandom";
private readonly string URL_PERFORMCOMMAND = "https://your-play-integrity-server.uc.r.appspot.com/performCommand";
구체적인 URL은 프로젝트 이름과 서버를 배포하는 데 사용한 Google Cloud 리전에 따라 다릅니다.
테스트 서버 기능
Unity 편집기에서 프로젝트를 실행하여 서버 기능을 테스트할 수 있습니다. 다음 단계를 따르세요.
Scenes
폴더에 있는SampleScene
장면 파일을 엽니다.- 편집기에서 Play(재생) 버튼을 클릭합니다.
- Game(게임) 디스플레이에서 Request Random(랜덤 요청) 버튼을 클릭합니다.
잠시 후 다음과 같은 임의의 값이 화면에 표시됩니다.
13. 프로젝트에 Play Integrity 플러그인 추가(Unity)
플러그인 다운로드
웹브라우저에서 Play Unity 플러그인 GitHub 저장소의 출시 페이지를 엽니다. 최신 버전의 플러그인을 사용합니다. com.google.play.integrity-<version>
을 다운로드하세요.애셋 목록에서 Play Integrity unitypackage
파일을 찾습니다.
플러그인 설치
Unity 편집기 메뉴 바에서 Assets -> Import Package -> Custom Package...(애셋 -> 패키지 가져오기 -> 맞춤 패키지...)를 선택하고 다운로드한 .unitypackage
파일을 엽니다. Import Unity Package(Unity 패키지 가져오기) 창이 표시되면 Import(가져오기) 버튼을 클릭합니다.
이 플러그인에는 Unity용 외부 종속 항목 관리자(EDM4U)가 포함되어 있습니다. EDM4U는 Play Integrity를 사용하는 데 필요한 Java 구성요소의 자동 종속 항목 해결을 구현합니다. 자동 종속 항목 해결을 사용 설정하라는 메시지가 표시되면 Enable(사용 설정) 버튼을 클릭합니다.
자동 해결을 사용하는 것이 좋습니다. 종속 항목 문제로 인해 프로젝트가 빌드되지 않거나 실행되지 않을 수 있습니다.
14. 무결성 요청(Unity)
무결성 요청 만들기
무결성 요청을 만들려면 다음 단계를 따르세요.
- IDE 또는 텍스트 편집기의
Scripts
폴더에서PlayIntegrityController.cs
파일을 엽니다. - 파일 상단의
using
문 블록에 다음 줄을 추가합니다.
using Google.Play.Integrity;
RunIntegrityCommand()
함수를 찾고yield return null;
문을 다음 코드로 바꿉니다.
// Call our server to retrieve a random number.
yield return GetRandomRequest();
if (!string.IsNullOrEmpty(_randomString))
{
// Create an instance of an integrity manager.
var integrityManager = new IntegrityManager();
// Request the integrity token by providing a nonce.
var tokenRequest = new IntegrityTokenRequest(GenerateNonceString(_randomString,
TEST_COMMAND));
var requestIntegrityTokenOperation =
integrityManager.RequestIntegrityToken(tokenRequest);
// Wait for PlayAsyncOperation to complete.
yield return requestIntegrityTokenOperation;
// Check the resulting error code.
if (requestIntegrityTokenOperation.Error != IntegrityErrorCode.NoError)
{
// Log the error, in a real application, for potentially
// transient errors such as network connectivity, you should
// add retry with an exponential backoff
Debug.Log($@"IntegrityAsyncOperation failed with error:
{requestIntegrityTokenOperation.Error.ToString()}");
yield break;
}
// Get the response.
var tokenResponse = requestIntegrityTokenOperation.GetResult();
// Send the command to our server with a POST request, including the
// token, which will be decrypted and verified on the server.
yield return PostServerCommand(tokenResponse.Token);
}
명령어를 서버로 전송
PostServerCommand()
함수를 찾고 yield return null;
문을 다음 코드로 바꿔 PlayIntegrityController.cs
파일을 계속 수정합니다.
// Start a HTTP POST request to the performCommand URL, sending it the
// command and integrity token data provided by Play Integrity.
var serverCommand = new ServerCommand(TEST_COMMAND, tokenResponse);
var commandRequest = new UnityWebRequest(URL_PERFORMCOMMAND, "POST");
string commandJson = JsonUtility.ToJson(serverCommand);
byte[] jsonBuffer = Encoding.UTF8.GetBytes(commandJson);
commandRequest.uploadHandler = new UploadHandlerRaw(jsonBuffer);
commandRequest.downloadHandler = new DownloadHandlerBuffer();
commandRequest.SetRequestHeader(CONTENT_TYPE, JSON_CONTENT);
yield return commandRequest.SendWebRequest();
if (commandRequest.result == UnityWebRequest.Result.Success)
{
// Parse the command result Json
var commandResult = JsonUtility.FromJson<CommandResult>(
commandRequest.downloadHandler.text);
if (commandResult != null)
{
resultLabel.text = commandResult.diagnosticMessage;
_expressToken = commandResult.expressToken;
if (commandResult.commandSuccess)
{
resultLabel.color = Color.green;
expressButton.SetActive(true);
}
else
{
resultLabel.color = Color.black;
expressButton.SetActive(false);
}
}
else
{
Debug.Log("Invalid CommandResult json");
}
}
else
{
Debug.Log($"Web request error on processToken: {commandRequest.error}");
}
파일을 저장합니다.
15. 빌드 및 업로드(Unity)
Unity 편집기 Android 키 저장소 관리자를 사용하여 빌드를 Play Console에 업로드하기 위해 서명되도록 구성합니다.
서명 정보를 구성하고 나면 다음 단계를 따르세요.
- Unity File(파일) 메뉴에서 Build -> Build Settings...(빌드 -> 빌드 설정...)를 선택합니다.
SampleScene
이 Scenes in Build(빌드의 장면) 목록에 포함되어 있는지 확인합니다.- Build App Bundle (Google Play)(App Bundle 빌드(Google Play)) 체크박스가 선택되어 있는지 확인합니다.
- Build(빌드) 버튼을 클릭하고 내보내기 파일의 이름을 지정합니다.
App Bundle 파일을 만든 후 Play Console에 업로드합니다. 빌드에 빠르게 액세스하려면 내부 테스트 트랙을 사용하는 것이 좋습니다.
이제 빌드를 다운로드하고 설치하여 무결성 검사를 실행할 수 있습니다. 다음과 유사한 결과가 표시됩니다.
수고하셨습니다. Unity 엔진 프로젝트에 Play Integrity를 통합했습니다. 다른 클라이언트 예시로 계속 진행하거나 이 Codelab의 끝부분으로 건너뛰세요.
16. 프로젝트 빌드 및 실행(Kotlin)
Android 스튜디오를 실행합니다. Welcome to Android Studio 창에서 Open 버튼을 클릭하고 add-play-integrity-codelab/kotlin/start
에 있는 Android 스튜디오 프로젝트를 엽니다.
애플리케이션 ID 업데이트
Google Play에 빌드를 업로드하기 전에 애플리케이션 ID를 기본값에서 고유한 값으로 변경해야 합니다. 다음 단계를 따르세요.
- Android 스튜디오의 Project 창에서
PlayIntegrityCodelab.app
모듈의build.gradle
파일을 엽니다. applicationId
문을 찾습니다.com.example.google.codelab.playintegritykotlin
을 서버를 배포할 때 선택한 식별자로 변경하고 파일을 저장합니다.- 파일 상단에 Gradle 파일이 변경되었음을 알려주는 배너가 표시됩니다. Sync Now를 클릭하여 파일을 새로고침하고 다시 동기화합니다.
서버 URL 업데이트
서버를 배포한 URL 위치를 가리키도록 프로젝트를 업데이트해야 합니다. 이렇게 하려면 다음 단계를 따르세요.
- Android 스튜디오의 Project 창에서
start/app/src/main/java/com.example.google.codelab.playintegritykotlin/integrity
아래의IntegrityServer
파일을 엽니다. - URL을
‘https://your.play-integrity.server.com'
에서 서버의 기준 URL로 변경하고 파일을 저장합니다.
다음과 유사한 결과가 표시됩니다.
private val SERVER_URL: String = "https://your-play-integrity-server.uc.r.appspot.com"
구체적인 URL은 프로젝트 이름과 서버를 배포하는 데 사용한 Google Cloud 리전에 따라 다릅니다.
빌드와 실행
개발용으로 구성된 Android 기기를 연결합니다. Android 스튜디오에서 프로젝트를 빌드하고 연결된 기기에서 실행합니다. 앱은 다음과 같이 표시됩니다.
시작 시 앱은 서버에서 getRandom
엔드포인트를 호출하고 결과를 표시합니다. URL이 잘못되었거나 서버가 작동하지 않는 등의 오류가 발생하면 오류 대화상자가 표시됩니다. Request Random 버튼을 선택하여 서버에서 새로운 랜덤 숫자를 검색할 수 있습니다. Call server with integrity check 버튼은 아직 아무 작업도 하지 않습니다. 다음 섹션에서 기능을 추가합니다.
17. 프로젝트에 Play Integrity 추가(Kotlin)
Play Integrity 라이브러리와 지원 종속 항목을 프로젝트에 추가하려면 다음 단계를 따르세요.
- Android 스튜디오의 Project 창에서
start/app
아래의build.gradle
파일을 엽니다. - 파일 하단에서
dependencies
블록을 찾습니다. dependencies
블록 하단에 다음 줄을 추가합니다.
implementation "com.google.android.play:integrity:1.0.1"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.6.1"
- 파일을 저장합니다.
- 파일 상단에 Gradle 파일이 변경되었음을 알려주는 배너가 표시됩니다. Sync Now를 클릭하여 파일을 새로고침하고 다시 동기화합니다.
Kotlin 샘플에서는 코루틴을 사용합니다. kotlinx-coroutines-play-services
라이브러리는 Kotlin 코루틴 내에서 Play Integrity 비동기 Task
객체 작업을 용이하게 하는 확장 프로그램을 추가합니다.
18. 무결성 요청(Kotlin)
Android 스튜디오의 Project 창에서 start/app/src/main/java/com.example.google.codelab.playintegritykotlin/integrity
아래의 IntegrityServer
파일을 엽니다. 파일 하단에는 빈 integrityCommand
함수가 있습니다. Call server with integrity check 버튼을 누르면 UI에서 이 함수를 호출합니다.
integrityCommand
함수에 코드를 추가하여 다음 작업을 실행하세요.
- 무결성 검사와 연결할 nonce를 구성할 때 사용할 서버에서 새로운 랜덤 숫자를 가져옵니다.
- Play Integrity API를 호출하여 무결성 요청을 하고 결과가 포함된 무결성 토큰을 수신합니다.
- HTTP
POST
요청을 사용하여 명령어와 무결성 토큰을 서버에 전송합니다. - 결과를 처리하고 표시합니다.
다음 코드를 빈 integrityCommand
함수에 추가하세요.
// Set our state to working to trigger a switch to the waiting UI
_serverState.emit(ServerState(
ServerStatus.SERVER_STATUS_WORKING))
// Request a fresh random from the server as part
// of the nonce we will generate for the request
var integrityRandom = IntegrityRandom("", 0U)
try {
val returnedRandom = httpClient.get<IntegrityRandom>(
SERVER_URL + "/getRandom")
integrityRandom = returnedRandom
} catch (t: Throwable) {
Log.d(TAG, "getRandom exception " + t.message)
_serverState.emit(ServerState(ServerStatus.SERVER_STATUS_UNREACHABLE,
IntegrityRandom("", 0U)))
}
// If we have a random, we are ready to request an integrity token
if (!integrityRandom.random.isNullOrEmpty()) {
val nonceString = GenerateNonce.GenerateNonceString(TEST_COMMAND,
integrityRandom.random)
// Create an instance of an IntegrityManager
val integrityManager = IntegrityManagerFactory.create(context)
// Use the nonce to configure a request for an integrity token
try {
val integrityTokenResponse: Task<IntegrityTokenResponse> =
integrityManager.requestIntegrityToken(
IntegrityTokenRequest.builder()
.setNonce(nonceString)
.build()
)
// Wait for the integrity token to be generated
integrityTokenResponse.await()
if (integrityTokenResponse.isSuccessful && integrityTokenResponse.result != null) {
// Post the received token to our server
postCommand(integrityTokenResponse.result!!.token(), integrityRandom)
} else {
Log.d(TAG, "requestIntegrityToken failed: " +
integrityTokenResponse.result.toString())
_serverState.emit(ServerState(ServerStatus.SERVER_STATUS_FAILED_TO_GET_TOKEN))
}
} catch (t: Throwable) {
Log.d(TAG, "requestIntegrityToken exception " + t.message)
_serverState.emit(ServerState(ServerStatus.SERVER_STATUS_FAILED_TO_GET_TOKEN))
}
}
서버에 명령어를 POST
하는 코드는 별도의 postCommand
함수로 나뉩니다. 다음 코드를 빈 postCommand
함수에 추가합니다.
try {
val commandResult = httpClient.post<CommandResult>(
SERVER_URL + "/performCommand") {
contentType(ContentType.Application.Json)
body = ServerCommand(TEST_COMMAND, tokenString)
}
_serverState.emit(ServerState(ServerStatus.SERVER_STATUS_REACHABLE,
integrityRandom,
commandResult.diagnosticMessage,
commandResult.commandSuccess,
commandResult.expressToken))
} catch (t: Throwable) {
Log.d(TAG, "performCommand exception " + t.message)
_serverState.emit(ServerState(ServerStatus.SERVER_STATUS_UNREACHABLE))
}
누락된 가져오기를 해결하고 파일을 저장합니다.
19. 결과 표시(Kotlin)
확인 결과 요약으로 UI 업데이트
현재 UI에는 무결성 확인 결과 요약의 자리표시자 텍스트가 표시됩니다. 자리표시자를 실제 요약으로 바꾸려면 다음 단계를 따르세요.
- Android 스튜디오의 Project 창에서
start/app/src/main/java/com.example.google.codelab.playintegritykotlin/ui/main
아래의MainView.kt
파일을 엽니다. - MainUI 함수의 끝으로 이동하여
text = "None",
문을 찾아 다음 코드로 바꿉니다.
text = state.serverState.serverVerdict,
- 누락된 가져오기를 해결하고 파일을 저장합니다.
20. 빌드 및 업로드(Kotlin)
앱의 키 저장소 생성 및 설정
Android에서는 기기에 설치되거나 업데이트되기 전에 모든 앱이 인증서를 사용하여 디지털 방식으로 서명되어야 합니다.
이 Codelab에서는 앱의 키 저장소를 만듭니다. 기존 게임의 업데이트를 게시한다면 이전 버전의 앱을 출시할 때 사용한 동일한 키 저장소를 재사용하세요.
키 저장소 만들기 및 출시 App Bundle 빌드
Android 스튜디오의 키 저장소의 단계에 따라 키 저장소를 만들고, 이를 사용하여 게임의 서명된 출시 빌드를 생성합니다. Android 스튜디오의 Build 메뉴에서 Generate Signed Bundle / APK를 선택하여 빌드 프로세스를 시작합니다. Android App Bundle 또는 APK를 선택하라는 메시지가 표시되면 App Bundle 옵션을 선택합니다. 프로세스가 끝나면 Google Play Console에 업로드하기에 적합한 .aab 파일이 생성됩니다.
Play Console에 업로드
App Bundle 파일을 만든 후 Play Console에 업로드합니다. 빌드에 빠르게 액세스하려면 내부 테스트 트랙을 사용하는 것이 좋습니다.
테스트 빌드 실행
이제 Play 스토어에서 테스트 빌드를 다운로드하고 실행합니다. Call server with integrity check 버튼을 선택하면 성공하고 다음과 같이 표시됩니다.
21. 축하합니다
축하합니다. Play Integrity를 Android 애플리케이션에 추가했습니다.