Skip to content

Commit 72008d4

Browse files
authored
Merge pull request #132 from garanj/main
Fixes watch face release obfuscation and optimization issues
2 parents eea3828 + 8e4fc6d commit 72008d4

File tree

6 files changed

+52
-21
lines changed

6 files changed

+52
-21
lines changed

watchface/README.md

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,4 @@ example, using `pngquant` on all images, to help keep the watch face size to a m
2121

2222
To package the watch face, the [Pack](https://github.com/google/pack) is used. This is a native
2323
library, so the pre-builts are provided in `jniLibs`. A script is also included for building these
24-
fresh, but that should not be necessary.
25-
26-
## Signing the APK
27-
28-
For the purposes of this project, a key is generated at runtime and used to sign the APK. This is
29-
not the approach to take in production, but the watch face APK must be signed, and it doesn't so
30-
much matter what key is used to do it.
24+
fresh, but that should not be necessary.

watchface/build.gradle.kts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,11 @@ android {
3030
minSdk = libs.versions.minSdk.get().toInt()
3131
targetSdk = 36
3232
testInstrumentationRunner = "com.android.developers.testing.AndroidifyTestRunner"
33+
consumerProguardFiles("proguard-rules.pro")
34+
}
35+
buildFeatures {
36+
buildConfig = true
3337
}
34-
3538
compileOptions {
3639
sourceCompatibility = JavaVersion.toVersion(libs.versions.javaVersion.get())
3740
targetCompatibility = JavaVersion.toVersion(libs.versions.javaVersion.get())

watchface/pack-java/Cargo.lock

Lines changed: 8 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

watchface/proguard-rules.pro

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,29 @@
66
-dontwarn org.eclipse.wst.xml.xpath2.processor.**
77

88
# Ignore missing Java SE annotation processing classes, often from libraries like AutoValue/JavaPoet
9-
-dontwarn javax.lang.model.**
9+
-dontwarn javax.lang.model.**
10+
11+
-keep class com.android.developers.androidify.watchface.creator.PackPackage {
12+
native <methods>;
13+
}
14+
15+
-keep class com.android.developers.androidify.watchface.creator.PackPackage$Resource { *; }
16+
17+
# Keep all classes in the BouncyCastle provider, as they are loaded via reflection
18+
-keep class org.bouncycastle.** { *; }
19+
-keep interface org.bouncycastle.** { *; }
20+
21+
# Keep the APK Signer library
22+
-keep class com.android.apksig.** { *; }
23+
-keep interface com.android.apksig.** { *; }
24+
25+
# Keep Apache Xerces XML parser
26+
-keep class org.apache.xerces.** { *; }
27+
28+
## Keep standard Java XML (JAXP), DOM, and SAX interfaces and classes
29+
-keep interface org.w3c.dom.** { *; }
30+
-keep class org.w3c.dom.** { *; }
31+
-keep interface org.xml.sax.** { *; }
32+
-keep class org.xml.sax.** { *; }
33+
-keep class javax.xml.** { *; }
34+
-keep interface javax.xml.** { *; }

watchface/src/main/java/com/android/developers/androidify/watchface/creator/PackPackage.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@ data class PackPackage(
2424
var resources: MutableList<Resource> = mutableListOf()
2525

2626
data class Resource(
27-
val subdirectory: String,
28-
val name: String,
29-
val contentsBase64: String,
27+
@JvmField val subdirectory: String,
28+
@JvmField val name: String,
29+
@JvmField val contentsBase64: String,
3030
) {
3131
companion object {
3232
fun fromBase64Contents(

watchface/src/main/java/com/android/developers/androidify/watchface/creator/Signer.kt

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import com.android.apksig.util.DataSink
2323
import com.android.apksig.util.DataSource
2424
import com.android.apksig.util.DataSources
2525
import com.android.apksig.util.ReadableDataSink
26+
import com.android.developers.androidify.watchface.BuildConfig
2627
import org.bouncycastle.asn1.x500.X500Name
2728
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter
2829
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder
@@ -38,8 +39,10 @@ import java.security.cert.X509Certificate
3839
import java.util.Calendar
3940
import java.util.Date
4041

41-
private const val KEY_ALIAS = "com.android.developers.androidify.ApkSigningKey"
42-
private const val CERT_ALIAS = "com.android.developers.androidify.Cert"
42+
private val keyAlias : String
43+
get() = "com.android.developers.androidify.ApkSigningKey-" + BuildConfig.BUILD_TYPE
44+
private val certAlias: String
45+
get() = "com.android.developers.androidify.Cert-" + BuildConfig.BUILD_TYPE
4346
private const val ANDROID_KEYSTORE = "AndroidKeyStore"
4447

4548
/**
@@ -71,13 +74,13 @@ fun signApk(unsignedApk: ByteArray): ByteArray {
7174
private fun getOrCreateSigningKeyPair(): KeyPair {
7275
val keyStore = KeyStore.getInstance(ANDROID_KEYSTORE).apply { load(null) }
7376

74-
if (keyStore.containsAlias(KEY_ALIAS)) {
75-
val entry = keyStore.getEntry(KEY_ALIAS, null) as KeyStore.PrivateKeyEntry
77+
if (keyStore.containsAlias(keyAlias)) {
78+
val entry = keyStore.getEntry(keyAlias, null) as KeyStore.PrivateKeyEntry
7679
return KeyPair(entry.certificate.publicKey, entry.privateKey)
7780
}
7881

7982
val parameterSpec = KeyGenParameterSpec.Builder(
80-
KEY_ALIAS,
83+
keyAlias,
8184
KeyProperties.PURPOSE_SIGN,
8285
).run {
8386
setDigests(KeyProperties.DIGEST_SHA256)
@@ -151,7 +154,7 @@ private fun storeCertificate(certificate: X509Certificate): Boolean {
151154
val keyStore = KeyStore.getInstance(ANDROID_KEYSTORE).apply {
152155
load(null)
153156
}
154-
keyStore.setCertificateEntry(CERT_ALIAS, certificate)
157+
keyStore.setCertificateEntry(certAlias, certificate)
155158
true
156159
} catch (e: Exception) {
157160
// Log the exception for debugging
@@ -169,7 +172,7 @@ private fun getOrCreateCertificate(keyPair: KeyPair): X509Certificate {
169172
val keyStore = KeyStore.getInstance(ANDROID_KEYSTORE).apply {
170173
load(null)
171174
}
172-
return (keyStore.getCertificate(CERT_ALIAS) ?: createCertificate(keyPair)) as X509Certificate
175+
return (keyStore.getCertificate(certAlias) ?: createCertificate(keyPair)) as X509Certificate
173176
}
174177

175178
/**

0 commit comments

Comments
 (0)