Rush 2: build App Inventor extensions with Kotlin, Java and Maven libraries

Rush

Rush is a command-line tool for building App Inventor extensions in Java or Kotlin. Shreyash Saitwal created it in 2021 and introduced it in the original Rush thread, which covers Rush 1. This thread is the home of Rush 2: releases, questions and bug reports go here.

The current version is 2.1.1.

What Rush does

  • Builds extensions against App Inventor v206, the current release.
  • Supports Java and Kotlin, in the same project if you want.
  • Downloads libraries from Maven Central, Google's Maven repository or any repository you add, with their dependencies. Android libraries (AARs) ship with their resources.
  • Keeps every library private to your extension, so extensions work together in one app, on App Inventor and on Kodular.
  • Shrinks the extension and its libraries with R8, and optionally optimizes and obfuscates it.
  • Generates a Markdown reference of your blocks with every build, ready to paste into a forum post.

Highlights

  • Libraries from Maven. List a library in rush.yml and Rush downloads it with everything it depends on. No more hunting for JARs or keeping track of a library's dependencies by hand. JARs and AARs you have as files go in the deps folder.

  • Extensions work together in one app. When two extensions bundle the same library (Kotlin, Gson, Guava and so on), the app build fails with "defined multiple times", or one extension gets the other's version and crashes. Rush renames every library your extension ships under your package: its code and, for AARs, its resources, manifest and R classes too. Two extensions can ship different versions of the same library, and an old library in your extension can't clash with the one App Inventor ships. Extensions work on Kodular too, which bundles its own Kotlin and AndroidX libraries.

  • Small extensions. R8 shrinks your extension and all its libraries as one program, so code nothing uses is removed. Media3Player went from 10.2 MB to 6.6 MB, or 5.0 MB with rush build --optimize. Optimized builds also write a mapping file for reading stack traces.

  • Android libraries with their resources. Libraries like Media3's player UI ship as real AARs, and App Inventor compiles their resources into the app. Their manifests are merged into your extension's, and ${applicationId} becomes the app's package.

  • Android resources. Put layouts, drawables, strings and colors in a res folder and use them from your code through the R class, as in Android Studio. Your resources can use your libraries' resources (Media3's @drawable/exo_icon_play), and styles can extend Theme.AppCompat. Resource names start with your extension's package, so two extensions never overwrite each other's resources.

  • AndroidManifest.xml. Permissions, services, activities, receivers, providers and meta-data go in src/AndroidManifest.xml, as in an Android app, and are merged with your libraries' manifests.

  • Libraries with native code. Native code finds some classes by their original names. Rush reads the library's .so files and prints the packages to keep, as lines for rush.yml. This is how WebRTC and Firebase ship.

  • Modern Java and Kotlin. Kotlin 1.8 to 2.4, and Java 17 language features (records, sealed classes, switch expressions, text blocks) on every Android version your extension supports. Libraries compiled for Java 11 or 17 work. With min_sdk 24 or higher, java.time and other newer Java APIs work as well. Kotlin Multiplatform libraries such as supabase-kt and Ktor build too.

  • Blocks. Dropdown blocks from enums, with descriptions from Javadoc. Several components in one extension, sharing one AIX. A warning when a block returns a result App Inventor can't wait for.

  • You decide where libraries go. libraries in rush.yml places a library: private (the default), shared for libraries whose objects pass between extensions, provided for libraries App Inventor or another extension already has, or exclude. rush deps tree shows where each library goes and why.

  • GitHub Actions. New projects include a workflow that builds the extension on every push. Pushing a tag that matches the version in rush.yml, such as v1.0.0, publishes a GitHub release with the AIX and its documentation attached. shreyashsaitwal/rush-cli@v2 sets up Rush in any workflow.

  • No computer needed. The Rush extension template creates a project on GitHub that builds in the browser, and every project has a dev container for Codespaces. That works from a phone or tablet too.

  • AI coding agents and editors. Every project carries instructions for AI coding agents (AGENTS.md and a Claude skill), and VS Code and IntelliJ project files.

  • Reproducible and fast. Two clean builds of a project produce identical AIX files. Builds that change nothing skip compiling and DEX, and libraries are desugared once for all your projects.

Installing

Rush needs a JDK 17 or newer. A JRE isn't enough. Rush uses the JDK that JAVA_HOME points to, or else the one on your PATH.

Linux and macOS:

curl -fsSL https://raw.githubusercontent.com/shreyashsaitwal/rush-cli/main/scripts/install/install.sh | bash

Windows (PowerShell):

iwr https://raw.githubusercontent.com/shreyashsaitwal/rush-cli/main/scripts/install/install.ps1 -useb | iex

The installer offers to download App Inventor's runtime and build tools (about 140 MB) once. After that, builds work offline. On Linux and macOS, add the bin folder the installer prints to your PATH. On Windows, the installer does it for you; open a new terminal afterwards.

Rush runs on 64-bit Windows, Linux (x86-64) and macOS (Intel and Apple silicon).

Updating

  • Rush 2: run rush upgrade.
  • Rush 1: run the installer above. It replaces Rush 1. Then convert each project with rush migrate (commit or back it up first). The migration guide lists what to check afterwards.

Creating your first extension

Rush is a command-line tool: run it in a terminal, not by double-clicking.

rush create my_extension --package com.example --language java --ide intellij
cd my_extension
rush build

The extension is written to the out folder as an .aix file. Import it in App Inventor from the Extension palette.

Libraries go in rush.yml:

version: '1.0.0'
min_sdk: 21

dependencies:
- com.google.code.gson:gson:2.13.1

repositories:
- https://jitpack.io

Commands

Command What it does
rush create Creates a project
rush build Builds the AIX. --optimize also optimizes and obfuscates it
rush deps sync Downloads dependencies and writes the classpath for your editor
rush deps tree Shows each library and where it goes
rush clean Removes build output
rush migrate Converts Rush 1 projects and older rush.yml files
rush agents Refreshes the AI agent instructions and editor files
rush upgrade Installs the latest Rush

Questions that come up often

These are collected from the original thread, answered for Rush 2.

Is Rush an app? Nothing happens when I open it.

Rush runs in a terminal (Command Prompt, PowerShell, Terminal). Open one in the folder where you keep your extensions and run rush create. If the terminal says rush isn't found, Rush's bin folder isn't on your PATH: open a new terminal after installing, or add the folder the installer printed.

Could not run javac, or class file has wrong version

Rush needs a JDK 17 or newer, not a JRE. Check with java -version and javac -version: both must print 17 or newer. If you have several JDKs, point JAVA_HOME to the one Rush should use.

My path or Windows user name has spaces

Rush 2 builds in folders with spaces in their names, and project names can contain spaces too.

The installer can't download Rush

The installer downloads from GitHub. If your network blocks raw.githubusercontent.com or GitHub downloads, try another network or a VPN, or install by hand: download the zip for your system from the latest release, unzip it into a folder, add its bin folder to your PATH, and run rush deps sync --dev-deps.

My antivirus flags Rush

That's a false positive. Exclude Rush's folder from scanning, or install from the release zip as above.

How do I add a library?

Add its Maven coordinates (group:artifact:version) under dependencies in rush.yml, and Rush downloads it with its dependencies. For a JAR or AAR you have as a file, put it in the deps folder and list its file name instead. YAML is sensitive to indentation: keep list items under their key, as in the example above.

Permissions, services and other manifest entries

Put them in src/AndroidManifest.xml, as in an Android app. Manifests of AAR libraries are merged in automatically.

The extension builds, but the app fails with no such class or NoClassDefFoundError

Rush 1 needed ProGuard keep rules for the extension class; Rush 2 keeps your extension's classes itself. If the app crashes with a library class missing, the library usually clashes with another extension or with App Inventor's copy. Libraries are private in Rush 2, so rebuild the extensions with Rush 2. If two extensions must share a library's objects, mark it shared in both.

Missing class androidx… when building

App Inventor's AndroidX libraries are from 2018 and always win. When a library needs a newer version of one of them, the build names the missing classes and the rule to add. Jetpack Compose can't work in App Inventor.

My extension works in a built app but not in the AI Companion

The Companion can't load extensions that ship AARs, which includes extensions with resources. Test them with a built APK.

Can my extension show something in the designer?

No: App Inventor shows every extension as a non-visible component. An extension can still show views in the app: let users place an arrangement, and add your view to it from a block. See Showing views.

Can I build extensions on Android?

Use the Rush extension template or a Codespace from your project: both build in the browser.

How do I uninstall Rush?

Delete Rush's folder (~/.local/share/rush on Linux and macOS, %LOCALAPPDATA%\rush on Windows, or ~/.rush for older installs) and remove its bin folder from your PATH.

Good to know

  • App Inventor's AndroidX libraries date from 2018 and always take priority. Libraries that need a recent AndroidX, such as Jetpack Compose, do not work in App Inventor.
  • DEX files in assets are not supported, and 32-bit Windows isn't either.
  • When two extensions in one app ship androidx.startup, only one extension's initializers run (#88).

Built with Rush 2

  • Media3Player: video and audio player built on AndroidX Media3 (ExoPlayer).
  • Supabase: auth, database, realtime, storage and Edge Functions.
  • WebRTC: video and voice calls, and data channels.

Their source code is a working example if you're planning an extension on modern Android libraries. Built something with Rush? Share it in this thread.

Release history

Rush 2
  • 2.1.1 (October 2026): fixes Could not find Rush data directory after upgrading to 2.1.0.
  • 2.1.0 (October 2026): every library private by default, AARs included; whole-program R8; original_names for native libraries; Kotlin Multiplatform libraries; extensions built for different min_sdk in one app.
  • 2.0.0 (October 2026): Kotlin and Java 17, Maven dependencies, AARs with resources, Android resources, manifest merging, R8, several extensions in one app, block docs, GitHub Actions, App Inventor v206.

Full notes are on GitHub.

Reporting a problem

Reply in this thread, or open an issue, with:

  • the output of rush --version, java -version and javac -version,
  • the command you ran and its full output,
  • your rush.yml,
  • your operating system.

Ask here rather than in private messages, so the answer helps the next person too.

Credits

Thanks to Shreyash Saitwal for creating Rush, and to everyone who tested it and answered questions in the original thread.

4 Likes

Isn’t it confusing that you made a fork but still call it Rush and use the same logo?

2 Likes

If you’re willing to maintain the original repo, I can give you edit access to it.

1 Like

Thank you, I'd be glad to. I'll move my work into the original repository so there's one Rush again.

In the long run I'd like Rush to be maintained by the community rather than by one person. I'll maintain it to start with. As people get involved, I'd like a few of them to share the work of reviewing changes and publishing releases.

To make that easier, would you be open to moving the repository into a GitHub organization? You'd stay an owner, and the stars, issues and history would all come with it. GitHub also redirects the old links. If you'd rather keep it under your account, the Maintain role would be enough for now.

I kept the name because it's still Rush, the same tool and the same commands, updated for App Inventor v206.

1 Like

Here's the first extension built with Rush 2: Media3Player, a video and audio player built on AndroidX Media3 (ExoPlayer).

Media3Player in fullscreen

It uses most of what Rush 2.2 adds:

  • AARs with resources: Media3's player UI, session and download libraries ship as real AARs, and the build server compiles their resources into the app.
  • Kotlin: the whole extension is written in Kotlin.
  • Block docs: rush build generates the Markdown documentation of every block, which is attached to each release.
  • GitHub Actions: the Rush setup action builds every push, and pushing a version tag publishes a release with the AIX, the docs and a sample project.

If you're planning an extension on AndroidX or other modern Android libraries, its source code is a working example. The Media3Player topic has the features and downloads.

2 Likes

thank you :+1:

That sounds good to me. Do you have any suggestions for the org name? I was thinking maybe we can create an umbrella org open to housing any AI2 related open-source project. Let’s see what others have to say. If there’s enough interest we can go ahead with it.

1 Like

An umbrella org is the right direction. I can move all my OS AI2 projects there as well. Let's wait for some good names for the org.

1 Like

Maybe you could start using https://codeberg.org/ instead of Github. Codeberg is a place for open source software like yours. More and more open source software teams are moving from Github to Codeberg. Maybe a good time to do that too.

I too have been thinking of moving away from GitHub for a while now, but for this I think it'd be better to stick with GitHub. It has better discoverability for community projects in my opinion.

1 Like

If you want that too chance you have to join the movement. :grin: :wink:

1 Like

Rush 2.0.0: back in the original repository

Rush 2 now lives in Shreyash's repository again, where it's released as Rush 2.0.0:

The version restarts at 2.0.0 because it's the first Rush 2 release from the original repository. It contains everything from this fork's 2.0 to 2.5 releases, plus:

  • R8 replaces ProGuard. Optimized builds also write a mapping file for reading stack traces.
  • libraries in rush.yml decides where a library goes: exclude, provided, shared or private. rush deps tree shows where each one goes and why.
  • Fixes: ${applicationId} in library manifests becomes the app's package, so two apps using the same extension can be installed together. Libraries that declare ids the new way (recent AndroidX) build on App Inventor.

Installing

Linux and macOS:

curl -fsSL https://raw.githubusercontent.com/shreyashsaitwal/rush-cli/main/scripts/install/install.sh | bash

Windows (PowerShell):

iwr https://raw.githubusercontent.com/shreyashsaitwal/rush-cli/main/scripts/install/install.ps1 -useb | iex

The commands in the first post install Rush 2.0.0 too.

Already using Rush 2.1 or newer from this fork? Run rush upgrade twice: the first run installs 2.5.1, which then upgrades to 2.0.0 from the original repository. On 2.0.x, run the installer above.

Switching a project

  1. Replace zainulhassan815/rush-cli with shreyashsaitwal/rush-cli in .github/workflows/build.yml, .github/workflows/copilot-setup-steps.yml and .devcontainer/devcontainer.json.
  2. Run rush migrate. Projects created by this fork set -repackageclasses in src/proguard-rules.pro, which now fails the build. Rush applies it itself.
  3. Run rush agents to refresh the instructions for AI agents.

The fork stays online, so existing workflows keep building, but new versions only ship from the original repository.

Building in the browser

The Rush extension template creates a project on GitHub with nothing installed: a workflow creates the project, and a codespace or GitHub Copilot's coding agent writes the code. As a test, I asked Copilot for an extension that draws animated loading spinners into arrangements. Rush 2.0.0 built it, and it works in the AI Companion.

Thanks again to Shreyash for Rush, and for taking it back.

(post deleted by author)

1 Like

Awesome work…:heart:

Rush 2.1.1: everything since the move to the original repository

Rush now ships from the original repository, and the current version is 2.1.1. The version restarted when Rush moved: 2.5.1 was the last release from the old repository, 2.0.0 the first from the original, and 2.1.0 and 2.1.1 followed. Here is everything that changed since 2.5.1. The first post is updated to match.

Release notes: 2.0.0, 2.1.0, 2.1.1.

2.1: every library private by default

The biggest change since the move. Extensions no longer clash with each other, with App Inventor's own libraries, or with Kodular's.

  • Private libraries by default. Every library your extension ships is renamed under <your package>.repacked: its code, and an AAR's resources, manifest, R classes and file name. Two extensions can ship different versions of the same library. Media3Player now works next to Texting (both bundle Guava) and on Kodular (which bundles RecyclerView).
  • shared is the opt-in for libraries whose objects pass between extensions. What a shared library uses is shared too.
  • Smaller extensions. R8 shrinks the extension and all its private libraries as one program. Media3Player's AIX: 10.2 MB → 6.6 MB, or 5.0 MB with --optimize.
  • Libraries with native code stay private. Native code finds a few classes by their original names, so only their packages keep them, listed under original_names in rush.yml. Rush reads the library's .so files and prints the lines to add. Firebase now ships with Kotlin private and works on Kodular, which bundles its own Kotlin. Its AIX went from 7.8 MB to 2.0 MB.
  • Kotlin Multiplatform libraries build, such as supabase-kt and Ktor. AARs without code ship without classes.jar.
  • Extensions built for different min_sdk work in one app. A D8 bug crashed apps mixing an extension built for API 23 (Media3Player) with one built for 24 (Firebase). Rush corrects it until D8 is fixed.
  • Extension resources can use their libraries' resources: a layout can show Media3's @drawable/exo_icon_play or its DefaultTimeBar, and a style can extend a library's style or Theme.AppCompat. Code can use the R classes App Inventor generates (androidx.appcompat.R).
  • Intent actions keep their value, so other apps and the system still reach your services (Media3's MediaSessionService).
  • Optimized builds resolve ServiceLoader lookups of private libraries, which App Inventor apps can't do at runtime.
  • Android's default ProGuard rules apply to every R8 run, so a Parcelable's CREATOR no longer disappears in optimized builds.
  • Clearer missing-class errors: when a library needs a newer version of one App Inventor provides, Rush names the exact classes and the rule to add.
Smaller changes in 2.1
  • Firebase and ML Kit find their components when private: class names in every manifest attribute are renamed with their library, prefixed meta-data names included.
  • Class names in private libraries' resources (Material's bottom-sheet behavior, fragments, menus) are renamed with them.
  • Optimized builds no longer leave classes R8 renamed outside the extension's package.
  • Private AARs without resources join the extension's code.
  • Raw resources ship byte for byte, and resource XML Rush can't read fails with the file's name.
  • Downloads land in the local Maven repository atomically, so an interrupted one can't leave a broken file.
  • A relocated library is no longer dropped from its users' dependencies.
  • Projects resolve their dependencies again once after upgrading Rush.
  • The resources of App Inventor's AndroidX are downloaded once, by rush deps sync, and builds then run offline.
  • New installs go to ~/.local/share/rush (Linux and macOS) or %LOCALAPPDATA%\rush (Windows). Existing installs stay where they are.
  • Prereleases can be installed by version: RUSH_VERSION=2.1.0-beta.3 for the installers, version: for the setup action.
  • New projects allow the annotations App Inventor's AndroidX lacks (-dontwarn androidx.annotation.**).

2.1.1

2.1.0 failed with Could not find Rush data directory after rush upgrade from 2.0, after re-running the installer, and in the setup action. Rush now finds its home next to its own binary, wherever it's installed. RUSH_HOME still overrides it.

2.0.0: back in the original repository

Everything in 2.5.1, plus:

  • R8 replaces ProGuard. R8 reports classes that the shipped code uses but nothing ships as Missing class errors; add -dontwarn rules only for code that never runs. Optimized builds write a mapping file for reading stack traces.
  • Rush owns -repackageclasses. A project rule file that sets it fails the build, and rush migrate removes it.
  • libraries in rush.yml places a library: exclude, provided, shared or private. rush deps tree shows where each one goes and why. provided_dependencies is deprecated; rush migrate converts it.
  • Only libraries every App Inventor app has count as provided. The ones App Inventor adds for some components only (Guava, Gson…) are bundled.
  • A warning for Continuation<T> results, which App Inventor doesn't wait for. Deliver slow results through events.
  • Fixes: ${applicationId} in library manifests becomes the app's package, so two apps using the same extension install side by side. AARs that declare ids as <id name="…"/> (recent AndroidX) build on App Inventor. rush create no longer hangs when it isn't run in a terminal.

Upgrading

  • From 2.1 to 2.5 of the old repository: run rush upgrade twice. The first run installs 2.5.1, which then upgrades to 2.1.1 from the original repository (on 2.5.1, once is enough). On 2.0.x from the old repository, run the installer from the first post.
  • From 2.0.0 or 2.1.0: run rush upgrade. If rush fails with Could not find Rush data directory, run the installer from the first post again.

Workflows that use shreyashsaitwal/rush-cli@v2 build with 2.1.1 already.

Updating a project

Projects created before the move
  1. Replace zainulhassan815/rush-cli with shreyashsaitwal/rush-cli in .github/workflows/build.yml, .github/workflows/copilot-setup-steps.yml and .devcontainer/devcontainer.json.
  2. Run rush migrate. It removes -repackageclasses from src/proguard-rules.pro and converts provided_dependencies.
  3. Run rush agents to refresh the instructions for AI agents.

Most projects then build unchanged with 2.1. Some need one change, and the build error says which:

  • An AAR with native code (WebRTC, ML Kit, Firebase's datastore) needs the packages its native code names. The error prints the original_names lines to add to rush.yml, or the shared alternative:
    original_names:
    - org.jni_zero
    - org.webrtc
    - org.webrtc.audio
    
  • An AAR with assets or JARs in libs/ can't be renamed. The error names the shared line to add.
  • Recent AndroidX libraries use annotations App Inventor's AndroidX lacks (Missing class androidx.annotation.DoNotInline). They're only needed to compile. Add this line to src/proguard-rules.pro:
    -dontwarn androidx.annotation.**
    
  • Libraries whose objects pass between extensions need shared in each extension.
  • Extension resources can't use names starting with <package>_repacked_, which Rush gives private libraries' resources.

When you rebuild an extension with private libraries, its libraries' classes and resources change names. If an app stored something under the old names (jobs scheduled with a library's component, widgets, or data serialized with class names), mention it in your extension's release notes.

Coming next

Updates of Media3Player, Supabase and WebRTC built with 2.1, and a Firebase Cloud Messaging extension with push notifications in the foreground, the background and when the app is closed.