# Writing an ADB module for Shizuku-Next An ADB module adds to Shizuku: a zip with a `module.prop` in it, whose scripts run through the Shizuku server with the environment the ADB module format defines, and whose optional WebUI is a page inside this app with a bridge back into that shell. This app implements that format rather than one of its own. If you have written a module for Shevery or Xhizuku, it installs and runs here unchanged. The last section lists the few places where this implementation answers differently, so nothing is a surprise. The format is [kerneldroid](https://github.com/kerneldroid)'s [Nightzuku](https://github.com/kerneldroid/Nightzuku), which is where the modules, the actions and services and the `window.Shizuku` bridge come from; [Shevery](https://github.com/HmnDev-Tech/shevery) publishes the guide and API reference this one is written against, and [Xhizuku](https://github.com/xeonleonreal/Xhizuku) implements the same format. ## The package A module is a zip with `module.prop` at its root. Everything else is optional: ```text my-module.zip ├── module.prop ├── banner.png (or banner.jpg / banner.jpeg / banner.webp) ├── action.sh ├── service.sh └── webui/ └── index.html ``` ## module.prop ```properties id=my-module name=My Module version=1.0 versionCode=1 author=Your Name description=What this module does, in a sentence. banner=banner.png webui=webui action=action.sh usesShellBridge=true ``` | Key | Required | What it means | | --- | --- | --- | | `id` | yes | The directory name the module is installed under. `^[A-Za-z][A-Za-z0-9._-]{1,63}$` - a letter, then letters, digits, dots, underscores or hyphens. | | `name` | yes | What the card is called. | | `version` | no | Shown on the card as it is written. | | `versionCode` | no | The number that decides whether an update manifest is newer. | | `author` | no | Shown on the card. | | `description` | no | Shown on the card, and matched by the search box. | | `banner` | no | A picture named by the module. Without it, `banner.png`, `banner.jpg`, `banner.jpeg` and `banner.webp` are tried in that order. | | `webui` | no | The WebUI directory. Without it, `webroot`, `webui` and `web` are tried in that order. The page is only offered when `/index.html` is a file. | | `action` | no | The script an action runs, relative to the module directory. Defaults to `action.sh`. | | `usesShellBridge` | no | `true` asks for the WebUI's shell bridge. A module that does not ask for it gets the module's own information and nothing else. | `service.sh` is not named here: a file at the module root with that name is the service. Values are read literally. This is deliberately not a properties parser, so a description holding a `:` or a backslash arrives as written. ## Installing The zip is unpacked into a staging directory and only renamed to the module's `id` once its `module.prop` has named it, so a refused zip leaves nothing that looks installed, and a module can never choose where it lands. Installing over a module that is already there replaces it, which is what installing a newer zip means. Checked while reading, before anything is written: - every entry is a relative path that stays inside the module: no leading `/`, no `..` anywhere, no drive letters, no NUL bytes; - at most **2048 entries**; - at most **200 MB** unpacked in total; - at most **256 KB** per `.sh` file. Modules live in the app's external files directory, under `adb_modules/`. Not its private storage, which is the obvious place and does not work: the shell Shizuku runs a script as cannot enter an app's own directory, so the first `cd` into a module would fail and the module would look broken for no visible reason. On a device with no external storage at all, the private directory is used instead, and a module can be installed and read there but its scripts cannot run. ## Running A script is run as one command line, which is the whole of the contract: ```sh cd '' && \ MODDIR='' \ ASH_STANDALONE=1 \ SHIZUKU_MODULE_ID='' \ SHIZUKU_MODULE_MODE='safe|full' \ SHIZUKU_MODULE_TRUSTED='0|1' \ SHIZUKU_MODULE_BACKGROUND='0|1' \ sh '