APK'yı build.gradle'da anahtar deposu bilgisi koymadan imzala


152

O deposu şifrenizi ve anahtar şifre yüzden kurulum imza işlemi çalışıyorum değildir projenin saklanan build.gradledosyanın.

Şu anda aşağıdaki var build.gradle:

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

    buildTypes {
        release {
            signingConfig signingConfigs.release            
        }
    }
}

Mükemmel çalışıyor ama olmamalıdır değerlerini koymak storePasswordve keyPasswordbenim depoda. Ben koymak değil tercih ederim storeFileve keyAliasorada ya.

build.gradleBazı harici kaynaklardan (yalnızca bilgisayarımda bulunan bir dosya gibi) parola alacak şekilde değiştirmenin bir yolu var mı ?

Ve elbette, değiştirilmiş olan build.gradlebaşka bir bilgisayarda kullanılabilir olmalıdır (bilgisayar parolalara erişimi olmasa bile).

Önemli olursa Android Studio ve Mac OS X Maverics'te kullanıyorum.


"Ve tabii ki, değişmiş build.gradle (bilgisayar şifrelerine erişimi yoksa bile) herhangi başka bir bilgisayarda kullanılabilir olmalıdır" - Veri değilse build.gradle, sen dışında bir şey olması gerekir build.gradle, ister bu, ortam değişkenlerine (bir yanıt başına), özellikler dosyasına (başka bir yanıt başına) veya başka yollara yapılan bir düzenlemedir. Dışarıda bir şeyler yapmak istemiyorsanız build.gradle, tanım gereği tüm imzalama bilgileri içeride olmalıdır buid.gradle .
CommonsWare

2
@CommonsWare Haklısın. Yine de build.gradle içinde kesinlikle bir şey olmasını istediğimi söylemedim. Ve build.gradle'ın bazı harici kaynaklardan parola
Bobrovsky


Yanıtlar:


120

Groovy ile ilgili güzel bir şey, Java kodunu özgürce karıştırabilmeniz ve kullanarak bir anahtar / değer dosyasında okunması oldukça kolaydır java.util.Properties. Belki de deyimsel Groovy kullanmanın daha kolay bir yolu var, ancak Java hala oldukça basit.

Bir keystore.propertiesdosya oluşturun (bu örnekte, projenizin kök dizininde) settings.gradle, ancak istediğiniz yere koyabilirsiniz:

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

Bunu şu adrese ekleyin 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
Benim keystore.properties üzerinden tırnak kaldırmak zorunda kaldı
Jacob Tabak

6
Eklenti sürümü 0.9. + İle benim için imzalı sürümü oluşturmaz. SigningConfigs block ve buildTypes.release.signingConfig öğesiyle ne yapmam gerekiyor? onları kaldır?
Fernando Gallego

1
StoreFile ayarının geçerli herhangi bir değere (ör. storeFile file('AndroidManifest.xml')) Ayarlanıp daha sonra geçersiz kılınmasının imzalama işleminin gerçekleşmesine neden olduğu görülmektedir.
miracle2k

5
Bina Error:(24, 0) Could not find property 'android' on root project 'RootProjectName', satır 24'ün if-bloğuna sahip olduğu hatayla sonuçlanır . apply plugin: 'com.android.application'Kök build.gradle öğesine eklemek de derlemenin başarısız olmasına izin verir. Neyi yanlış yapıyorum?
PhilLab

2
Bu 2018 yılında işe yaramıyor. Onaylanmadı mı? Bu hata atmaya devam ettiCould not get unknown property 'android' for root project
Neon Warge

106

Alternatif olarak, Scott Barta'nın yanıtını otomatik oluşturulan not koduna daha benzer bir şekilde uygulamak isterseniz keystore.properties, proje kök klasörünüzde bir dosya oluşturabilirsiniz :

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

ve not kodunuzu şu şekilde değiştirin:

// 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']
        }
    }

    ...

}

Bu özellikler dosyasını modülünüzün kökünde depolayabilirsiniz, bu durumda atlayın rootProjectve bu kodu farklı anahtar depoları ve anahtar takma adları için birkaç özellik kümesine sahip olacak şekilde değiştirebilirsiniz.


7
Harika çalışıyor. if ( keystorePropertiesFile.exists() )Öznitelikleri alıp imzalamaya çalışmadan önce dosyanın mevcut olduğundan emin olurdum .
Joshua Pinter

Ve dosyanın .txtsonuna uzantı eklemeyi unutmayın keystore.properties.
Levon Petrosyan

11
Dosyada bir .txtuzantıya ihtiyacınız olmamalıdır keystore.properties.
Matt Zukowski

2
Bu bilgi buraya eklendi gibi görünüyor - developer.android.com/studio/publish/…
Vadim Kotov

36

En kolay yol bir ~/.gradle/gradle.propertiesdosya oluşturmaktır .

ANDROID_STORE_PASSWORD=hunter2
ANDROID_KEY_PASSWORD=hunter2

Ardından build.gradledosyanız şu şekilde görünebilir:

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

1
Gitignore ~ ​​/ .gradle / gradle.properties yapmalı mıyım?
vzhen

Tam talimatlar aynı zamanda yerel belgelerle de ilgilidir.
Pencilcheck

23

Birkaç bağlantıyı okuduktan sonra:

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

Mac OSX kullandığınız için, şifrelerinizi saklamak için Anahtarlık Erişimi'ni kullanabilirsiniz.

Anahtarlık Erişimi'nde şifre nasıl eklenir

Sonra sınıf yazılarınızda:

/* 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]
}

Bunun gibi kullanın:

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

2
Cevabınız sadece Mac OSX için geçerli olsa da, gerçekten beğendim! Sağladığınız ikinci bağlantının, birisinin çoklu platform desteği uygulaması gerektiğinde diğer platformlar için bir yedekleme çözümü içerdiğini unutmayın.
Delblanco

Linux ve pencereler için de aynı çözümü sağlayabilir misiniz? Teşekkürler.
Jay Mungara

18

Ben böyle yaparım. Ortam Değişkenlerini Kullan

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

3
Ne yazık ki, bu , her bilgisayardaki her proje için sistem ortamlarının oluşturulmasını gerektirir . Aksi takdirde şu hatayı alıyorumNeither path nor baseDir may be null or empty string. path='null'
Bobrovsky

@Bobrovsky Bu sorunun cevaplandığını biliyorum, ancak sistem ortamı değişkenlerini veya gradle.properties dosyasını kullanabilirsiniz. Muhtemelen gradle.properties dosyasını kullanmak istiyorsunuz. Birden fazla proje için kullanabilirsiniz.
Jared Burrows

3
Android Studio'yu komut satırından çalıştırmadığınız sürece bu MacOSX üzerinde çalışmaz.
Henrique de Sousa

Yukarıdakilere katılıyorum. Aynı yapılandırmaya sahibim ve bunu Android stüdyosunda derleyemezsiniz. Bunun çalışması için komut satırından çalıştırmanız gerekir. Daha iyi bir yol arıyorum, böylece Android Studio'da çalışırken bu satırlara yorum yapmak zorunda değilim.
Sayooj Valsan

@Bobrovsky: Pencerelerde çalışıyor mu? Tüm bunları sistem ortamlarında belirtmeli miyiz?
DKV

12

Mevcut herhangi bir Android Studio gradle projesini almak ve herhangi bir dosyayı düzenlemeden komut satırından oluşturmak / imzalamak mümkündür. Bu, anahtarlarınızı ve parolalarınızı build.gradle dosyanızda değil, ayrı tutarken projenizi sürüm kontrolünde depolamayı çok güzel hale getirir:

./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

Kabul edilen cevap, projenin aynı kök klasöründe bulunan APK'yı imzalamak için hangi anahtar deposunun kullanılacağını kontrol etmek için bir dosya kullanır. Git gibi vcs kullandığımızda , göz ardı edilecek özellikler dosyasını eklemeyi unuttuğumuzda kötü bir şey olabilir. Çünkü şifremizi dünyaya açıklayacağız. Sorunlar hala devam ediyor.

Özellikler dosyasını projemiz içinde aynı dizinde yapmak yerine dışarıda yapmalıyız. Gradle.properties dosyasını kullanarak dışarıda yapıyoruz.

İşte adımlar:

Kök projenizde gradle.properties dosyasını düzenleyin veya oluşturun ve aşağıdaki kodu ekleyin, yolu kendinizle düzenlemeyi unutmayın:

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

2. /pro / yolunuzda androidproject.properties oluşturun ve aşağıdaki kodu ekleyin, /your/path/to/android.keystore anahtar deponuzun yolunu değiştirmeyi unutmayın:

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

3. uygulama modülünüzde build.gradle (proje kökü build.gradle değil) yoksa aşağıdaki kodu ekleyin veya buna ayarlayın:

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

4.Adım 3'teki kodun altına aşağıdaki kodu ekleyin:

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

Bu kod, 1. adımdaki gradle.properties dosyasında AndroidProject.signing özelliğini arayacaktır . Özellik bulunursa, özellik değerini 2. adımda oluşturduğumuz androidproject.properties'e işaret eden dosya yolu olarak çevirir . Ardından, tüm özellik değeri build.gradle için imzalama yapılandırması olarak kullanılacaktır.

Artık anahtar deposu şifremizi ifşa etme riski konusunda tekrar endişelenmemize gerek yok.

Devamı için build.gradle içinde deposu bilgi koymadan imzalanması Android Apk'nizin


Bu benim için iyi çalışıyor. sadece storeFile dosyasını neden kullandıklarını bilmek (System.getenv ("KEYSTORE"))
DKV

9

Kimlik bilgilerini harici bir JSON dosyasına koymak isteyenler için ve sınıftan okumak istediğim şey budur:

my_project / credentials.json:

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

my_project / robot / uygulama / 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
                // ...
            }
        }
    }
// ...
}

Bir .jsondosya türünü seçmememin nedeni .properties(kabul edilen yanıtta olduğu gibi) bir dosya türü seçmemin nedeni, aynı dosyaya ( my_project/credentials.json) ihtiyaç duyduğum diğer özel özellikleri (diğer özel özellikleri) depolamak ve yine de gradle ayrıştırma yapmak bu dosyadan da bilgi imzalama.


Benim için en iyi çözüm gibi görünüyor.
Aspiring Dev

4

Bu soru birçok geçerli Cevap verilmiş ama için yararlı olabilir kodumu paylaşmak istedim kütüphane sürdürüp çünkü, orijinal bırakır build.gradleoldukça temiz .

Modül dizinine bir klasör ekliyorum gitignore. Şöyle görünüyor:

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

keystore.jksve signing.propertieskendi kendini açıklayıcı olmalıdır. Ve signing.gradleşöyle görünüyor:

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]

Ve orijinal 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 ...
}

Gördüğünüz gibi, buildTypes'i belirtmek zorunda değilsiniz, eğer kullanıcı geçerli bir signingdizine erişebiliyorsa , sadece modüle koyar ve geçerli bir imzalı sürüm uygulaması oluşturabilir, aksi takdirde onun için çalışır normalde olurdu.


Bu çözümü gerçekten çok seviyorum. Ancak, blok apply fromsonra gelmelidirandroid
mgray88

0

Komut satırından parola isteyebilirsiniz:

...

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
  }

  ...
}

...

Bu cevap daha önce ortaya çıktı: https://stackoverflow.com/a/33765572/3664487


Bu bağlantı soruyu cevaplayabilse de, cevabın temel kısımlarını buraya eklemek ve bağlantıyı referans olarak sağlamak daha iyidir. Bağlantı verilen sayfa değişirse, yalnızca bağlantı yanıtları geçersiz olabilir. - Şu kaynaktan
mkobit

1
@mkobit, bu Stack Overflow'daki içeriğe bir link! Tabii ki, bağlı içeriği kopyalayıp yapıştırabilirim, ancak bu yinelenen içeriğe yol açar. Bu nedenle, yanılıyorsam, bir bağlantı yayınlamanın en iyi çözüm olduğunu varsayıyorum ve düzeltiyorum. "Bağlantılı sayfa değişti" iddiası, buradaki içeriğin de değişebileceği gerekçesiyle reddedilmelidir. Silmek için çözümünüzü şiddetle tavsiye ederim! Çünkü bağlantılı içerik mükemmel bir çözüm sunar.
user2768

Bence sorun hala "sadece link" yanıtı. Çözüm, yorum olarak göndermek, soruyu kopya olarak işaretlemek veya sorunu ele alan yeni bir cevap yazmaktır.
mkobit

Bazı durumlarda "yalnızca bağlantı" yanıtları teşvik edilmelidir. Yine de, tavsiyelerinizi ve çoğaltılan içeriği izledim. (Çoğaltılan içerik açıkça sorunludur, çünkü bazı içerikler güncellenebilir, ancak kalan içerik olmayabilir.)
user2768 18:15

Gerçekten, ben sadece cevap güncelledim ve yinelenen içerik sorunlara neden oluyor! Yalnızca bağlantı yanıtlarına karşı bir politika varsa, bu tür köşe vakalarını dikkate alacak şekilde uyarlanmalıdır.
user2768

0

Şifrem özel karakter Dolar işareti içerdiği $ ve ben gradle.properties dosyasında olduğunu kaçmak zorunda kaldı. Ondan sonra imza benim için çalıştı.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.