这是indexloc提供的服务,不要输入任何密码
Skip to content

[Bug][Proposal]: New Termux app versionCode spec to solve app store issues  #4012

@agnostic-apollo

Description

@agnostic-apollo

Android and Google PlayStore/F-Droid stores use the versionCode positive integer value of the currently installed app to decide whether the new APK to be installed or one hosted by the store is an updated version or not. If the versionCode of the new APK is higher, only then it is considered an update and allowed to be normally installed over the currently installed app. The versionName string value of apps is not used in this decision.

The max value for versionCode that Google PlayStore allows is 2 100 000 000 (2100000000), Android also internally stores it as an int and java INT_MAX value is only slightly higher 2 147 483 647.

Since termux-apps use semantic versioning 2.0 for versionName in the format x.y.x since 0.118.0 release, there needs to be some way for mapping the versionName to a versionCode while keeping it different for different install sources so that their app stores don't show updates of other sources. This is a problem for Google PlayStore because it does not check signatures of the currently installed app APK against the latest app APK hosted by the store that is to be updated, and it only compares the versionCode. So if the device has an APK installed from a different install source with a different signature, but its versionCode is lower than the latest APK hosted in the store, then PlayStore will attempt to download and install it and then fail with a Can't install Termux generic UI error, with the actual error Finsky Submitter: commit error message INSTALL_FAILED_UPDATE_INCOMPATIBLE: Existing package com.termux signatures do not match newer version; ignoring! logged to logcat that is returned by the Android package installer. User can manually disable auto update for the app from its app page options button, but any updates will still show in the PlayStore app updates list. Basically, to solve this, the versionCode of app APKs hosted by the "broken" stores must be lower than other install sources.

Note that F-Droid store does not show updates for apps in the app updates list if they are signed with a different signing key. The APK signing certificate SHA-256 digest is stored in the packages: <package_name>: versions: <version_id>: manifest: signer: sha256: 0 field of the index that F-Droid repository maintains for all hosted app APKs and it does not need to download the actual APK to find it. The signer field is stored in the manifest_signer_sha256 field of the Version table of the /data/data/org.fdroid.fdroid/databases/fdroid_db database that F-Droid app maintains. (1, 2) If the user manually tries to update an app from its app page, it is prevented with the The new version is signed with a different key to the old one. To install the new version, the old one must be uninstalled first. Please do this and try again. (Note that uninstalling will erase any internal data stored by the app) (1, 2) error, without actually trying to update the app and then failing.

An incremental versionCode cannot be used, as that would not allow patch releases. For example, 0.118.1 is released as 1000, then 0.119.0-beta.1 is released as 1001. If 0.118.1 F-Droid build fails or a bug is found after the release, then 0.118.2 patch version update may need to be released, but if its now released as 1002, it will be considered as higher version than 0.119.0-beta.1 (1001), which it won't be. So each major/minor/patch update must have sufficient reserved slots after their next respective increment. Additionally, there must be reserved slots for beta releases before a stable release as well.

The following versioning spec is proposed for mapping the versionName to a versionCode while also keeping a priority for different install sources. As the Google PlayStore allows max value 2 100 000 000 for a versionCode, but since the first and second section cannot go above 2 100, the max value is limited to 1 999 999 999 in the spec. Google PlayStore also suggests a similar versionCode spec.

noop  isp  major minor patch beta/stable
0     0    00    000   00    0
  • noop: 0-1 (currently not used)
  • release_variant: 1-9 (other values could be used for other stores like Samsung store)
    • 1 - PlayStore (lowest priority)
    • 5 - F-Droid or other sources like planned Termux site
    • 7 - GitHub and custom builds (highest priority)
  • major: 0-99
  • minor: 0-999
  • patch: 0-99
  • beta/stable: 0-9

The effectively allows 1000 minor releases for each of the 100 major releases. So a total of 100 x 1000 = 1,00,000 (1 hundred thousand) major/minor releases. If the 100 patch releases are also included, then total releases allowed would be 100 x 1000 x 100 = 10,000,000 (10 million). Even though the semantic versioning spec does not limit the size of major/minor/patch, the 1,00,000 releases should be sufficient for Termux's future. It will allow more than 5 releases to be made per day for the next 50 years (90000). Different install sources will also never conflict and will also have 1,00,000 releases each. The noop could possibly be used for targetSdkVersion variants or some other config, or could be used to expand versions themselves.

Following are examples of versionCode mapping from versionName with the noop and release_variant parts not set (= 0).

0 0 00 118 000 - 0.118.0
0 0 00 118 010 - 0.118.1
0 0 00 118 020 - 0.118.2
0 0 00 118 090 - 0.118.9

0 0 00 119 000 - 0.119.0-beta.1
0 0 00 119 001 - 0.119.0-beta.2
0 0 00 119 002 - 0.119.0

0 0 00 120 000 - 0.120.0-beta.1
0 0 00 120 008 - 0.120.0-beta.9
0 0 00 120 009 - 0.120.0

0 0 00 120 010 - 0.120.1

0 0 00 120 990 - 0.120.99

0 0 00 999 000 - 0.999.0
0 0 00 999 990 - 0.999.99

0 0 01 000 000 - 1.0.0

0 0 99 000 000 - 99.0.0

Following includes the release_variant parts for different versions.

0 1 00 108 010 - 0.108.1       - PlayStore
0 1 00 119 002 - 0.119.0       - PlayStore

0 5 00 118 010 - 0.118.1 -       F-Droid
0 5 00 119 000 - 0.119.0-beta.1 - F-Droid
0 5 00 119 001 - 0.119.0-beta.2 - F-Droid
0 5 00 119 002 - 0.119.0       - F-Droid

0 7 00 118 010 - 0.118.1 -       GitHub
0 7 00 119 000 - 0.119.0-beta.1 - GitHub
0 7 00 119 001 - 0.119.0-beta.2 - GitHub
0 7 00 119 002 - 0.119.0       - GitHub

At build time, the value release_variant x 1 00 000 000 can be added to the versionCode.

  • PlayStore: 1 00 000 000
  • F-Droid: 5 00 000 000
  • GitHub: 7 00 000 000

The release_variant can be set by exporting the $TERMUX_APP_BUILD__VERSION_CODE_RELEASE_VARIANT environment variable at build time, with the default value 7. For F-Droid, a pull request will need to be sent to export the value in the prebuild step of the com.termux package metadata file.

prebuild:
        - export TERMUX_APP_BUILD__VERSION_CODE_RELEASE_VARIANT=5

However, since F-Droid cannot dynamically detect generated versionCode, the versionCode would need to be hardcoded in app/build.gradle build, like 0 5 00 118 010 (versionCode 500118010) for next versionName 0.118.1. It would be much simpler to just use priority 5 for both GitHub and F-Droid, and possibly other non-broken sources/stores, like Termux site. This would also not require sending a pull request and no special logic will be need to be added to handle F-Droid requirement by first subtracting 5 00 000 000 from versionCode, and then adding $TERMUX_APP_BUILD__VERSION_CODE_RELEASE_VARIANT.

Related #4000

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions