Added: Add support for `TERMUX_APP_PACKAGE_MANAGER` and `TERMUX_APP_PACKAGE_VARIANT` to build APKs with different package manager configurations

The `TermuxBootstrap` class has been added that defines the `PackageManager` and `PackageVariant` classes for the supported package manager configurations for the app. The variant is defined by the `project.ext.packageVariant` value in the `app/build.gradle` and its value is used by the `build.gradle` to pack its respective bootstrap zips in the app APK at build time and the value is used to set `TermuxBootstrap.TERMUX_APP_PACKAGE_MANAGER` and `TermuxBootstrap.TERMUX_APP_PACKAGE_VARIANT` static values that are used at runtime by the app to run variant specific code. The manager is automatically extracted from the variant as the substring before first dash `-`.

The default variant is `apt-android-7` and it can either be replaced in `app/build.gradle` manually or the `TERMUX_PACKAGE_VARIANT` env variable can be exported in which the build command is run.

The `TERMUX_APP_PACKAGE_MANAGER` and `TERMUX_APP_PACKAGE_VARIANT` environmental variables will be exported by the app and they will also be added in Termux app info in about page and reports, allowing users and devs to know which variant is currently installed.

Bootstrap of a different variant must not be manually installed by the user after app installation by replacing `$PREFIX` since app code is dependant on the variant used to build the APK.

Currently, `apt-android-7` and `apt-android-5` variants will be built for by the workflows but they will fail for `apt-android-5` since `build.gradle` support is currently not enabled and will be enabled by a pull request that adds support for Android 5. The workflow needs to try to build the `apt-android-5` variant so that pull request builds are generated.
This commit is contained in:
agnostic-apollo 2022-04-28 09:33:20 +05:00
parent 4b3b1a5b6a
commit b950efec27
8 changed files with 250 additions and 25 deletions

View File

@ -8,8 +8,13 @@ on:
jobs:
attach-apks:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
package_variant: [ apt-android-7, apt-android-5 ]
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- name: Clone repository
uses: actions/checkout@v2
@ -18,6 +23,8 @@ jobs:
- name: Build and attach APKs to release
shell: bash {0}
env:
PACKAGE_VARIANT: ${{ matrix.package_variant }}
run: |
exit_on_error() {
echo "$1"
@ -34,13 +41,14 @@ jobs:
fi
APK_DIR_PATH="./app/build/outputs/apk/debug"
APK_VERSION_TAG="$RELEASE_VERSION_NAME+github-debug"
APK_VERSION_TAG="$RELEASE_VERSION_NAME+${{ env.PACKAGE_VARIANT }}-github-debug"
APK_BASENAME_PREFIX="termux-app_$APK_VERSION_TAG"
echo "Building APKs for '$RELEASE_VERSION_NAME' release"
echo "Building APKs for 'APK_VERSION_TAG' release"
export TERMUX_APK_VERSION_TAG="$APK_VERSION_TAG" # Used by app/build.gradle
export TERMUX_PACKAGE_VARIANT="${{ env.PACKAGE_VARIANT }}" # Used by app/build.gradle
if ! ./gradlew assembleDebug; then
exit_on_error "Build failed for '$RELEASE_VERSION_NAME' release."
exit_on_error "Build failed for '$APK_VERSION_TAG' release."
fi
echo "Validating APKs"
@ -58,8 +66,8 @@ jobs:
"${APK_BASENAME_PREFIX}_armeabi-v7a.apk" \
"${APK_BASENAME_PREFIX}_x86_64.apk" \
"${APK_BASENAME_PREFIX}_x86.apk" \
> sha256sums); then
exit_on_error "Generate sha25sums failed for '$RELEASE_VERSION_NAME' release."
> "${APK_BASENAME_PREFIX}_sha256sums"); then
exit_on_error "Generate sha25sums failed for '$APK_VERSION_TAG' release."
fi
echo "Attaching APKs to github release"
@ -70,7 +78,7 @@ jobs:
-a "$APK_DIR_PATH/${APK_BASENAME_PREFIX}_armeabi-v7a.apk" \
-a "$APK_DIR_PATH/${APK_BASENAME_PREFIX}_x86_64.apk" \
-a "$APK_DIR_PATH/${APK_BASENAME_PREFIX}_x86.apk" \
-a "$APK_DIR_PATH/sha256sums" \
-a "$APK_DIR_PATH/${APK_BASENAME_PREFIX}_sha256sums" \
"$RELEASE_VERSION_NAME"; then
exit_on_error "Attach APKs to release failed for '$RELEASE_VERSION_NAME' release."
exit_on_error "Attach APKs to release failed for '$APK_VERSION_TAG' release."
fi

View File

@ -11,12 +11,19 @@ on:
jobs:
build:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
package_variant: [ apt-android-7, apt-android-5 ]
steps:
- name: Clone repository
uses: actions/checkout@v2
- name: Build APKs
shell: bash {0}
env:
PACKAGE_VARIANT: ${{ matrix.package_variant }}
run: |
exit_on_error() { echo "$1"; exit 1; }
@ -35,7 +42,7 @@ jobs:
fi
APK_DIR_PATH="./app/build/outputs/apk/debug"
APK_VERSION_TAG="$RELEASE_VERSION_NAME-github-debug" # Note the "-", GITHUB_SHA will already have "+" before it
APK_VERSION_TAG="$RELEASE_VERSION_NAME-${{ env.PACKAGE_VARIANT }}-github-debug" # Note the "-", GITHUB_SHA will already have "+" before it
APK_BASENAME_PREFIX="termux-app_$APK_VERSION_TAG"
# Used by attachment steps later
@ -43,11 +50,12 @@ jobs:
echo "APK_VERSION_TAG=$APK_VERSION_TAG" >> $GITHUB_ENV
echo "APK_BASENAME_PREFIX=$APK_BASENAME_PREFIX" >> $GITHUB_ENV
echo "Building APKs for '$RELEASE_VERSION_NAME' build"
echo "Building APKs for 'APK_VERSION_TAG' build"
export TERMUX_APP_VERSION_NAME="${RELEASE_VERSION_NAME/v/}" # Used by app/build.gradle
export TERMUX_APK_VERSION_TAG="$APK_VERSION_TAG" # Used by app/build.gradle
export TERMUX_PACKAGE_VARIANT="${{ env.PACKAGE_VARIANT }}" # Used by app/build.gradle
if ! ./gradlew assembleDebug; then
exit_on_error "Build failed for '$RELEASE_VERSION_NAME' build."
exit_on_error "Build failed for '$APK_VERSION_TAG' build."
fi
echo "Validating APKs"
@ -65,8 +73,8 @@ jobs:
"${APK_BASENAME_PREFIX}_armeabi-v7a.apk" \
"${APK_BASENAME_PREFIX}_x86_64.apk" \
"${APK_BASENAME_PREFIX}_x86.apk" \
> sha256sums); then
exit_on_error "Generate sha25sums failed for '$RELEASE_VERSION_NAME' release."
> "${APK_BASENAME_PREFIX}_sha256sums"); then
exit_on_error "Generate sha25sums failed for '$APK_VERSION_TAG' release."
fi
- name: Attach universal APK file
@ -112,7 +120,7 @@ jobs:
- name: Attach sha256sums file
uses: actions/upload-artifact@v2
with:
name: sha256sums
name: ${{ env.APK_BASENAME_PREFIX }}_sha256sums
path: |
${{ env.APK_DIR_PATH }}/sha256sums
${{ env.APK_DIR_PATH }}/${{ env.APK_BASENAME_PREFIX }}_sha256sums
${{ env.APK_DIR_PATH }}/output-metadata.json

View File

@ -2,6 +2,16 @@ plugins {
id "com.android.application"
}
ext {
// The packageVariant defines the bootstrap variant that will be included in the app APK.
// This must be supported by com.termux.shared.termux.TermuxBootstrap.PackageVariant or app will
// crash at startup.
// Bootstrap of a different variant must not be manually installed by the user after app installation
// by replacing $PREFIX since app code is dependant on the variant used to build the APK.
// Currently supported values are: [ "apt-android-7" ]
packageVariant = System.getenv("TERMUX_PACKAGE_VARIANT") ?: "apt-android-7" // Default: "apt-android-7"
}
android {
compileSdkVersion project.properties.compileSdkVersion.toInteger()
ndkVersion = System.getenv("JITPACK_NDK_VERSION") ?: project.properties.ndkVersion
@ -37,6 +47,8 @@ android {
if (appVersionName) versionName = appVersionName
validateVersionName(versionName)
buildConfigField "String", "TERMUX_PACKAGE_VARIANT", "\"" + project.ext.packageVariant + "\"" // Used by TermuxApplication class
manifestPlaceholders.TERMUX_PACKAGE_NAME = "com.termux"
manifestPlaceholders.TERMUX_APP_NAME = "Termux"
manifestPlaceholders.TERMUX_API_APP_NAME = "Termux:API"
@ -115,10 +127,10 @@ android {
variant.outputs.all { output ->
if (variant.buildType.name == "debug") {
def abi = output.getFilter(com.android.build.OutputFile.ABI)
outputFileName = new File("termux-app_" + (apkVersionTag ? apkVersionTag : "debug") + "_" + (abi ? abi : "universal") + ".apk")
outputFileName = new File("termux-app_" + (apkVersionTag ? apkVersionTag : project.ext.packageVariant + "-" + "debug") + "_" + (abi ? abi : "universal") + ".apk")
} else if (variant.buildType.name == "release") {
def abi = output.getFilter(com.android.build.OutputFile.ABI)
outputFileName = new File("termux-app_" + (apkVersionTag ? apkVersionTag : "release") + "_" + (abi ? abi : "universal") + ".apk")
outputFileName = new File("termux-app_" + (apkVersionTag ? apkVersionTag : project.ext.packageVariant + "-" + "release") + "_" + (abi ? abi : "universal") + ".apk")
}
}
}
@ -161,7 +173,7 @@ def downloadBootstrap(String arch, String expectedChecksum, String version) {
if (checksum == expectedChecksum) {
return
} else {
logger.quiet("Deleting old local file with wrong hash: " + localUrl)
logger.quiet("Deleting old local file with wrong hash: " + localUrl + ": expected: " + expectedChecksum + ", actual: " + checksum)
file.delete()
}
}
@ -196,11 +208,16 @@ clean {
task downloadBootstraps() {
doLast {
def version = "2022.04.22-r1"
downloadBootstrap("aarch64", "ec8a6043644594fc24681cffaf9c7b32f5bc68df7491c5df9a060e40e1934c70", version)
downloadBootstrap("arm", "f8ec9505081b81da0ee66413762c52e6cb4a6ebd7be1a2a5ddee8953e0795dc9", version)
downloadBootstrap("i686", "0491f12ed84a5ef3c28bd742311fed9f176e32100a2c6bbdb017df8f48044484", version)
downloadBootstrap("x86_64", "94073a0e136bf5a9c05c1997a55dc261248f4ccb8bffaa9a950a132529cd1529", version)
def packageVariant = project.ext.packageVariant
if (packageVariant == "apt-android-7") {
def version = "2022.04.22-r1" + "+" + packageVariant
downloadBootstrap("aarch64", "ec8a6043644594fc24681cffaf9c7b32f5bc68df7491c5df9a060e40e1934c70", version)
downloadBootstrap("arm", "f8ec9505081b81da0ee66413762c52e6cb4a6ebd7be1a2a5ddee8953e0795dc9", version)
downloadBootstrap("i686", "0491f12ed84a5ef3c28bd742311fed9f176e32100a2c6bbdb017df8f48044484", version)
downloadBootstrap("x86_64", "94073a0e136bf5a9c05c1997a55dc261248f4ccb8bffaa9a950a132529cd1529", version)
} else {
throw new GradleException("Unsupported TERMUX_PACKAGE_VARIANT \"" + packageVariant + "\"")
}
}
}

View File

@ -3,8 +3,10 @@ package com.termux.app;
import android.app.Application;
import android.content.Context;
import com.termux.BuildConfig;
import com.termux.shared.errors.Error;
import com.termux.shared.logger.Logger;
import com.termux.shared.termux.TermuxBootstrap;
import com.termux.shared.termux.TermuxConstants;
import com.termux.shared.termux.crash.TermuxCrashUtils;
import com.termux.shared.termux.file.TermuxFileUtils;
@ -30,6 +32,9 @@ public class TermuxApplication extends Application {
Logger.logDebug("Starting Application");
// Set TermuxBootstrap.TERMUX_APP_PACKAGE_MANAGER and TermuxBootstrap.TERMUX_APP_PACKAGE_VARIANT
TermuxBootstrap.setTermuxPackageManagerAndVariant(BuildConfig.TERMUX_PACKAGE_VARIANT);
// Init app wide SharedProperties loaded from termux.properties
TermuxAppSharedProperties properties = TermuxAppSharedProperties.init(context);

View File

@ -23,6 +23,7 @@ import com.termux.shared.file.FileUtils;
import com.termux.shared.interact.MessageDialogUtils;
import com.termux.shared.interact.ShareUtils;
import com.termux.shared.shell.ShellUtils;
import com.termux.shared.termux.TermuxBootstrap;
import com.termux.shared.termux.terminal.TermuxTerminalViewClientBase;
import com.termux.shared.termux.extrakeys.SpecialButton;
import com.termux.shared.android.AndroidUtils;
@ -756,9 +757,11 @@ public class TermuxTerminalViewClient extends TermuxTerminalViewClientBase {
reportString.append("\n\n").append(AndroidUtils.getDeviceInfoMarkdownString(mActivity));
String termuxAptInfo = TermuxUtils.geAPTInfoMarkdownString(mActivity);
if (termuxAptInfo != null)
reportString.append("\n\n").append(termuxAptInfo);
if (TermuxBootstrap.isAppPackageManagerAPT()) {
String termuxAptInfo = TermuxUtils.geAPTInfoMarkdownString(mActivity);
if (termuxAptInfo != null)
reportString.append("\n\n").append(termuxAptInfo);
}
if (addTermuxDebugInfo) {
String termuxDebugInfo = TermuxUtils.getTermuxDebugMarkdownString(mActivity);

View File

@ -0,0 +1,174 @@
package com.termux.shared.termux;
import androidx.annotation.Nullable;
import com.termux.shared.logger.Logger;
public class TermuxBootstrap {
private static final String LOG_TAG = "TermuxBootstrap";
/** The {@link PackageManager} for the bootstrap in the app APK added in app/build.gradle. */
public static PackageManager TERMUX_APP_PACKAGE_MANAGER;
/** The {@link PackageVariant} for the bootstrap in the app APK added in app/build.gradle. */
public static PackageVariant TERMUX_APP_PACKAGE_VARIANT;
/** Set name as app wide night mode value. */
public static void setTermuxPackageManagerAndVariant(@Nullable String packageVariantName) {
TERMUX_APP_PACKAGE_VARIANT = PackageVariant.variantOf(packageVariantName);
if (TERMUX_APP_PACKAGE_VARIANT == null) {
throw new RuntimeException("Unsupported TERMUX_APP_PACKAGE_VARIANT \"" + packageVariantName + "\"");
}
Logger.logVerbose(LOG_TAG, "Set TERMUX_APP_PACKAGE_VARIANT to \"" + TERMUX_APP_PACKAGE_VARIANT + "\"");
// Set packageManagerName to substring before first dash "-" in packageVariantName
int index = packageVariantName.indexOf('-');
String packageManagerName = (index == -1) ? null : packageVariantName.substring(0, index);
TERMUX_APP_PACKAGE_MANAGER = PackageManager.managerOf(packageManagerName);
if (TERMUX_APP_PACKAGE_MANAGER == null) {
throw new RuntimeException("Unsupported TERMUX_APP_PACKAGE_MANAGER \"" + packageManagerName + "\" with variant \"" + packageVariantName + "\"");
}
Logger.logVerbose(LOG_TAG, "Set TERMUX_APP_PACKAGE_MANAGER to \"" + TERMUX_APP_PACKAGE_MANAGER + "\"");
}
/** Is {@link PackageManager#APT} set as {@link #TERMUX_APP_PACKAGE_MANAGER}. */
public static boolean isAppPackageManagerAPT() {
return PackageManager.APT.equals(TERMUX_APP_PACKAGE_MANAGER);
}
///** Is {@link PackageManager#TAPM} set as {@link #TERMUX_APP_PACKAGE_MANAGER}. */
//public static boolean isAppPackageManagerTAPM() {
// return PackageManager.TAPM.equals(TERMUX_APP_PACKAGE_MANAGER);
//}
///** Is {@link PackageManager#PACMAN} set as {@link #TERMUX_APP_PACKAGE_MANAGER}. */
//public static boolean isAppPackageManagerPACMAN() {
// return PackageManager.PACMAN.equals(TERMUX_APP_PACKAGE_MANAGER);
//}
/** Is {@link PackageVariant#APT_ANDROID_7} set as {@link #TERMUX_APP_PACKAGE_VARIANT}. */
public static boolean isAppPackageVariantAPTAndroid7() {
return PackageVariant.APT_ANDROID_7.equals(TERMUX_APP_PACKAGE_VARIANT);
}
///** Is {@link PackageVariant#APT_ANDROID_5} set as {@link #TERMUX_APP_PACKAGE_VARIANT}. */
//public static boolean isAppPackageVariantAPTAndroid5() {
// return PackageVariant.APT_ANDROID_5.equals(TERMUX_APP_PACKAGE_VARIANT);
//}
///** Is {@link PackageVariant#TAPM_ANDROID_7} set as {@link #TERMUX_APP_PACKAGE_VARIANT}. */
//public static boolean isAppPackageVariantTAPMAndroid7() {
// return PackageVariant.TAPM_ANDROID_7.equals(TERMUX_APP_PACKAGE_VARIANT);
//}
///** Is {@link PackageVariant#PACMAN_ANDROID_7} set as {@link #TERMUX_APP_PACKAGE_VARIANT}. */
//public static boolean isAppPackageVariantTPACMANAndroid7() {
// return PackageVariant.PACMAN_ANDROID_7.equals(TERMUX_APP_PACKAGE_VARIANT);
//}
/** Termux package manager. */
public enum PackageManager {
/**
* Advanced Package Tool (APT) for managing debian deb package files.
* https://wiki.debian.org/Apt
* https://wiki.debian.org/deb
*/
APT("apt");
///**
// * Termux Android Package Manager (TAPM) for managing termux apk package files.
// * https://en.wikipedia.org/wiki/Apk_(file_format)
// */
//TAPM("tapm");
///**
// * Package Manager (PACMAN) for managing arch linux pkg.tar package files.
// * https://wiki.archlinux.org/title/pacman
// * https://en.wikipedia.org/wiki/Arch_Linux#Pacman
// */
//PACMAN("pacman");
private final String name;
PackageManager(final String name) {
this.name = name;
}
public String getName() {
return name;
}
public boolean equalsManager(String manager) {
return manager != null && manager.equals(this.name);
}
/** Get {@link PackageManager} for {@code name} if found, otherwise {@code null}. */
@Nullable
public static PackageManager managerOf(String name) {
if (name == null || name.isEmpty()) return null;
for (PackageManager v : PackageManager.values()) {
if (v.name.equals(name)) {
return v;
}
}
return null;
}
}
/** Termux package variant. The substring before first dash "-" must match one of the {@link PackageManager}. */
public enum PackageVariant {
/** {@link PackageManager#APT} variant for Android 7+. */
APT_ANDROID_7("apt-android-7");
///** {@link PackageManager#APT} variant for Android 5+. */
//APT_ANDROID_5("apt-android-5");
///** {@link PackageManager#TAPM} variant for Android 7+. */
//TAPM_ANDROID_7("tapm-android-7");
///** {@link PackageManager#PACMAN} variant for Android 7+. */
//PACMAN_ANDROID_7("pacman-android-7");
private final String name;
PackageVariant(final String name) {
this.name = name;
}
public String getName() {
return name;
}
public boolean equalsVariant(String variant) {
return variant != null && variant.equals(this.name);
}
/** Get {@link PackageVariant} for {@code name} if found, otherwise {@code null}. */
@Nullable
public static PackageVariant variantOf(String name) {
if (name == null || name.isEmpty()) return null;
for (PackageVariant v : PackageVariant.values()) {
if (v.name.equals(name)) {
return v;
}
}
return null;
}
}
}

View File

@ -397,6 +397,11 @@ public class TermuxUtils {
markdownString.append((AndroidUtils.getAppInfoMarkdownString(context)));
if (context.getPackageName().equals(TermuxConstants.TERMUX_PACKAGE_NAME)) {
AndroidUtils.appendPropertyToMarkdown(markdownString, "TERMUX_APP_PACKAGE_MANAGER", TermuxBootstrap.TERMUX_APP_PACKAGE_MANAGER);
AndroidUtils.appendPropertyToMarkdown(markdownString, "TERMUX_APP_PACKAGE_VARIANT", TermuxBootstrap.TERMUX_APP_PACKAGE_VARIANT);
}
Error error;
error = TermuxFileUtils.isTermuxFilesDirectoryAccessible(context, true, true);
if (error != null) {

View File

@ -6,6 +6,7 @@ import androidx.annotation.NonNull;
import com.termux.shared.errors.Error;
import com.termux.shared.file.filesystem.FileTypes;
import com.termux.shared.termux.TermuxBootstrap;
import com.termux.shared.termux.TermuxConstants;
import com.termux.shared.file.FileUtils;
import com.termux.shared.logger.Logger;
@ -61,6 +62,10 @@ public class TermuxShellUtils {
environment.add("TERMUX_APP_PID=" + TERMUX_APP_PID);
if (TERMUX_APK_RELEASE != null)
environment.add("TERMUX_APK_RELEASE=" + TERMUX_APK_RELEASE);
if (TermuxBootstrap.TERMUX_APP_PACKAGE_MANAGER != null)
environment.add("TERMUX_APP_PACKAGE_MANAGER=" + TermuxBootstrap.TERMUX_APP_PACKAGE_MANAGER.getName());
if (TermuxBootstrap.TERMUX_APP_PACKAGE_VARIANT != null)
environment.add("TERMUX_APP_PACKAGE_VARIANT=" + TermuxBootstrap.TERMUX_APP_PACKAGE_VARIANT.getName());
if (TERMUX_APP_AM_SOCKET_SERVER_ENABLED != null)
environment.add("TERMUX_APP_AM_SOCKET_SERVER_ENABLED=" + TERMUX_APP_AM_SOCKET_SERVER_ENABLED);