mirror of
https://github.com/fankes/termux-app.git
synced 2025-09-04 01:35:39 +08:00
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.
229 lines
9.2 KiB
Groovy
229 lines
9.2 KiB
Groovy
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
|
|
def appVersionName = System.getenv("TERMUX_APP_VERSION_NAME") ?: ""
|
|
def apkVersionTag = System.getenv("TERMUX_APK_VERSION_TAG") ?: ""
|
|
def splitAPKsForDebugBuilds = System.getenv("TERMUX_SPLIT_APKS_FOR_DEBUG_BUILDS") ?: "1"
|
|
def splitAPKsForReleaseBuilds = System.getenv("TERMUX_SPLIT_APKS_FOR_RELEASE_BUILDS") ?: "0" // F-Droid does not support split APKs #1904
|
|
|
|
dependencies {
|
|
implementation "androidx.annotation:annotation:1.3.0"
|
|
implementation "androidx.core:core:1.6.0"
|
|
implementation "androidx.drawerlayout:drawerlayout:1.1.1"
|
|
implementation "androidx.preference:preference:1.1.1"
|
|
implementation "androidx.viewpager:viewpager:1.0.0"
|
|
implementation "com.google.android.material:material:1.4.0"
|
|
implementation "com.google.guava:guava:24.1-jre"
|
|
implementation "io.noties.markwon:core:$markwonVersion"
|
|
implementation "io.noties.markwon:ext-strikethrough:$markwonVersion"
|
|
implementation "io.noties.markwon:linkify:$markwonVersion"
|
|
implementation "io.noties.markwon:recycler:$markwonVersion"
|
|
|
|
implementation project(":terminal-view")
|
|
implementation project(":termux-shared")
|
|
}
|
|
|
|
defaultConfig {
|
|
applicationId "com.termux"
|
|
minSdkVersion project.properties.minSdkVersion.toInteger()
|
|
targetSdkVersion project.properties.targetSdkVersion.toInteger()
|
|
versionCode 118
|
|
versionName "0.118.0"
|
|
|
|
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"
|
|
manifestPlaceholders.TERMUX_BOOT_APP_NAME = "Termux:Boot"
|
|
manifestPlaceholders.TERMUX_FLOAT_APP_NAME = "Termux:Float"
|
|
manifestPlaceholders.TERMUX_STYLING_APP_NAME = "Termux:Styling"
|
|
manifestPlaceholders.TERMUX_TASKER_APP_NAME = "Termux:Tasker"
|
|
manifestPlaceholders.TERMUX_WIDGET_APP_NAME = "Termux:Widget"
|
|
|
|
externalNativeBuild {
|
|
ndkBuild {
|
|
cFlags "-std=c11", "-Wall", "-Wextra", "-Werror", "-Os", "-fno-stack-protector", "-Wl,--gc-sections"
|
|
}
|
|
}
|
|
|
|
splits {
|
|
abi {
|
|
enable ((gradle.startParameter.taskNames.any { it.contains("Debug") } && splitAPKsForDebugBuilds == "1") ||
|
|
(gradle.startParameter.taskNames.any { it.contains("Release") } && splitAPKsForReleaseBuilds == "1"))
|
|
reset ()
|
|
include 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a'
|
|
universalApk true
|
|
}
|
|
}
|
|
}
|
|
|
|
signingConfigs {
|
|
debug {
|
|
storeFile file('dev_keystore.jks')
|
|
keyAlias 'alias'
|
|
storePassword 'xrj45yWGLbsO7W0v'
|
|
keyPassword 'xrj45yWGLbsO7W0v'
|
|
}
|
|
}
|
|
|
|
buildTypes {
|
|
release {
|
|
minifyEnabled true
|
|
shrinkResources false // Reproducible builds
|
|
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
|
}
|
|
|
|
debug {
|
|
signingConfig signingConfigs.debug
|
|
}
|
|
}
|
|
|
|
compileOptions {
|
|
sourceCompatibility JavaVersion.VERSION_1_8
|
|
targetCompatibility JavaVersion.VERSION_1_8
|
|
}
|
|
|
|
externalNativeBuild {
|
|
ndkBuild {
|
|
path "src/main/cpp/Android.mk"
|
|
}
|
|
}
|
|
|
|
lintOptions {
|
|
disable 'ProtectedPermissions'
|
|
}
|
|
|
|
testOptions {
|
|
unitTests {
|
|
includeAndroidResources = true
|
|
}
|
|
}
|
|
|
|
packagingOptions {
|
|
jniLibs {
|
|
useLegacyPackaging true
|
|
}
|
|
}
|
|
|
|
applicationVariants.all { variant ->
|
|
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 : 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 : project.ext.packageVariant + "-" + "release") + "_" + (abi ? abi : "universal") + ".apk")
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
dependencies {
|
|
testImplementation "junit:junit:4.13.2"
|
|
testImplementation "org.robolectric:robolectric:4.4"
|
|
}
|
|
|
|
task versionName {
|
|
doLast {
|
|
print android.defaultConfig.versionName
|
|
}
|
|
}
|
|
|
|
def validateVersionName(String versionName) {
|
|
// https://semver.org/spec/v2.0.0.html#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string
|
|
// ^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$
|
|
if (!java.util.regex.Pattern.matches("^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?\$", versionName))
|
|
throw new GradleException("The versionName '" + versionName + "' is not a valid version as per semantic version '2.0.0' spec in the format 'major.minor.patch(-prerelease)(+buildmetadata)'. https://semver.org/spec/v2.0.0.html.")
|
|
}
|
|
|
|
def downloadBootstrap(String arch, String expectedChecksum, String version) {
|
|
def digest = java.security.MessageDigest.getInstance("SHA-256")
|
|
|
|
def localUrl = "src/main/cpp/bootstrap-" + arch + ".zip"
|
|
def file = new File(projectDir, localUrl)
|
|
if (file.exists()) {
|
|
def buffer = new byte[8192]
|
|
def input = new FileInputStream(file)
|
|
while (true) {
|
|
def readBytes = input.read(buffer)
|
|
if (readBytes < 0) break
|
|
digest.update(buffer, 0, readBytes)
|
|
}
|
|
def checksum = new BigInteger(1, digest.digest()).toString(16)
|
|
while (checksum.length() < 64) { checksum = "0" + checksum }
|
|
if (checksum == expectedChecksum) {
|
|
return
|
|
} else {
|
|
logger.quiet("Deleting old local file with wrong hash: " + localUrl + ": expected: " + expectedChecksum + ", actual: " + checksum)
|
|
file.delete()
|
|
}
|
|
}
|
|
|
|
def remoteUrl = "https://github.com/termux/termux-packages/releases/download/bootstrap-" + version + "/bootstrap-" + arch + ".zip"
|
|
logger.quiet("Downloading " + remoteUrl + " ...")
|
|
|
|
file.parentFile.mkdirs()
|
|
def out = new BufferedOutputStream(new FileOutputStream(file))
|
|
|
|
def connection = new URL(remoteUrl).openConnection()
|
|
connection.setInstanceFollowRedirects(true)
|
|
def digestStream = new java.security.DigestInputStream(connection.inputStream, digest)
|
|
out << digestStream
|
|
out.close()
|
|
|
|
def checksum = new BigInteger(1, digest.digest()).toString(16)
|
|
while (checksum.length() < 64) { checksum = "0" + checksum }
|
|
if (checksum != expectedChecksum) {
|
|
file.delete()
|
|
throw new GradleException("Wrong checksum for " + remoteUrl + ": expected: " + expectedChecksum + ", actual: " + checksum)
|
|
}
|
|
}
|
|
|
|
clean {
|
|
doLast {
|
|
def tree = fileTree(new File(projectDir, 'src/main/cpp'))
|
|
tree.include 'bootstrap-*.zip'
|
|
tree.each { it.delete() }
|
|
}
|
|
}
|
|
|
|
task downloadBootstraps() {
|
|
doLast {
|
|
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 + "\"")
|
|
}
|
|
}
|
|
}
|
|
|
|
afterEvaluate {
|
|
android.applicationVariants.all { variant ->
|
|
variant.javaCompileProvider.get().dependsOn(downloadBootstraps)
|
|
}
|
|
}
|