# 서명 키 변경 가이드

최근 구글의 콘텐츠 앱 결제 정책 변경으로 인해 패키지 네임 또는 서명 키의 변경이 필요한 사례가 많아지고 있습니다.

아래와 같이 유형별 수정 방안을 참고하여 기존 앱 사용자의 이탈을 막고 원활한 업데이트를 할 수 있도록 하시기 바랍니다.

<figure><img src="https://1837360763-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fot0z57AnnXZ02C5qyePV%2Fuploads%2F8Z7co6LoUbcdSNmHhAjy%2Fimage.png?alt=media&#x26;token=40440f81-c745-427f-82cf-fc4de60b59cb" alt=""><figcaption></figcaption></figure>

## 상세페이지 연동 규격 <a href="#id" id="id"></a>

[연동 규격 개발 가이드](https://onestore-dev.gitbook.io/dev/docs/apps/android/app-signing/broken-reference)에서 확인할 수 있습니다.

## 설치된 앱의 서명 키 확인 방법 <a href="#id" id="id"></a>

설치된 앱의 인증서 지문을 획득한 후 비교할 서명 키의 인증서 지문과 동일 여부를 확인합니다.

**설치된 앱의 인증서 SHA-256 digest 확인 방법 예제**

```java
val certs = runCatching {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
        val signingInfo = packageManager.getPackageInfo(packageName, PackageManager.GET_SIGNING_CERTIFICATES).signingInfo
        if (signingInfo.hasMultipleSigners()) {
            signingInfo.apkContentsSigners
        } else {
            signingInfo.signingCertificateHistory
        }
    } else {
        packageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES).signatures
    }
}.mapCatching {
    it.map {
        val encodedCert = CertificateFactory.getInstance("X509").generateCertificate(ByteArrayInputStream(it.toByteArray())).encoded
        MessageDigest.getInstance("SHA-256").digest(encodedCert).toHexString()
    }
}.recoverCatching {
    // handle exceptions
    throw it
}.getOrNull()
 
fun ByteArray.toHexString() = joinToString(separator = "") { "%02x".format(it) }
```

**참고**

* Android API reference
  * <https://developer.android.com/reference/android/content/pm/PackageManager#getPackageInfo(java.lang.String,%20int)>
  * <https://developer.android.com/reference/android/content/pm/PackageManager#getPackageInfo(java.lang.String,%20android.content.pm.PackageManager.PackageInfoFlags)>
  * <https://developer.android.com/reference/android/content/pm/PackageManager#GET_SIGNATURES>
  * <https://developer.android.com/reference/android/content/pm/PackageManager#GET_SIGNING_CERTIFICATES>
* API level 30 이상에서 타 패키지의 정보를 조회할 경우 패키지 공개 상태 필터링 적용이 필요합니다.
  * <https://developer.android.com/training/package-visibility/declaring?hl=ko#package-name>
* 서명 키 인증서 지문은 Google Play App Signing을 사용하는 경우 Play Console에서 확인 가능하며, 직접 서명하는 경우 keytool, apksigner 등으로 추출 가능합니다.

<br>

## 설치된 앱의 앱 출처 정보 확인 방법 <a href="#id" id="id"></a>

앱을 설치한 스토어 또는 인스톨러의 이름이 앱 설치 시 기록되며 설정 > 애플리케이션 > 애플리케이션 정보에서 확인할 수 있습니다.

| 원스토어 앱 출처 정보                                                                                                                                                                                                        | Google Play 앱 출처 정보                                                                                                                                                                                                 | Galaxy Store 앱 출처 정보                                                                                                                                                                                                |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| ![](https://1837360763-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fot0z57AnnXZ02C5qyePV%2Fuploads%2F6KxIyOjxPoatRFlOR1qA%2Fimage.png?alt=media\&token=99ec6c57-4c3f-46af-8881-3e9e7e8aaff4) | ![](https://1837360763-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fot0z57AnnXZ02C5qyePV%2Fuploads%2FL95w5Q6PpVmPlGnXwZCe%2Fimage.png?alt=media\&token=240b7def-d799-454a-be1b-5c577811e735) | ![](https://1837360763-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fot0z57AnnXZ02C5qyePV%2Fuploads%2FZFT8lcY1RPqDls3dk1G5%2Fimage.png?alt=media\&token=4eed7181-34e3-4427-bf19-dfb007b60de0) |

설치된 앱의 인스톨러 패키지 네임을 획득한 후 스토어의 패키지 네임과 비교해서 앱 출처 정보를 확인합니다.

## **스토어별 패키지 네임**

* 원스토어
  * com.skt.skaf.A000Z00040
  * com.kt.olleh.storefront
  * com.kt.olleh.istore
  * com.lguplus.appstore
  * android.lgt.appstore
* &#x20;Google Play
  * com.android.vending
* &#x20;Galaxy Store
  * com.sec.android.app.samsungapps

**설치된 앱의 앱 출처 정보 확인 방법 예제**

```java
val installer = runCatching {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
        packageManager.getInstallSourceInfo(packageName).installingPackageName
    } else {
        packageManager.getInstallerPackageName(packageName)
    }
}.getOrNull()
```

|   |
| - |

**참고**

* Android API reference
  * <https://developer.android.com/reference/android/content/pm/PackageManager#getInstallSourceInfo(java.lang.String)>
  * <https://developer.android.com/reference/android/content/pm/PackageManager#getInstallerPackageName(java.lang.String)>
* &#x20;API level 30 이상에서 타 패키지의 정보를 조회할 경우 패키지 공개 상태 필터링 적용이 필요합니다.
  * <https://developer.android.com/training/package-visibility/declaring?hl=ko#package-name>

## 앱 삭제 요청 방법 <a href="#id" id="id"></a>

앱에서 자체적으로 삭제 기능을 제공하기 위해서는 DELETE\_PACKAGES(또는 REQUEST\_DELETE\_PACKAGES) 권한이 필요합니다.\
일반적인 권한이 아니므로, 사용자가 직접 삭제를 할 수 있도록 안내 후 애플리케이션 정보 화면으로 이동합니다.&#x20;

\
**삭제할 앱의 애플리케이션 정보 화면으로 이동 예제**

```java
startActivity(Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.parse("package:$packageName")).apply {
    addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
})
```

**참고**

* Android API reference
  * <https://developer.android.com/reference/android/provider/Settings#ACTION_APPLICATION_DETAILS_SETTINGS>

| 앱 삭제 요청 예시 화면(앱 에서 구현)                                                                                                                                                                                                                                                             | 애플리케이션 정보 화면                                                                                                                                                                                                        |
| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| <p><img src="https://1837360763-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fot0z57AnnXZ02C5qyePV%2Fuploads%2FemdlrVO5ZvOUFNqTCFYU%2Fimage.png?alt=media&#x26;token=2c646695-e349-480e-a22c-e05093012d3f" alt=""></p><p>\[삭제] 버튼 터치 시 애플리케이션 정보 화면으로 이동</p> | ![](https://1837360763-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fot0z57AnnXZ02C5qyePV%2Fuploads%2FvFGHzDAc2AEff6bxw4Hq%2Fimage.png?alt=media\&token=c18444bc-f1c7-4020-9b98-ec48f3bd2378) |

<br>
