AutoLua is a lightweight Android scripting tool based on LuaJava. Call Java/Android APIs directly from Lua — no compilation required.
Common use cases:
Default project structure:
init.lua initialization script, runs first on app launchlayout.aly UI layout filemain.lua main program entryscript.lua script entry.alp compressed project file for import/exportCreate a Demo project in the app to get started. Example — a button with click handler:
import("android.widget.*") layout = { LinearLayout, orientation = "vertical", { Button, text = "点击", id = "btn" }, } activity.setContentView(loadlayout(layout)) btn.onClick = function(v) print("clicked") end
Main areas:
import() is the core mechanism: wildcard .* imports entire packages (lazy), class name imports a single class, inner classes use $ separator. Return value can be assigned to variables; also supports loading Lua modules.
import("android.widget.*") -- import entire package import("android.widget.Button") -- import single class import("android.view.View$OnClickListener") -- inner class local Btn = import("android.widget.Button") -- assign to variable
loadlayout(t [, root]) parses a layout table into a view tree. id values are auto-injected into the root table (default _G), accessible as global variables.
layout = {
LinearLayout,
orientation = "vertical",
{
TextView,
id = "tv",
text = "Hello",
textSize = "18sp",
},
}
activity.setContentView(loadlayout(layout))
print(tv.getText()) -- id auto-injected, no declaration neededDefine these global functions; the app calls them automatically at the corresponding lifecycle stage:
function onCreate() -- app created print("onCreate") end function onStart() -- app visible print("onStart") end function onResume() -- app enters foreground print("onResume") end function onPause() -- app enters background print("onPause") end function onStop() -- app invisible print("onStop") end function onDestroy() -- app destroyed print("onDestroy") end
Widget events are bound via Lua function assignment, with getter/setter shorthand.
btn.onClick = function(v) print(v) end btn.onLongClick = function(v) return true -- return true = handled end
Getter/setter shorthand: btn.text = "hello" is equivalent to btn.setText("hello")
Requires root permission
ScriptApi is a built-in automation module that wraps touch, image/color, key, and input method operations. Global simulation via root — no dependency on Accessibility Service. Complements the Accessibility Service approach.
Import via require("ScriptApi"), or call Install2Global() to inject into the global namespace.
Switch to AutoLua IME and input text. First call auto-selects as default IME.
InputText("hello")Restore system default IME.
Launch the specified app. If activity is omitted, auto-resolves the launch Activity.
RunApp("com.android.settings")Force-stop the specified app.
Check app install and run status.
| Return | Description |
|---|---|
| -1 | Not installed |
| 0 | Installed, not running |
| 1 | Installed and running |
| 2 | Running status unknown |
Enumerate matching package names, space-separated. Supports fuzzy matching; empty string enumerates all installed apps.
local pkgs = EnumApp("com.tencent")Set the development reference resolution. All subsequent coordinates are auto-scaled to screen ratio.
SetScreenScale(1080, 1920)
Disable screen scaling, restore actual coordinates.
Keep screenshot state; subsequent captures reuse system cache. Pair with ReleaseCapture() to avoid repeated screenshots.
Release screenshot hold.
Capture full screen and save to file.
SnapShot("/sdcard/screen.png")Capture a rectangular region and save. Pass 0 for screen edge; deg is clockwise rotation count (0-3).
Capture(0, 0, 500, 300, "/sdcard/crop.png")
Get the pixel color at the specified coordinates.
| Parameter | Type | Required | Description |
|---|---|---|---|
| x | number | ✓ | X coordinate |
| y | number | ✓ | Y coordinate |
| type | number | ✗ | 0=hex (default) 1=decimal |
local hex = GetColor(100, 200)
Count pixels matching the specified color within the region. Pass 0 for boundaries.
Single-point color compare. Check if the color at coordinates matches. Similarity 0-1 (1 = exact match).
true match, false no matchCmpColor(100, 200, "0xFF0000", 0.9)
Multi-point color compare. Check multiple coordinates at once. Format: "x|y|color,...".
true all match, false any mismatchCmpColorEx("100|200|0xFF0000,300|400|0x00FF00", 0.9)
Find a color within a region. Pass 0 for boundaries; dir=0 = left-to-right, top-to-bottom.
| Return | Description |
|---|---|
| ret | ≥0 found, <0 not found |
| x, y | Match point coordinates |
local ret, x, y = FindColor(0, 0, 0, 0, "0xFF0000", 0, 0.9) if ret >= 0 then Tap(x, y) end
Multi-point color find. Locate the main color first, then verify each offset point. Pass 0 for boundaries.
| Parameter | Type | Description |
|---|---|---|
| x1,y1,x2,y2 | number | Search region (0=boundary) |
| main | string | Main color |
| offsets | string | Offset string offX|offY|color |
| dir | number | Search direction (0/1/2) |
| sim | number | Similarity 0-1 |
FindMultiColor(0, 0, 0, 0, "0xFF0000", "10|0|0x00FF00,-10|0|0x0000FF", 0, 0.9)
Key press / release.
Full key press (down + up).
KeyPress("BACK") KeyPress("HOME")
Tap at coordinates.
Tap(500, 300)
Swipe from start to end. ms defaults to -1 (auto speed).
Swipe(100, 500, 900, 500, 500)
Hold at coordinates. ms defaults to -1 (hold indefinitely).
Touch(500, 300, 2000)
Multi-touch. id defaults to 0, used to distinguish fingers.
TouchDown(300, 400, 0) TouchMove(600, 400, 0, 200) TouchUp(0)
Delay in milliseconds. Thread sleeps in Java state to avoid ANR.
Delay(1000)
Check screen orientation.
true, portrait returns falseMove the script floating window to coordinates.
Inject all ScriptApi functions into the global namespace — no Script. prefix needed afterwards.
local Script = require("ScriptApi") Script.Install2Global() Tap(500, 300) -- call directly
Core module, auto-loaded — no manual require needed
Provides async tasks, timers, layout building, string processing, file I/O, debug output and more. All functions are auto-injected into the global namespace — call directly from scripts.
Execute heavy work in a thread pool, callback result on main thread. Supports arguments (boolean/number/string/Java objects). If first arg is a number, it is treated as delay in ms.
Task(function(a, b) return a + b end, 1, 2, print) -- print receives result 3 Task(1000, function() print("after 1 second delay") end)
Create an independent Lua thread with its own global environment. Cannot directly access external variables; interact with the main thread via call(t, fn) / set(t, k, v).
t = Thread("myscript", arg1, arg2) call(t, "doWork", data) set(t, "config", { timeout = 30 })
Periodic timer. delay = initial delay, period = interval in ms. Set t.enabled = false to pause, t.stop() to stop. If f has a run() method, it is called repeatedly.
t = Timer(function() print("every second") end, 0, 1000) -- t.enabled = false -- pause -- t.stop() -- stop
Parse layout table into view tree. id injected into root (default _G). Supports .aly layout files.
| Parameter | Type | Required | Description |
|---|---|---|---|
| t | table/string | ✓ | Layout table or .aly filename |
| root | table | ✗ | id→view mapping table, default _G |
layout = { LinearLayout, { TextView, id = "tv", text = "Hi" } }
activity.setContentView(loadlayout(layout))
print(tv.getText())Floating window only controls scripts launched this way Launch a new script. arg is a string; if arg points to an existing file path, it is auto-read as JSON config.
StartScript("test") StartScript("test", "hello") StartScript("test", "/sdcard/config.json") -- auto-detected as JSON
Stop the currently running script.
Output to Logcat with tag "lua". Arguments are auto-joined with spaces. adb logcat -s lua
log("x=", x, "y=", y)Serialize a Lua object to a readable string. Supports nested tables and circular reference detection.
print(DumpObj({ a = 1, b = { 2, 3 } }))
Print the current Lua call stack to Logcat for debugging call paths.
Split a string by delimiter, returns an array.
local parts = Split("a,b,c", ",") -- {"a", "b", "c"}
Remove leading and trailing whitespace.
Trim(" hello ") -- "hello"
Round to nearest integer.
Round(3.6) -- 4
Deep copy a table. n = max recursion depth (default 3). Handles circular references.
Check if file exists, returns boolean.
Read entire file contents. Returns nil on failure.
Write string to file, overwriting existing content.
Show an Android Toast message.
ShowToast("Done")Output to Logcat with arguments joined; includes current filename and line number. adb logcat -s lua
TracePrint("x=", x, "y=", y)Import a Java class/package or Lua module. Wildcard imports are lazy; class name auto-takes the last segment as variable name. See AutoLua Basics → Import Packages/Classes/Modules.
import("android.widget.*") import("android.widget.Button")
Accessibility function module imported via local AS = require("AccessibilityApi"). Provides node search, gestures, global keys etc. Requires Accessibility Service to be enabled.
Check if the Accessibility Service is connected.
if AS.IsConnected() then AS.Click(500, 300) end
Tap at coordinates.
AS.Click(500, 300)
Long-press at coordinates.
AS.LongClick(500, 300)
Press at coordinates, release after delay ms.
AS.Press(500, 300, 2000)
Swipe from start to end.
AS.Swipe(100, 500, 900, 500, 500)
Gesture swipe along a Path.
Check if a node exists, returns boolean.
local ok = AS.FindNode("确定")Find by text and click. name is a string.
AS.FindAndClick("确定")Find an input field by text and set its text.
AS.FindAndSetText("搜索", "关键词")Global back key.
Global Home key.
Global Recents key.
Open notification shade.
Inject all Accessibility Service functions into the global namespace — no AS. prefix needed afterwards.
local AS = require("AccessibilityApi") AS.Install2Global() Click(500, 300) -- call directly