Skip to content

Termux Libraries

agnostic-apollo edited this page Mar 17, 2024 · 11 revisions

Termux Libraries

Contents

Importing Libraries

The termux-app repository publishes 3 libraries that are used by Termux plugin apps and can also be used by 3rd party apps as long as they agree to the terms of the relevant Licenses. The versions of termux-app and all libraries are updated together.

Termux plugins and 3rd party apps only need to import termux-shared library for interacting with the termux-app, like for using TermuxConstants and all other utilities provided by it.

However, if the app needs to use the terminal provided by termux-app, then import terminal-view library as well. The terminal-emulator library will be automatically imported since its a dependency of terminal-view. The termux-shared library also depends on terminal-view and terminal-emulator libraries, but an explicit additional import of terminal-view is necessary if using the terminal.

JitPack

The libraries are being published on https://jitpack.io for termux-app version >= 0.116.

For importing the libraries in your project, you need to follow the following instructions.

  1. Add repository url for the libraries to root level of build.gradle file.
allprojects {
    repositories {
    	...
        //mavenLocal()
        maven { url "https://jitpack.io" }
    }
}
  1. Add termux-shared library dependency or other termux libraries to app module level build.gradle file.
dependencies {
    implementation "com.termux:termux-shared:0.118.0"
}
  1. Add empty-to-avoid-conflict-with-guava library dependency to app module level build.gradle file to prevent errors like Duplicate class com.google.common.util.concurrent.ListenableFuture found in modules when building.
dependencies {
    implementation "com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava"
}
  1. Run Sync Gradle with Project Files in Android Studio in File drop down menu or Sync Now popup button that may appear at the top of build.gradle file.

 

Additional Info

  • The Termux libraries are published under both the com.termux and com.github.termux groupId by JitPack since https://termux.com has a DNS TXT record from git.termux.com to https://github.com/termux as per JitPack custom domain requirements. You can confirm by running dig txt git.termux.com and should get something like following in the output. Using com.termux is preferred.

    ;; ANSWER SECTION:
    git.termux.com.     300 IN  TXT "https://github.com/termux"
    

    Both group ids have separate JitPack pages that can be used to trigger and view builds. They both also have separate build logs and artifacts and one may fail while the other may not. Additionally, there is an API page too, e.g like https://jitpack.io/api/resolve/com.termux/termux-app/master-SNAPSHOT.

  • When the first time a library version is imported, like via gradle, then a build is automatically triggered on JitPack servers if build artifacts do not already exist for it, and it does not need to be manually triggered on the site. However, building the library artifacts on JitPack servers will take some time and you may get errors locally like Unable to resolve dependency for ':app@debug/compileClasspath' and local gradle builds will expire eventually. You can check on the JitPack site to see if the required build has succeeded and it will take a few minutes for builds to be downloadable even after build.log shows them to have been succeeded, run Sync Project with Gradle Files again to try to re-download.

  • The versions =< 0.118.0 and older commits use minSdkVersion 24. However, latest commits on master branch after version 0.118.0 use minSdkVersion 21 since support for Android 5/6 was re-added.

  • When termux-app publishes GitHub releases, a build on JitPack servers is automatically triggered via the Trigger Termux Library Builds on JitPack workflow so that imports are instant for that release version when someone tries to import them for the first time. The version build triggered will be for without the v prefix, like 0.118.0. A version with the v prefix like v0.118.0, triggers a separate build on JitPack.

Example imports

Check https://github.com/jitpack/jitpack.io#building-with-jitpack for details, like including commit or branch level import.

  • implementation "com.termux.termux-app:termux-shared:0.118.0"
  • implementation "com.termux.termux-app:termux-shared:master-SNAPSHOT"
  • implementation "com.termux.termux-app:termux-shared:8e3a8980a8"
  • implementation "com.github.termux.termux-app:termux-shared:0.118.0"
  • implementation "com.termux.termux-app:terminal-view:0.118.0"

Manual jar/aar Files Download

The builds logs at https://jitpack.io/#termux/termux-app will list the paths for the files generated at the end under Files: section. You can append those paths to "https://jitpack.io/" to download a specific file.

GitHub Packages

The Termux libraries were published on GitHub Packages for versions 0.109-0.114 but has since been stopped. GitHub Package hosting is considered a private repository since it requires github API keys if a hosted library needs to be imported as a dependency. Importing from private repositories is not allowed as per F-Droid policy so Termux plugin apps can't import Termux libraries as dependencies when building on F-Droid, so we moved to JitPack publishing.

There are plans to continue publishing on GitHub Packages as well in future, but requires modifying build.gradle maven-publish tasks to publish both on GitHub and JitPack and also support local publishing. This should also allow comparisons of GitHub and F-Droid releases against each other for security reasons (software supply chain attacks), assuming any problems of reproducible builds are solved.

For importing the libraries in your project, you need to follow the following instructions.

  1. Create a GitHub access token to download packages. You can create it from your GitHub account from Settings -> Developer settings -> Personal access tokens -> Generate new token. You must enable the read:packages scope when creating the token. You can get more details at AndroidLibraryForGitHubPackagesDemo.

  2. Create github.properties file in project root directory, and set your username and token. Also optionally add the github.properties entry to .gitignore file so that your token doesn't accidentally get added to git, most of the Termux apps already have it ignored.

GH_USERNAME=<username>
GH_TOKEN=<token>
  1. Add to app module level build.gradle if you want to import termux-shared.
def githubProperties = new Properties()
githubProperties.load(new FileInputStream(rootProject.file("github.properties")))

dependencies {
    implementation "com.termux:termux-shared:0.114"
}

repositories {
    maven {
        name = "GitHubPackages"
        url = uri("https://maven.pkg.github.com/termux/termux-app")

        credentials {
            username = githubProperties['GH_USERNAME'] ?: System.getenv("GH_USERNAME")
            password = githubProperties['GH_TOKEN'] ?: System.getenv("GH_TOKEN")
        }
    }
}

Remove Extra Dependency Files

If you don't plan on using the following specific classes in your app, then remove their JNI lib dependency from APK file during build time as well.

android {
    packagingOptions {
        // Remove terminal-emulator and termux-shared JNI libs added via termux-shared dependency
        exclude 'lib/*/libtermux.so'
        exclude 'lib/*/liblocal-socket.so'
    }
}

Target SDK 30 Package Visibility

If your third-party app has set targetSdkVersion to >=30 (android >= 11), then it needs to add com.termux package to the queries element or request QUERY_ALL_PACKAGES permission in its AndroidManifest.xml. Otherwise it will get PackageSetting{...... com.termux/......} BLOCKED errors in logcat when interacting with termux-app, like with RUN_COMMAND intent and it will not work.

<manifest
    <queries>
        <package android:name="com.termux" />
   </queries>

   <application
       ....
   </application>
</manifest>

Check package-visibility, QUERY_ALL_PACKAGES googleplay policy and this article for more info.

Forking and Local Development

If you are forking the termux-app plugins, then you will need to import your own modified version of the termux-shared library in which you updated the package name, etc in the TermuxConstants class. By default, the build.gradle file of plugin apps will import the libraries published for com.termux package name and you can't use them in your forked plugins. You can either publish your modified termux-shared library via local maven publishing to build your apps or publishing your libraries on JitPack or GitHub and import them instead, i.e with your groupId com.github.<user>.

If you are a maintainer/contributor of the termux-app plugins and need to update the termux-shared or the other libraries and want to test the updates locally before pushing them upstream, then you can use local maven publishing for that too.

For updating and publishing the libraries locally, you need to follow the following instructions.

  1. Firstly git clone the termux-app repo. Make whatever changes you need to make to termux-shared or other libraries. Then from the root directory of termux-app, run ./gradlew publishReleasePublicationToMavenLocal. This should build a release version of all the libraries and publish them locally. You can view the published files at ~/.m2/repository/com/termux/. The version with which they are published will be defined by the versionName value in the build.gradle file.

  2. In the root level build.gradle file of the plugin, uncomment the mavenLocal() line so that local version of termux-shared that was published in 1 gets sourced. You should also keep the maven { url "https://jitpack.io" } line uncommented in case other JitPack dependencies need to be sourced remotely, that are not available locally.

allprojects {
    repositories {
    	...
        mavenLocal()
        //maven { url "https://jitpack.io" }
    }
}
  1. In the app level build.gradle file of the plugin, comment out the original com.termux.termux-app:termux-shared:* dependency line and replace it with com.termux:termux-shared:*. Note that the groupId used by JitPack is com.termux.termux-app, but when publishing locally, its com.termux.
dependencies {
    //implementation "com.termux.termux-app:termux-shared:0.118.0"

    // Use if below libraries are published locally by termux-app with `./gradlew publishReleasePublicationToMavenLocal` and used with `mavenLocal()`.
    // If updates are done, republish there and sync project with gradle files here
    implementation "com.termux:termux-shared:0.118.0"
}
  1. Run Sync Gradle with Project Files in Android Studio in File drop down menu of the plugin app window to import the locally published library. You can check the Build tab at the bottom of Android Studio for any import errors.

Now every time you make changes in termux-app libraries, run ./gradlew publishReleasePublicationToMavenLocal to publish the changes and then in the plugin app, run Sync Gradle with Project Files to import the changes.

  1. When testing is complete, make appropriate commits in termux-app and push them to termux-app upstream. If you are making a pull request, you will need to wait for changes to be merged with master before you will be able to push the plugins to their upstream. Once changes have been committed to master, find the commit hash from GitHub for your commit or the latest commit, then go to https://jitpack.io/#com.termux/termux-app and trigger a build for that commit under the Commits tab with Get it button and make sure it succeeds. You necessarily don't need to trigger build manually, importing it in plugin app in 5 will automatically do it, but since it may timeout/fail the first time, best do it before pushing changes to upstream. Note that by default, JitPack uses first 10 characters for versions based on commit hashes.

  2. In your plugin app, revert the changes made in 2 and 3 but update the original dependency line with the commit hash from JitPack, like for example 8e3a8980a8. If instead of commit hash, a new version termux-app was published, like 0.118, then use that instead of commit hash as version. Then make a commit like Changed: Bump termux-shared to 8e3a8980a8 and push changes to plugin upstream.

dependencies {
    implementation "com.termux.termux-app:termux-shared:8e3a8980a8"

    // Use if below libraries are published locally by termux-app with `./gradlew publishReleasePublicationToMavenLocal` and used with `mavenLocal()`.
    // If updates are done, republish there and sync project with gradle files here
    //implementation "com.termux:termux-shared:0.118.0"
}

Note that making changes to library after dependencies have already been cached without incrementing version number may need deleting gradle cache if syncing gradle files doesn't work after publishing changes. This shouldn't normally happen, but sometimes does. Open Gradle right sidebar in Android Studio, then right click on top level entry, then select Refresh Gradle Dependencies, which will redownload/refresh all dependencies and will take a lot of time. Instead you can run find ~/.gradle/caches/ -type d -name "*.termux*" -prune -exec rm -rf "{}" \; -print to just remove termux cached libraries, and then running gradle sync again.