SDK 런타임의 이전 버전과의 호환성

이 문서에서는 개발자가 SDK 런타임으로 이전하는 데 도움이 되는 새로운 Jetpack 라이브러리를 제안합니다. 이전 Android 플랫폼 버전에서 SDK 런타임이 어떻게 지원 (빌드에서 실행까지), 그리고 런타임 환경 개발자가 예상할 수 있는 차이점이나 제한사항을 설명합니다. 이 라이브러리를 사용하면 개발자는 SDK 런타임 지원 여부와 관계없이 기기에서 실행할 수 있는 기능이 포함된 단일 버전의 앱 또는 SDK를 만들 수 있습니다.

이전 버전과의 호환성은 다음 구성요소를 통해 이루어집니다.

  • Android Gradle 플러그인 (AGP) + Bundletool은 SDK 런타임을 APK에 번들로 묶어 SDK 런타임이 지원되지 않는 기기의 앱 변형을 빌드합니다.

  • SDK 런타임 클라이언트 라이브러리(androidx.privacysandbox.sdkruntime:sdkruntime-client)는 앱 애셋에서 번들 SDK를 로드하고 SDK 런타임이 지원되지 않는 기기에서 SDK 런타임을 에뮬레이션합니다.

  • SDK 런타임 제공자 라이브러리(androidx.privacysandbox.sdkruntime:sdkruntime-provider)는 SDK가 SDK 런타임 클라이언트 라이브러리에서 로드할 수 있도록 하는 API를 제공합니다.

Bundletool을 사용한 SDK 전송

SDK 런타임이 지원되는 기기에서 SDK는 별도의 패키지로 전송되고 설치됩니다.

SDK 런타임 지원이 없는 플랫폼 버전을 지원하기 위해 Bundletool은 앱이 종속된 모든 SDK를 포함하는 앱 APK 집합의 변형을 하나 이상 빌드합니다. 각 SDK는 별도의 APK 분할로 패키징됩니다. 또한 다음과 같은 변환이 수행됩니다.

  1. SDK 바이트 코드 (DEX) 파일을 SDK 분할에 애셋으로 복사합니다.
  2. SDK 자바 리소스를 SDK 분할에 애셋으로 복사합니다.
  3. SDK 리소스를 재매핑하여 앱 리소스와 병합합니다.
  4. SDK 런타임 클라이언트 라이브러리의 구성을 생성합니다.

SDK 런타임 클라이언트 라이브러리로 SDK 로드

SDK 런타임 클라이언트 라이브러리는 플랫폼 API와 유사한 API를 제공하지만 SDK 런타임 환경의 SDK와 변형 앱과 함께 번들로 제공되는 SDK를 모두 지원합니다.

SDK 런타임 클라이언트 라이브러리를 사용하려면 androidx.privacysandbox.sdkruntime:sdkruntime-client 종속 항목을 추가하고 SdkSandboxManager 대신 SdkSandboxManagerCompat를 사용합니다.

앱이 SDK를 로드하려고 하면 라이브러리는 먼저 빌드 중에 SDK가 앱과 번들되었는지 확인합니다. 번들된 경우 라이브러리는 SDK 분할에서 SDK를 추출하여 앱 프로세스에 로드합니다. SDK가 앱과 번들로 제공되지 않은 경우 라이브러리는 SDK를 로드하도록 플랫폼 API에 위임합니다.

애셋에서 SDK 추출

앱이 번들 SDK를 로드하려고 하면 SDK 런타임 클라이언트 라이브러리가 SDK의 DEX 파일이 기기 저장소(code_cache)에 이미 추출되었는지 확인하고 추출되지 않은 경우 애셋에서 추출합니다.

라이브러리는 일반적으로 앱 설치 또는 업데이트 후에 한 번만 파일을 추출합니다.

사용 가능한 저장공간이 허용된 기준점 (현재 100MB)보다 적고 DEX 파일이 추출되지 않으면 라이브러리는 지원되는 기기 (API 27 이상)의 애셋에서 SDK를 직접 로드하려고 시도합니다. 따라서 메모리 공간이 더 커집니다.

SDK 클래스용 Classloader

SDK와 앱 클래스 간의 충돌을 방지하기 위해 모든 SDK 클래스는 기본 앱 클래스 로더와 완전히 독립적인 별도의 클래스 로더를 사용하여 로드됩니다.

현재 SDK 런타임 설계에서는 앱과 SDK 간의 모든 통신이 바인더 IPC 호출을 사용하여 이루어집니다. 번들 SDK에는 동일한 SDK 바인더 객체가 사용되며, 바인더 트랜잭션 직렬화를 통해 앱 개발자는 앱 측에서 SDK 바인더 객체를 SDK 바인더 인터페이스로 전송할 수 있습니다.

기타 내부 상호작용 (예: SDK 초기화, SDK에 컨트롤러 API 제공 등)의 경우 라이브러리는 Reflection과 동적 프록시를 사용하여 다양한 클래스 로더에서 작동합니다.

SDK 환경

SDKRuntime Provider 라이브러리는 SDK 개발자에게 API를 제공합니다. 이러한 API는 플랫폼 API와 비슷하지만 SDK 런타임 환경과 SDKRuntime 클라이언트 라이브러리에서 모두 SDK를 로드할 수 있습니다.

라이브러리 SDK를 사용할 수 있으려면 androidx.privacysandbox.sdkruntime:sdkruntime-provider 종속 항목을 추가하고 SandboxedSdkProvider 대신 SandboxedSdkProviderCompat를 확장해야 합니다.

또한 SandboxedSdkProviderAdapter를 SDK 제공업체로 사용하여 compat 제공자가 SDK 런타임 환경에 로드될 수 있게 해야 합니다.

SdkSandboxControllerCompat는 SDK가 SDK 런타임에 로드될 때 플랫폼 API에 위임하거나 SDK가 번들 SDK로 로드될 때 SDKRuntime 클라이언트 라이브러리에 위임합니다.

번들 SDK의 경우 라이브러리는 SDK 런타임 환경과 유사한 동작을 에뮬레이션하는 방식으로 SDK 환경을 수정합니다.

다음 섹션에서는 SDKRuntime 클라이언트 라이브러리에서 SDK를 로드할 때 예상되는 동작을 설명합니다.

SDK 리소스

SDK 리소스 (res/)는 SDK가 앱 프로세스에 로드될 때 지원됩니다. Bundletool은 모든 SDK의 리소스를 앱 리소스와 병합합니다.

충돌을 방지하기 위해 모든 리소스 ID에서 packageId 접두사를 변경하여 SDK 리소스를 다시 매핑합니다.

SDK가 SDKRuntime 클라이언트 라이브러리에 의해 로드되면 R 클래스를 사용하여 재매핑된 리소스를 처리할 수 있도록 packageId가 런타임에 업데이트됩니다.

자바 리소스

Java 리소스는 SDK가 앱 프로세스에 로드될 때 지원됩니다. Bundletool은 모든 SDK 자바 리소스를 앱 애셋의 특수 디렉터리에 복사합니다. SDKRuntime 클라이언트 라이브러리는 중간 클래스 로더를 사용하여 모든 자바 리소스 관련 호출을 새 루트 디렉터리로 리디렉션합니다.

SDK 애셋

SDK 애셋이 재매핑 없이 앱 애셋과 병합됩니다.

SDK 저장소

SDK 저장소를 지원하기 위해 SDK 런타임 클라이언트 라이브러리는 앱 저장소에 번들된 각 SDK에 대한 전용 루트 디렉터리를 만들고 이 디렉터리를 저장소 루트로 사용하는 특수 컨텍스트를 제공합니다.

이 컨텍스트는 SandboxedSdkProviderCompat#getContext에서 가져올 수 있습니다.

지원되는 저장소 관련 메서드:

  • getDataDir
  • getCacheDir
  • getCodeCacheDir
  • getNoBackupFilesDir
  • getDir
  • getFilesDir
  • openFileInput
  • openFileOutput
  • deleteFile
  • getFileStreamPath
  • fileList
  • getDatabasePath
  • openOrCreateDatabase
  • moveDatabaseFrom - SDK 컨텍스트 간에만
  • deleteDatabase
  • databaseList
  • getSharedPreferences
  • moveSharedPreferencesFrom - SDK 컨텍스트 간에만
  • deleteSharedPreferences

기기 보호 저장소 컨텍스트는 해당 컨텍스트에서 createDeviceProtectedStorageContext()를 호출하여 만들 수 있습니다.

SdkSandboxControllerCompat

SDKRuntime 클라이언트 라이브러리는 앱 프로세스에 로드된 번들 SDK에 SdkSandboxControllerCompat 구현을 제공합니다.

클라이언트 라이브러리에서 API를 지원하지 않는 경우 (예: 앱 버전보다 최신 버전의 라이브러리로 빌드된 SDK를 사용하는 경우) 가장 적합한 대체 값이 사용됩니다 (무작동 또는 예외).

버전 관리

SDKRuntime 클라이언트 라이브러리가 번들 SDK를 로드할 때 SDK 내의 SDKRuntime Provider 라이브러리와 핸드셰이크를 실행합니다. 라이브러리는 핸드셰이크 중에 버전을 교환하고 사용할 수 없는 API를 가장 적합한 대체(노옵스(no-ops) 또는 예외)로 대체하도록 동작을 조정합니다.

앱과 SDK 개발자 모두에게 최신 버전의 라이브러리를 사용하는 것이 좋습니다. 그러지 않으면 두 부분에서 모두 지원이 필요한 기능을 사용하지 못할 수 있습니다.

모든 버전의 SDKRuntime 클라이언트 라이브러리는 모든 버전의 SDKRuntime Provider 라이브러리 또는 그 반대로 SDK를 로드할 수 있습니다.

향후 특정 버전의 제공자 라이브러리로 SDK를 로드하는 데 필요한 최소 클라이언트 라이브러리 버전으로 변경될 예정입니다.

이렇게 하면 조각화가 최소화되고 번들 SDK가 성공적으로 로드된 경우 대부분의 API가 지원됩니다.