키 저장소 정보를 build.gradle에 넣지 않고 APK에 서명


152

키 저장소 비밀번호와 키 비밀번호 프로젝트 build.gradle파일에 저장 되지 않도록 서명 프로세스를 설정하려고 합니다.

현재 나는 다음과 같은 것을 가지고있다 build.gradle:

android {
    ...
    signingConfigs {
        release {
            storeFile file("my.keystore")
            storePassword "store_password"
            keyAlias "my_key_alias"
            keyPassword "key_password"
        }
    }

    buildTypes {
        release {
            signingConfig signingConfigs.release            
        }
    }
}

완벽하게 작동하지만 의 값 과 저장소에 값을 입력 해서는 안됩니다 . 나는 넣지하는 것을 선호 하고 하나있다.storePasswordkeyPasswordstoreFilekeyAlias

build.gradle일부 외부 소스 (내 컴퓨터에만있는 파일과 같은)로부터 암호를 얻도록 변경하는 방법이 있습니까?

물론 변경 사항 build.gradle은 다른 컴퓨터에서도 사용할 수 있어야합니다 (컴퓨터가 암호에 액세스 할 수없는 경우에도).

중요한 경우 Android Studio 및 Mac OS X Maverics를 사용하고 있습니다.


"물론, 변경된 build.gradle는 (컴퓨터가 암호에 대한 액세스 권한이없는 경우에도) 다른 컴퓨터에서 사용할 수 있어야"- 데이터에없는 경우 build.gradle, 당신이 아닌 다른 뭔가를해야합니다 build.gradle여부, 그것은 환경 변수 (한 답변 당), 속성 파일 (다른 답변 당) 또는 다른 수단에 대한 조정입니다. 외부에 물건을 갖고 싶지 않다면 build.gradle, 정의에 따라 모든 서명 정보는 내부 에 있어야 합니다buid.gradle .
CommonsWare

2
@CommonsWare 당신이 맞아요. 그래도 build.gradle 내에 엄격하게 무언가를 갖고 싶다고 말하지 않았습니다. 그리고 build.gradle이 일부 외부 소스 (내 컴퓨터에만있는 파일과 같은)로부터 암호를 얻을
Bobrovsky


답변:


120

Groovy의 좋은 점은 Java 코드를 자유롭게 혼합 할 수 있으며를 사용하여 키 / 값 파일을 쉽게 읽을 수 있다는 것 java.util.Properties입니다. 관용적 그루비를 사용하는 훨씬 쉬운 방법이 있을지 모르지만 Java는 여전히 매우 간단합니다.

keystore.properties파일을 작성 하십시오 (이 예제에서 프로젝트 옆의 루트 디렉토리에 원하는 위치에 파일 settings.gradle을 넣을 수 있음).

storePassword=...
keyPassword=...
keyAlias=...
storeFile=...

이것을 다음에 추가하십시오 build.gradle:

allprojects {
    afterEvaluate { project ->
        def propsFile = rootProject.file('keystore.properties')
        def configName = 'release'

        if (propsFile.exists() && android.signingConfigs.hasProperty(configName)) {
            def props = new Properties()
            props.load(new FileInputStream(propsFile))
            android.signingConfigs[configName].storeFile = file(props['storeFile'])
            android.signingConfigs[configName].storePassword = props['storePassword']
            android.signingConfigs[configName].keyAlias = props['keyAlias']
            android.signingConfigs[configName].keyPassword = props['keyPassword']
        }
    }
}

29
keystore.properties에서 따옴표를 제거해야했습니다
Jacob Tabak

6
플러그인 버전 0.9. +에서는 서명 된 버전을 생성하지 않습니다. signingConfigs 블록 및 buildTypes.release.signingConfig 항목으로 무엇을해야합니까? 그들을 제거?
페르난도 Gallego

1
storeFile을 유효한 값으로 설정 storeFile file('AndroidManifest.xml')한 다음 (예 :) 나중에 재정의하면 서명 프로세스가 발생합니다.
miracle2k

5
Error:(24, 0) Could not find property 'android' on root project 'RootProjectName'24 행이 if-block이있는 경우 오류가 발생 합니다. apply plugin: 'com.android.application'루트 build.gradle에 추가 하면 빌드가 실패합니다. 내가 뭘 잘못하고 있죠?
PhilLab

2
2018 년에는 작동하지 않습니다. 더 이상 사용되지 않습니까? Could not get unknown property 'android' for root project
pt

106

또는 자동 생성 된 gradle 코드와 유사한 방식으로 Scott Barta의 답변을 적용하려면 keystore.properties프로젝트 루트 폴더에 파일을 만들 수 있습니다 .

storePassword=my.keystore
keyPassword=key_password
keyAlias=my_key_alias
storeFile=store_file  

gradle 코드를 다음과 같이 수정하십시오.

// Load keystore
def keystorePropertiesFile = rootProject.file("keystore.properties");
def keystoreProperties = new Properties()
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))

...

android{

    ...

    signingConfigs {
        release {
            storeFile file(keystoreProperties['storeFile'])
            storePassword keystoreProperties['storePassword']
            keyAlias keystoreProperties['keyAlias']
            keyPassword keystoreProperties['keyPassword']
        }
    }

    ...

}

이 속성 파일을 모듈의 루트에 저장할 수 있습니다.이 경우에는 생략 rootProject하고 다른 키 저장소 및 키 별명에 대한 여러 속성 세트를 갖도록이 코드를 수정할 수도 있습니다.


7
잘 작동합니다. 내가 사용 if ( keystorePropertiesFile.exists() )확인 파일 속성을 얻기 위해 시도하기 전에 존재하고 로그인을 시도 할 수 있습니다.
Joshua Pinter

파일 .txt끝에 확장자 를 추가하는 것을 잊지 마십시오 keystore.properties.
Levon Petrosyan

11
파일 .txt확장자는 필요하지 않습니다 keystore.properties.
Matt Zukowski

2
이 정보 것 같은데 여기에 추가되었습니다 - developer.android.com/studio/publish/...
바딤 Kotov을

36

가장 쉬운 방법은 ~/.gradle/gradle.properties파일 을 만드는 것 입니다.

ANDROID_STORE_PASSWORD=hunter2
ANDROID_KEY_PASSWORD=hunter2

그러면 build.gradle파일이 다음과 같이 보일 수 있습니다.

android {
    signingConfigs {
        release {
            storeFile file('yourfile.keystore')
            storePassword ANDROID_STORE_PASSWORD
            keyAlias 'youralias'
            keyPassword ANDROID_KEY_PASSWORD
        }
    }
    buildTypes {
        release {
            signingConfig signingConfigs.release
        }
    }
}

1
~ / .gradle / gradle.properties를 gitignore해야합니까?
vzhen

전체 지침은 기본 문서에 반응합니다.
Pencilcheck

23

몇 가지 링크를 읽은 후 :

http://blog.macromates.com/2006/keychain-access-from-shell/ http://www.thoughtworks.com/es/insights/blog/signing-open-source-android-apps-without-disclosing- 비밀번호

Mac OSX를 사용하고 있으므로 키 체인 접근을 사용하여 암호를 저장할 수 있습니다.

키 체인 접근에서 비밀번호를 추가하는 방법

그런 다음 gradle 스크립트에서 :

/* Get password from Mac OSX Keychain */
def getPassword(String currentUser, String keyChain) {
    def stdout = new ByteArrayOutputStream()
    def stderr = new ByteArrayOutputStream()
    exec {
        commandLine 'security', '-q', 'find-generic-password', '-a', currentUser, '-gl', keyChain
        standardOutput = stdout
        errorOutput = stderr
        ignoreExitValue true
    }
    //noinspection GroovyAssignabilityCheck
    (stderr.toString().trim() =~ /password: '(.*)'/)[0][1]
}

다음과 같이 사용하십시오.

getPassword (현재 사용자, "Android_Store_Password")

/* Plugins */
apply plugin: 'com.android.application'

/* Variables */
ext.currentUser = System.getenv("USER")
ext.userHome = System.getProperty("user.home")
ext.keystorePath = 'KEY_STORE_PATH'

/* Signing Configs */
android {  
    signingConfigs {
        release {
            storeFile file(userHome + keystorePath + project.name)
            storePassword getPassword(currentUser, "ANDROID_STORE_PASSWORD")
            keyAlias 'jaredburrows'
            keyPassword getPassword(currentUser, "ANDROID_KEY_PASSWORD")
        }
    }

    buildTypes {
        release {
            signingConfig signingConfigs.release
        }
    }
}

2
귀하의 답변은 Mac OSX에만 적용되지만 정말 마음에 듭니다! 제공 한 두 번째 링크에는 다른 플랫폼을위한 백업 솔루션이 포함되어 있습니다. 누군가가 다중 플랫폼 지원을 구현해야하는 경우에 대비합니다.
Delblanco

리눅스와 윈도우에 동일한 솔루션을 제공 할 수 있습니까? 감사.
Jay Mungara

18

이것이 내가하는 방법입니다. 환경 변수 사용

  signingConfigs {
    release {
        storeFile file(System.getenv("KEYSTORE"))
        storePassword System.getenv("KEYSTORE_PASSWORD")
        keyAlias System.getenv("KEY_ALIAS")
        keyPassword System.getenv("KEY_PASSWORD")
    }

3
불행하게도,이 생성되는 시스템 환경을 필요로 각 프로젝트각 컴퓨터 . 그렇지 않으면 다음과 같은 오류가 발생합니다Neither path nor baseDir may be null or empty string. path='null'
Bobrovsky

@Bobrovsky이 질문에 대한 답변은 알고 있지만 시스템 환경 변수 또는 gradle.properties 파일을 사용할 수 있습니다. gradle.properties 파일을 사용하려고합니다. 여러 프로젝트에 사용할 수 있습니다.
Jared Burrows

3
명령 행에서 Android Studio를 실행하지 않으면 MacOSX에서 작동하지 않습니다.
Henrique de Sousa

위의 모든 사항에 동의합니다. 동일한 구성을 가지고 있으며 Android 스튜디오에서 컴파일 할 수 없습니다. 이 작업을 수행하려면 명령 줄에서 실행해야합니다. 더 나은 방법을 찾고 있으므로 Android Studio에서 실행할 때이 줄에 주석을 달지 않아도됩니다.
Sayooj Valsan

@Bobrovsky : Windows에서 작동합니까?. 시스템 환경에서이 모든 것을 언급해야합니까?
DKV December

12

기존 Android Studio gradle 프로젝트를 가져 와서 파일을 편집하지 않고도 명령 줄에서 빌드 / 서명 할 수 있습니다. 이렇게하면 build.gradle 파일이 아닌 키와 비밀번호를 별도로 유지하면서 프로젝트를 버전 제어에 저장하는 것이 매우 좋습니다.

./gradlew assembleRelease -Pandroid.injected.signing.store.file=$KEYFILE -Pandroid.injected.signing.store.password=$STORE_PASSWORD -Pandroid.injected.signing.key.alias=$KEY_ALIAS -Pandroid.injected.signing.key.password=$KEY_PASSWORD

9

허용 된 답변은 파일을 사용하여 프로젝트의 동일한 루트 폴더에있는 APK에 서명하는 데 사용할 키 저장소를 제어합니다. 우리가 사용하는 경우 VCS 같이 힘내 , 우리가 목록을 무시하는 특성 파일을 추가하는 것을 잊지 나쁜 일이 될 수 있습니다. 비밀번호를 세상에 공개 할 것이기 때문입니다. 문제는 여전히 지속됩니다.

프로젝트 내에서 동일한 디렉토리에 속성 파일을 만드는 대신 외부에 만들어야합니다. gradle.properties 파일을 사용하여 외부에 만듭니다.

단계는 다음과 같습니다.

1. 루트 프로젝트에서 gradle.properties를 편집하거나 작성하고 다음 코드를 추가하십시오. 경로를 직접 편집하십시오.

AndroidProject.signing=/your/path/androidproject.properties  

2. / your / path /에 androidproject.properties를 만들고 다음 코드를 추가하십시오 ./your/path/to/android.keystore를 키 저장소 경로로 변경하는 것을 잊지 마십시오.

STORE_FILE=/your/path/to/android.keystore  
STORE_PASSWORD=yourstorepassword  
KEY_ALIAS=yourkeyalias  
KEY_PASSWORD=yourkeypassword  

3. 앱 모듈 build.gradle (프로젝트 루트 build.gradle 아님)에 다음 코드가 없으면 추가하거나 조정하십시오.

signingConfigs {  
     release  
   }  
   buildTypes {  
   debug {  
     debuggable true  
   }  
   release {  
     minifyEnabled true  
     proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'  
     signingConfig signingConfigs.release  
   }  
 }  

4 단계에서 코드 아래에 다음 코드를 추가하십시오.

if (project.hasProperty("AndroidProject.signing")  
     && new File(project.property("AndroidProject.signing").toString()).exists()) {  
     def Properties props = new Properties()  
     def propFile = new File(project.property("AndroidProject.signing").toString())  
     if(propFile.canRead()) {  
      props.load(new FileInputStream(propFile))  
      if (props!=null && props.containsKey('STORE_FILE') && props.containsKey('STORE_PASSWORD') &&  
         props.containsKey('KEY_ALIAS') && props.containsKey('KEY_PASSWORD')) {  
         android.signingConfigs.release.storeFile = file(props['STORE_FILE'])  
         android.signingConfigs.release.storePassword = props['STORE_PASSWORD']  
         android.signingConfigs.release.keyAlias = props['KEY_ALIAS']  
         android.signingConfigs.release.keyPassword = props['KEY_PASSWORD']  
      } else {  
         println 'androidproject.properties found but some entries are missing'  
         android.buildTypes.release.signingConfig = null  
      }  
     } else {  
            println 'androidproject.properties file not found'  
          android.buildTypes.release.signingConfig = null  
     }  
   }  

이 코드는 1 단계의 gradle.properties 에서 AndroidProject.signing 속성을 검색합니다 . 속성이 발견되면 속성 값을 2 단계 에서 만든 androidproject.properties를 가리키는 파일 경로로 변환합니다 . 그런 다음 모든 속성 값이 build.gradle의 서명 구성으로 사용됩니다.

이제 키 저장소 비밀번호가 노출 될 위험에 대해 다시 걱정할 필요가 없습니다.

build.gradle에 키 저장소 정보를 넣지 않고 Android APK 서명 에서 자세히 알아보십시오.


이것은 나를 위해 잘 작동합니다. 왜 그들이 storeFile 파일 (System.getenv ( "KEYSTORE"))을 사용하는지 아는 것
DKV

9

자격 증명을 외부 JSON 파일 에 넣고 gradle 에서이 정보를 읽으려는 사람들에게 이것이 내가 한 일입니다.

my_project / credentials.json :

{
    "android": {
        "storeFile": "/path/to/acuity.jks",
        "storePassword": "your_store_password",
        "keyAlias": "your_android_alias",
        "keyPassword": "your_key_password"
    }
}

my_project / android / app / build.gradle

// ...
signingConfigs {
        release {

            def credsFilePath = file("../../credentials.json").toString()
            def credsFile = new File(credsFilePath, "").getText('UTF-8')
            def json = new groovy.json.JsonSlurper().parseText(credsFile)
            storeFile file(json.android.storeFile)
            storePassword = json.android.storePassword
            keyAlias = json.android.keyAlias
            keyPassword = json.android.keyPassword
        }
        ...
        buildTypes {
            release {
                signingConfig signingConfigs.release //I added this
                // ...
            }
        }
    }
// ...
}

.json파일 형식이 아닌 파일 형식을 선택 한 이유 .properties(허용 된 답변에서와 같이)는 다른 데이터 (필요한 다른 사용자 정의 속성)를 동일한 파일 ( my_project/credentials.json)에 저장하고 여전히 gradle 파싱하기 때문입니다. 해당 파일 내에서 정보 서명


나에게 가장 좋은 해결책 인 것 같습니다.
주목받는 개발자

4

이 질문은 많은 유효한 답변을 받았지만 원본을 깨끗하게 유지 하기 때문에 라이브러리 관리자 에게 유용한 코드를 공유하고 싶었습니다 .build.gradle

나는 모듈 디렉토리에 폴더를 추가한다 gitignore. 다음과 같이 보입니다 :

/signing
    /keystore.jks
    /signing.gradle
    /signing.properties

keystore.jks그리고 signing.properties자명해야한다. 그리고 이것 signing.gradle처럼 보입니다 :

def propsFile = file('signing/signing.properties')
def buildType = "release"

if (!propsFile.exists()) throw new IllegalStateException("signing/signing.properties file missing")

def props = new Properties()
props.load(new FileInputStream(propsFile))

def keystoreFile = file("signing/keystore.jks")
if (!keystoreFile.exists()) throw new IllegalStateException("signing/keystore.jks file missing")

android.signingConfigs.create(buildType, {
    storeFile = keystoreFile
    storePassword = props['storePassword']
    keyAlias = props['keyAlias']
    keyPassword = props['keyPassword']
})

android.buildTypes[buildType].signingConfig = android.signingConfigs[buildType]

그리고 원래 build.gradle

apply plugin: 'com.android.application'
if (project.file('signing/signing.gradle').exists()) {
    apply from: 'signing/signing.gradle'
}

android {
    compileSdkVersion 27
    defaultConfig {
        applicationId ...
    }
}

dependencies {
    implementation ...
}

보시다시피, 사용자가 유효한 signing디렉토리에 액세스 할 수 있다면 buildTypes를 지정할 필요가 없습니다 . 모듈에 모듈을 넣고 유효한 서명 된 릴리스 응용 프로그램을 빌드 할 수 있습니다. 그렇지 않으면 다음과 같이 작동합니다. 일반적으로 그렇습니다.


나는이 솔루션을 정말 좋아한다. 그러나 블록 apply from이후에 와야합니다android
mgray88

0

명령 행에서 비밀번호를 요청할 수 있습니다.

...

signingConfigs {
  if (gradle.startParameter.taskNames.any {it.contains('Release') }) {
    release {
      storeFile file("your.keystore")
      storePassword new String(System.console().readPassword("\n\$ Enter keystore password: "))
      keyAlias "key-alias"
      keyPassword new String(System.console().readPassword("\n\$ Enter keys password: "))
    } 
  } else {
    //Here be dragons: unreachable else-branch forces Gradle to create
    //install...Release tasks.
    release {
      keyAlias 'dummy'
      keyPassword 'dummy'
      storeFile file('dummy')
      storePassword 'dummy'
    } 
  }
}

...

buildTypes {
  release {

    ...

    signingConfig signingConfigs.release
  }

  ...
}

...

이 답변은 이전에 나타납니다 : https://stackoverflow.com/a/33765572/3664487


이 링크가 질문에 대한 답변을 제공 할 수 있지만 여기에 답변의 필수 부분을 포함시키고 참조 용 링크를 제공하는 것이 좋습니다. 링크 된 페이지가 변경되면 링크 전용 답변이 유효하지 않을 수 있습니다. - 리뷰에서
mkobit

1
@ mkobit, 이것은 Stack Overflow의 내용에 대한 링크입니다! 물론 링크 된 내용을 복사하여 붙여 넣을 수는 있지만 내용이 복제됩니다. 따라서 링크를 게시하는 것이 가장 좋은 해결책이라고 생각합니다. "링크 된 페이지가 변경된다"는 주장은 여기의 내용도 변경 될 수 있다는 점을 기각해야합니다. 귀하의 솔루션을 삭제하는 것이 좋습니다. 링크 된 내용이 훌륭한 솔루션을 제공하기 때문입니다.
user2768

문제는 이것이 여전히 "링크 전용"이라는 것입니다. 해결책은 의견으로 의견을 게시하거나 질문을 중복으로 표시하거나 문제를 해결하는 여기에 새로운 답변을 작성하는 것입니다.
mkobit

경우에 따라 "링크 전용"답변을 권장해야합니다. 그럼에도 불구하고, 나는 당신의 조언과 내용을 복제했습니다. (일부 내용이 업데이트 될 수 있지만 나머지 내용은 업데이트되지 않을 수 있기 때문에 중복 된 내용은 분명 문제가 있습니다.)
user2768

사실, 방금 답변을 업데이트했으며 내용이 중복되어 문제가 발생했습니다! 링크 전용 답변에 대한 정책이있는 경우 그러한 코너 사례를 고려하도록 조정해야합니다.
user2768

0

내 비밀번호에는 달러 기호 $ 라는 특수 문자가 포함되어 있으며 gradle.properties 파일에서이 문자 를 이스케이프해야했습니다. 그 후 서명은 나를 위해 일했습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.