I have an Android APK in the Google Play store with an Target SDK of 23.
I have released a new version (same target SDK) and Google shows me this error:
If I proceed (I learnt the hard way) then none of the current users can upgrade to this version. I had to restore the code, increment the build number and rebuild the APK to "rollback" to a usable version.
However, I cannot work out WHY google is showing me this error. Note, the "0 Supported Android Devices" is a red-herring - it is a known issue in Google Play in the last 24 hours - if you publish the APK the real number of devices is shown.
Please give me some leads on what the difference is or what causes this error:
Non-upgradable APK
WARNING
None of the users of this APK will be able to upgrade to any of the new APKs added in this release.
TIP
Ensure that all your new APKs are added to this release.
I got able to resolve this issue:-
The issue was with the versioncode - I am sure you have not defined any version code in your App and it is getting generated by this formula:
versionCode = MAJOR * 10000 + MINOR * 100 + PATCH
But sometimes auto generated versioncode value of the latest release becomes smaller than the previous release (in your case 10403 < 104028) and that's why it shows non-upgradable APK.
What you need to do is:-
In your config.xml in tag add versioncode like below:-
android-versionCode="104280"
104280 will work for you as it is greater than older version.
Now get it published without any error.
Thanks Sanny
I'm using VS-TACO and ran into this problem.
To slightly clarify Sanny's answer which fixed the issue for me. Apparently, somewhere along the way the android-versionCode was calculated using this formula:
MAJOR * 100000 + MINOR * 1000 + PATCH * 10
but now it is getting calculated using the version Sanny shows:
MAJOR * 10000 + MINOR * 100 + PATCH
So for example if your version was 1.3.1 android-versionCode was calculated as "103010"
now you change the version to 1.3.2 and it is calculated the new way so the version is "10302" which is less than "103010".
So to work around this issue (I guess forever if the android version keeps getting calculated the new way) you can add the version tag to your config.xml:
<?xml version="1.0" encoding="utf-8"?>
<widget android-versionCode="103020" ...
or you can go into Visual Studio and use the visual editor for config.xml, go to the "Android" section and change the "Version Code:" value.
I ran into a similar problem but was able to solve it with the following Node script used as part of my continuous deployment pipeline.
Note:
This reads from a VERSION.md file that contains the current app version.
It may also be run with the --version argument to only update the current version in config.xml without setting the build versions.
#!/usr/bin/env node
var fs = require('fs');
var xml2js = require('xml2js');
const cliArgs = require('command-line-args');
const options = cliArgs([
{name: 'version', type: Boolean}
]);
// Read config.xml
var xml = fs.readFileSync('config.xml', 'utf8');
// Parse XML to JS Obj
xml2js.parseString(xml, function (err, result) {
if(err) {
return console.log(err);
}
// Get JS Obj
var obj = result;
const version = fs.readFileSync('VERSION.md', 'utf8');
if (options.version){
// Write current version
obj['widget']['$']['version'] = version;
} else {
// Increment build numbers (separately for iOS and Android)
obj['widget']['$']['ios-CFBundleVersion'] = version;
// remove all periods to create an integer for Android
const [major, minor, patch] = version.split('.')
obj['widget']['$']['android-versionCode'] = major+pad_number(minor)+pad_number(patch);
}
// Build XML from JS Obj
var builder = new xml2js.Builder();
var xml = builder.buildObject(obj);
// Write config.xml
fs.writeFile('config.xml', xml, function(err) {
if(err) {
return console.log(err);
}
console.log('Build number successfully incremented');
});
});
/**
* Pad a number with prepending zeros if less than 10
* #see [Javascript function to pad a string](https://stackoverflow.com/questions/2686855/is-there-a-javascript-function-that-can-pad-a-string-to-get-to-a-determined-leng)
*/
function pad_number(orig) {
return ("00"+orig).slice(-2);
}
I just had the same issue with the versions, as I upgraded react-native to 0.60.5
So I calculated the differences between missing versionCode version
Version 1.9 = VersionCode => 4194313
Version 1.10 = VersionCode = 3145739
Difference : 194313 - 3145739 = 1048574
Each APK per architecture will use that formula
versionCodes.get(abi) * 1048576 + defaultConfig.versionCode
I have modified a little bit my formula
versionCodes.get(abi) * 1048576 + defaultConfig.versionCode + 1048574
// applicationVariants are e.g. debug, release
applicationVariants.all { variant ->
variant.outputs.each { output ->
// For each separate APK per architecture, set a unique version code as described here:
// https://developer.android.com/studio/build/configure-apk-splits.html
def versionCodes = ["armeabi-v7a": 1, "x86": 2, "arm64-v8a": 3, "x86_64": 4]
def abi = output.getFilter(OutputFile.ABI)
if (abi != null) { // null for the universal-debug, universal-release variants
output.versionCodeOverride =
versionCodes.get(abi) * 1048576 + defaultConfig.versionCode + 1048575;
}
}
For those of you using Android Studio, I had this problem after upgrading from Eclipse to Android Studio and not configuring the gradle files properly.
Make sure the version code in your build.gradle in defaultConfig{} is correct.
...
defaultConfig {
...
versionCode 373
versionName "3.73"
I ran into this issue because in my cordova config.xml the previous version was 0.0.51 and the new version was 0.0.6. But in the playstore console, those numbers were converted to 51 and 6 for the APK number. One can't "upgrade" from 51 to 6. So I changed the xml to be 0.0.60, which made the APK number 60, and voila, I can update from 51 to 60.
Related
Right now my the app in the internal track has a version code of 565800002 and that in production has a version code of 291302934 which comes from the CircleCI build number * 100,000.
I would like to increment both version code numbers
internal and production
programmatically, especially the one on internal, but I'm stuck on how to do it.
You can use any groovy function or def to build your version code programmatically.
For ex,
**
* Use the number of seconds/10 since Dec 12 2017 as the versionCode.
* This lets us upload a new build at most every 10 seconds for the
* next 680 years.
*/
def verCode = (int) (((new Date().getTime() / 1000) - 1513056598) / 10)
Then in your defaultConfig block, you can use,
versionCode verCode
I took a project from github and developed a few functionalities that I needed for my own use.
I created a new apk after finishing those, the phone recognizes it as being a new version of the existing app, but it fails installation after a few seconds of "Installing". App not installed.
Links to printscreens:
https://gyazo.com/93b94183572f139d9a07b937c5a1eed2
https://gyazo.com/bdbee5e182f7e8d69ee00c7daac88cf3
I've displayed my current versionCode and it was something about 10230000. Tried to change it in gradle to 10230008, still fails. Changed my app versionName as well without any positive result.
The initial version of module gradle was:
...
versionName rootProject.ext.versionName
versionCode rootProject.ext.versionCode
buildConfigField 'String', 'REALM_ENCRYPTION_KEY', "\"${rootProject.ext.realmEncryptionKey}\""
...
Project gradle:
...
apply plugin: 'kotlin'
ext {
versionName = project['version.major'] + '.' +
project['version.minor'] + '.' +
project['version.patch']
versionCode = (project['version.major'].toInteger() * 1000 * 1000 * 1000) +
(project['version.minor'].toInteger() * 1000 * 1000) +
(project['version.patch'].toInteger() * 1000) +
project['version.build'].toInteger()
bugsnagAPIKey = System.getenv('BUGSNAG_API_KEY') ?: ''
realmEncryptionKey = System.getenv('REALM_ENCRYPTION_KEY') ?: 'ZX06poC7a96dL9,FR_9|Ww<2%]?4Ij(3wR3DmyNj0[{(,8g%jX2{03P45_p`N6|2'
}
...
Why can't the app be installed even though it is recognized as being an update?
Try in android studio:
Go to File -> Settings -> Build, Execution, Deployment -> Instant Run
and turn it of.
And try in you android phone:
Settings -> Apps & notifications -> See all x apps ->
Search your app and click on it and do FORCE STOP and UNINSTALL.
If you wants to update this application from the previous binary release (that is, you took this .apk from GitHub directly, and install it into your phone, compared to build the previous version from source code), then you have two choices:
Ask the original packager (author?) to pack your source for you.
Uninstall the previous APK, then install the new one.
Crack the signing key.
The easiest way is obviously the second one.
In my memory, the core of original question is the signing key of that .apk file.
If you are trying to update the app, the excited version on the device must have the same signature as the new version, otherweise it will not being installed. The ones you can try to do is uninstall the app and then reinstall it, then they will work well.
It may also be because you do not have enough expression for the new update.
I was compiling my React Native App for Android having enableSeparateBuildPerCPUArchitecture to false but since I read if I set to true, then the app will reduce like 4mb and it's true.
So my current version code was 9 so I set to 10 the new one and when I created a new release with that option to true I uploaded it to my Google Play dashboard and I realised the new version code is not 10 but is 1048586 :/
Fortunately I don't published that version and I just removed it but I'm wondering what happened and if that's normal and if I create a new version after that, the number will increate just 1 unit like 1048586 to 1048587?
Thanks!
EDIT
I found the line of code that set the version code
applicationVariants.all { variant ->
variant.outputs.each { output ->
// For each separate APK per architecture, set a unique version code as described here:
// http://tools.android.com/tech-docs/new-build-system/user-guide/apk-splits
def versionCodes = ["armeabi-v7a":1, "x86":2]
def abi = output.getFilter(OutputFile.ABI)
if (abi != null) { // null for the universal-debug, universal-release variants
output.versionCodeOverride =
versionCodes.get(abi) * 1048576 + defaultConfig.versionCode
}
}
}
But still I couldn't find the real reason about why it's necessary to increase the version code to a big number
"We need this because each APK in the ABI requires a separate version code which goes up each time the app updates. This code block adds a different constant for each architecture to your base version code. Each APK then get their own distinct values which are unlikely to overlap. For more details take a look at the Android documentation for ABI splits."
https://reactnative.thenativebits.com/courses/upgrading-react-native/upgrade-to-react-native-0.59/
Therefore you need to "give up control" of your versionCode to the build system and rely on the versionName instead.
Let's assume you multiplied with a small number .... like say 2.
So apk version codes for ["armeabi-v7a":1, "x86":2] will be
When you set the android: default version code to be 1:
armeabi-v7a: 1 * 2 + 1 = 3
x86: 2 * 2 + 1 = 5
Let's say you have another release now and decide to to use default version code to be 2. Hence version codes for architectures:
armeabi-v7a: 1 * 2 + 2 = 4
x86: 2 * 2 + 2 = 6
Now in the next release when you use default version code of 3, you'll notice that we run into issues. Here, version codes for architectures:
armeabi-v7a: 1 * 2 + 3 = 5 (CONFLICTS with x86 version code for 1st release)
x86: 2 * 2 + 3 = 7
PS: The above answer is solely based on my understanding/interpretation and the original authors could very well have had an entirely different reason.
change - def enableSeparateBuildPerCPUArchitecture from true to false after that whenever you create a build it should be increment with +1 only.
I am currently working on a Cordova project and had the problem that 8 was appended mysteriously to the versionCode of my project. For example: My original Version code was 100, the new Version code is 1008
I tracked the problem through my whole build pipeline and found the responsible code in the Gradle Build script.
if (Boolean.valueOf(cdvBuildMultipleApks)) {
productFlavors {
armv7 {
versionCode cdvVersionCode ?: defaultConfig.versionCode + 2
ndk {
abiFilters "armeabi-v7a", ""
}
}
x86 {
versionCode cdvVersionCode ?: defaultConfig.versionCode + 4
ndk {
abiFilters "x86", ""
}
}
all {
ndk {
abiFilters "all", ""
}
}
}
} else if (!cdvVersionCode) {
def minSdkVersion = cdvMinSdkVersion ?: privateHelpers.extractIntFromManifest("minSdkVersion")
// Vary versionCode by the two most common API levels:
// 14 is ICS, which is the lowest API level for many apps.
// 20 is Lollipop, which is the lowest API level for the updatable system webview.
if (minSdkVersion >= 20) {
defaultConfig.versionCode += 9
} else if (minSdkVersion >= 14) {
defaultConfig.versionCode += 8
}
}
I am not sure why cordova thinks it is correct to change my version code, and additionally, I am not sure if this behaviour is correct ... shouldnt it add the number and not append it?
Can I just remove the corresponding section in the build.gradle or is there some hidden sense behind this behaviour?
O.K. seems like this is a major unresolved bug in Cordova Version 5 and up. Here is the link to the ticket.
I had no problem when removing the offending code from my build.gradle
The platforms\android\build.gradle script will add 4, 2, 8 or 9 to the version file dependent on targeted architecure - arm / x86 or the targeted api version of android .
I had a situation where my project had a "8" appended to the version number, and this was uploaded to the Play store. Further builds seemed to have dropped the 8, which meant I was unable to upload further updates - a cordova prepare command recreates the AndroidManifest.xml file, overriding manual changes to this.
The version issue can be addressed by creating a platforms\android\gradle.properties file with the contents cdvVersionCode=13008
Alternatively, in my case, I inserted a android-versionCode attribute into the config.xml:
<widget xmlns:cdv="http://cordova.apache.org/ns/1.0" xmlns:vs="http://schemas.microsoft.com/appx/2014/htmlapps" id="uk.co.my.app" android-versionCode="103008" version="1.3.0" xmlns="http://www.w3.org/ns/widgets" defaultlocale="en-GB">
The desired android version, in my case 103008 is then correctly written to the AndroidManifest.xml file used for the build.
Downside is having to manually update the android version, upside, can upload the apk!
For those who want to keep the end '8', I have write a after_prepare hook to make it easy, no need to maintain the android-versionCode in config.xml manually mentioned by #ChilledFlame.
Note: if you do not keep the end '8', when you submit your app to the appstore, your android version code is smaller then previous which built by Cordova 5, you may encounter "version code downgrade issue".
create a file under folder hooks/after_prepare/, add the following code.
#!/usr/bin/env node
var path = require('path');
var fs = require('fs');
var xml2js = require('xml2js');
function xmlFileToJs(filename, cb) {
var filepath = path.normalize(path.join(__dirname, filename));
fs.readFile(filepath, 'utf8', function (err, xmlStr) {
if (err) throw (err);
xml2js.parseString(xmlStr, {}, cb);
});
}
function jsToXmlFile(filename, obj, cb) {
var filepath = path.normalize(path.join(__dirname, filename));
var builder = new xml2js.Builder();
var xml = builder.buildObject(obj);
fs.writeFile(filepath, xml, cb);
}
var androidManifestRPath = '../../platforms/android/AndroidManifest.xml';
xmlFileToJs(androidManifestRPath, function(error, data) {
var config = data;
config.manifest.$['android:versionCode'] += '8';
jsToXmlFile(androidManifestRPath, config)
});
or download from this link:
append_8_to_version_code.js
After removing versionCode modifications from ./platforms/android/build.gradle, an "8" was still being appended to the versionCode in my APK.
A "cordova clean" was required before the newly generated APK would have the correct versionCode in it.
I'm currently developing a custom library for Android.
My idea is to have a version for the app (I'm currently setting it in de build.gradle file and it works fine), and a different version for the library.
Is there a best practice in order to achieve this without having the two build.gradle files merged together?
I found a couple of similar questions on SO but they were 4 years old and not very helpful.
The solution for this is not Git as you probably already figured out. OP wants to externally version a library, potentially as a means to provide an API to a third-party without providing the source code.
This is not trivial with Gradle but it is doable.
You can do this at different levels, I'll explain the easiest and most straight-forward.
Setting the version number
First you need to add a version variable to your gradle.properties file. You can set this variable with a simple one-liner:
version=0.1.0-SNAPSHOT
Building a version string
In your project create a file called versioning.gradle and paste the following code inside (I found this online a long time ago, I don't have the source anymore):
ext {
/**
* Builds an Android version code from the version of the project.
* This is designed to handle the -SNAPSHOT and -RC format.
*
* I.e. during development the version ends with -SNAPSHOT. As the code stabilizes and release nears
* one or many Release Candidates are tagged. These all end with "-RC1", "-RC2" etc.
* And the final release is without any suffix.
* #return
*/
buildVersionCode = {
//The rules is as follows:
//-SNAPSHOT counts as 0
//-RC* counts as the RC number, i.e. 1 to 98
//final release counts as 99.
//Thus you can only have 98 Release Candidates, which ought to be enough for everyone
def candidate = "99"
def (major, minor, patch) = version.toLowerCase().replaceAll('-', '').tokenize('.')
if (patch.endsWith("snapshot")) {
candidate = "0"
patch = patch.replaceAll("[^0-9]","")
} else {
def rc
(patch, rc) = patch.tokenize("rc")
if (rc) {
candidate = rc
}
}
(major, minor, patch, candidate) = [major, minor, patch, candidate].collect{it.toInteger()}
(major * 1000000) + (minor * 10000) + (patch * 100) + candidate;
}
}
Once you've done this, be sure to include the versioning.gradle file from your main build.gradle file by adding apply from: '../versioning.gradle' near where the Android plugin is loaded.
Then, in your defaultConfig block, you want to change the default version variables to the following values:
versionCode buildVersionCode()
versionName version
Version number in the filename of the library
If you're truly building an Android library, then the expected output is an .aar file.
Therefore, add the following gradle code to your build.gradle file:
libraryVariants.all {
variant -> variant.outputs.each {
output -> output.outputFile = new File(
output.outputFile.parent,
output.outputFile.name.replace(".aar", "-${defaultConfig.versionName}.aar")
)
}
}
And that's it! Your output file will have a name with the version number you specify in the gradle.proprties file.
Caveats
This will version your library and/or API in a very static manner. Meaning that there's no way for a developer to dynamically get the version number through a method call.
Be sure to also have a method available that supplies client developers with the version number AND be sure to keep the two in sync. Only then you have a properly versioned library.
Why would you want to do this?
If the problem is that you need to be able to take different actions in the programs using the library depending on the version, then simply create a public static final constant somewhere in the library.
If the reason is cosmetic (e.g., for presentation), then simply put it in your Readme, Changelog, or wherever you need it. Messing up the build files for this purpose is a bad idea.
Based on your explanation:
My recommendation is to put it in the library's AndroidManifest.xml in that case (android:versionCode and android:versionName). This is what Google does with many of their own libraries, and it's harmless wrt the build.