I'm working on MirrorLink-aware Android application and faced issues with Mirrorlink's check of 'application ID' after signing APK with Google developer key.
I have created empty project generated with Mirrorlink plugin for Android studio, which created Gradle task allowing to generate .crt
file with Mirrorlink-related configuration info. I just copied this script to my own build.gradle
file in the main app module. But Mirrorlink-aware application validator show error for signed APK (standard app signing for publishing to Google Play), while find no problems if APK is unsigned.
How to find out the issue arisen after the app was signed?
What I tried: 1) Align Gradle script with example app provided by Mirrorlink - no luck.
2) Inserting v1SigningEnabled false
and v2SigningEnabled false
- no luck.
3) Gradle outputs for signed- and unsigned APKs are the same, except of output file name and > Task :app:validateSigningRelease
task.
AndroidManifest.xml Mirrorlink-related snipped:
<uses-permission android:name="com.mirrorlink.android.service.ACCESS_PERMISSION"/>
<intent-filter>
<action android:name="com.mirrorlink.android.app.LAUNCH"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
<intent-filter>
<action android:name="com.mirrorlink.android.app.TERMINATE"/>
<category android:name="android.intent.category.DEFAULT"/>
App module's build.gradle:
def generateSelfSignedCertificate(version){
def buildType = version == "release" ? "assembleRelease": "assembleDebug"
def rerunAssemble = true
def projectLocation = projectDir.toString()
def certGeneratorLocation = "certificategenerator-android-studio.jar"
def certXmlLocation = projectLocation + "/certificate.xml"
def certificateDestination = projectLocation + "/src/main/assets/self-signed.ccc.crt"
def certificateFolder = projectLocation + "/src/main/assets/"
def certificateIssuer = "CN=SELF-SIGNED"
def developerId = ""
def apkLocation = ""
android.applicationVariants.all { variant ->
if ((variant.name).equals(version)) {
variant.outputs.each { output ->
//noinspection GrReassignedInClosureLocalVar
apkLocation = output.outputFile
}
}
}
if (project.hasProperty("isLast")) {
rerunAssemble = !isLast
}
if (rerunAssemble) {
def subdir = new File(certificateFolder)
if( !subdir.exists() ) {
subdir.mkdirs()
}
exec {
executable 'java'
args "-jar", certGeneratorLocation, "generate-certificate", apkLocation,
android.defaultConfig.applicationId, android.defaultConfig.versionCode,
certXmlLocation, certificateDestination, certificateIssuer, developerId
println(args)
}
if (System.properties['os.name'].toLowerCase().contains("windows")) {
exec {
executable "cmd"
workingDir projectLocation
args "/c", "..\\gradlew.bat", buildType, "-PisLast=true"
}
} else {
exec {
executable "bash"
workingDir projectLocation
args "../gradlew", buildType, "-PisLast=true"
}
}
}
}
android {
.....
signingConfigs {
storeFile = 'sign.keyStorePath')
keyAlias = 'sign.keyAlias'
storePassword = 'sign.storePassword'
keyPassword = 'sign.keyPassword'
}
}
afterEvaluate {
if (this.hasProperty("assembleRelease")){
assembleRelease.finalizedBy generateSelfSignedCertificateForRelase
}
}
task generateSelfSignedCertificateForRelase {
doLast {
generateSelfSignedCertificate("release")
}
}
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release
}
}
}
....
}
Running "assesbleRelease" runs with no problems - it produces .crt file with Mirrorlink application ID. But if I put this file in "Mirrorlink-aware application validator" - it shows error report, as follows:
Checking com.mirrorlink.android.app.LAUNCH intent - OK
Checking com.mirrorlink.android.app.TERMINATE intent - OK
Checking com.mirrorlink.android.service.ACCESS_PERMISSION permission - OK
Checking DEVELOPER entity - INCONCLUSIVE. DEVELOPER entity not found
Checking if developer certificate exists for serverID="" - INCONCLUSIVE. DEVELOPER entity not found
Checking application id - FAIL. Calculated application ID doesn't mach id provided in self signed certificate
Checking self signed certificate - OK
The APK is not configured correctly.
BUT if I remove the string signingConfig signingConfigs.release
the validator finds no problems:
Checking com.mirrorlink.android.app.LAUNCH intent - OK
Checking com.mirrorlink.android.app.TERMINATE intent - OK
Checking com.mirrorlink.android.service.ACCESS_PERMISSION permission - OK
Checking DEVELOPER entity - INCONCLUSIVE. DEVELOPER entity not found
Checking if developer certificate exists for serverID="" - INCONCLUSIVE. DEVELOPER entity not found
Checking application id - OK
Checking self signed certificate - OK
The APK is correctly configured as a MirrorLink Aware application.
Well, guys, I found the issue :)
I have Crashlytics in the project, and it creates file crashlytics-build.properties
that is slightly changed on every build.
And yeah, this file is counted by Mirrorlink's tool certificategenerator-android-studio.jar
that generates appID with certificate. I have done some reverse-engineering and checked what is happening inside of this tool: it only skips assets/self-signed.ccc.crt
file and META-INF/
content.
So, I had slightly different APKs on EVERY assemble... Disabling Crashlytics plugin solves the issue.
You can either disable Crashlytics plugin (bad idea), or use ext.alwaysUpdateBuildId = false
param to skip creating unique build ID. Read more here.