web-dev-qa-db-ja.com

build.gradleにキーストア情報を入れずにAPKに署名する

キーストアのパスワードとキーのパスワードがプロジェクトの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            
        }
    }
}

それは完全に正常に動作しますが、私はしてはいけません私のリポジトリにstorePasswordkeyPasswordの値を入れます。 storeFilekeyAliasのどちらもそこに置かないことを希望します。

build.gradleを変更して、何らかの外部ソース(私のコンピューターにのみ存在するファイルなど)からパスワードを取得する方法はありますか?

そしてもちろん、変更されたbuild.gradleは他のコンピューターでも使用できるはずです(コンピューターがパスワードにアクセスできない場合でも)。

Android St​​udioおよびMac OS X Mavericsを使用している場合は、それが問題になります。

133
Bobrovsky

Groovyの素晴らしい点は、Javaコードを自由に混在させることができ、Java.util.Propertiesを使用してキー/値ファイルを読み取るのが非常に簡単なことです。おそらく、慣用的なGroovyを使用するさらに簡単な方法がありますが、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']
        }
    }
}
109
Scott Barta

あるいは、自動生成された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を省略し、このコードを変更して、異なるキーストアとキーエイリアスのプロパティセットをいくつか持つこともできます。

93
CurlyCorvus

最も簡単な方法は、~/.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
        }
    }
}
27
Dan Fabulich

いくつかのリンクを読んだ後:

http://blog.macromates.com/2006/keychain-access-from-Shell/http://www.thoughtworks.com/es/insights/blog/signing-open -source-Android-apps-without-disclosing-passwords

Mac OSXを使用しているため、キーチェーンアクセスを使用してパスワードを保存できます。

How to add password in Keychain Access

それからあなたの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(currentUser、 "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
        }
    }
}
20
Jared Burrows

これが私のやり方です。環境変数を使用する

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

受け入れられた回答では、ファイルを使用して、プロジェクトの同じルートフォルダーにあるAPKの署名に使用するキーストアを制御します。 Git のような 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.手順3のコードの下に次のコードを追加します。

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  
     }  
   }  

このコードは、step 1からgradle.propertiesでAndroidProject.signingプロパティを検索します。プロパティが見つかった場合、プロパティ値をstep 2で作成したandroidproject.propertiesを指すファイルパスとして変換します。次に、そこからのすべてのプロパティ値がbuild.gradleの署名設定として使用されます。

これで、キーストアのパスワードが公開されるリスクを心配する必要がなくなりました。

詳しくは build.gradleにキーストア情報を入れずにAndroid apkに署名

既存のAndroid St​​udio 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
6
Wayne Piekarski

資格情報を外部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がそのファイル内からの署名情報も解析します。

6
SudoPlz

この質問には多くの有効な回答が寄せられましたが、ライブラリメンテナーに役立つ可能性のあるコードを共有したかったのは、元の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 ...
}

ご覧のとおり、buildTypesを指定する必要はありません。ユーザーが有効なsigningディレクトリにアクセスできる場合、モジュールにそれを配置するだけで、有効な署名済みリリースアプリケーションをビルドできます。普通に彼のように機能します。

3
Michał K

コマンドラインからパスワードをリクエストできます:

...

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

0
user2768