Example: Writing a Settings Page
This tutorial will guide you on how to create a custom settings page using LuaHook.
1. Introduction
LuaHook allows you to create simple UI interfaces using Lua scripts, often used for configuring your Hook logic.
2. Settings Page Code Overview
Below is a typical Lua settings page script structure, showcasing a basic interface with a TextView and a Button:
::set::
function setActivity()
-- Import necessary Java classes for UI components and functionality
import "com.kulipai.luahook.util.*"
import "java.lang.*"
import "android.widget.Toast"
import "android.widget.*"
-- Define a global print function for debug output
function print(...)
local text = table.concat({ ... }, " ")
Toast.makeText(this, tostring(text), Toast.LENGTH_SHORT).show()
end
-- Use Lua table to define layout
local layout = {
LinearLayout, -- Root layout is LinearLayout
gravity = "center", -- Center content
id = "filelayout", -- Layout ID
orientation = 1, -- Vertical orientation (1=Vertical, 0=Horizontal)
layout_width = "fill", -- Fill parent width
layout_height = "fill", -- Fill parent height
{
TextView, -- Text view
id = "tv", -- Widget ID
textIsSelectable = true, -- Text selectable
gravity = "center", -- Center text
layout_width = "fill", -- Fill parent width
text = "Test Text", -- Default text
},
{
Button, -- Button view
id = "btn", -- Widget ID
layout_marginTop = "16dp", -- Top margin 16dp
layout_marginBottom = "16dp", -- Bottom margin 16dp
gravity = "center", -- Center content
layout_width = "fill", -- Fill parent width
text = "Test Button", -- Button text
},
}
-- Load and set layout to current Activity
activity.setContentView(loadlayout(layout))
-- Bind button click event
btn.onClick = function()
tv.setText("I Love LuaHook") -- Modify text content
end
end3. Key Points
loadlayoutFunction: This function is responsible for converting the layout structure defined by the Lua table into actual Android View objects and rendering them on the screen.- Event Binding: You can bind event listeners directly to UI widgets using the concise
WidgetID.onClickway, e.g.,btn.onClick = function() ... end. - Layout Attributes:
layout_width/layout_height: Can be set to"fill"(match_parent) or"wrap"(wrap_content).gravity: Controls the alignment of view content.orientation: Only applicable toLinearLayout, determines the arrangement direction of child views (vertical or horizontal).
- Units: In Android layouts, it is recommended to use
dp(density-independent pixels) as the unit for dimensions to ensure consistent display on screens with different densities.
4. Page Navigation and Parameter Passing
LuaHook provides two main ways to implement settings page navigation: Starting ScriptSetActivity via encapsulated Intent or Directly using the injectActivity method. Regardless of the method, ScriptSetActivity is ultimately used as the unified entry point to load and display the Lua settings page. Parameter passing is done via the standard Intent.putExtra mechanism.
4.1 Navigation via Encapsulated Intent
To simplify page navigation logic, it is recommended to encapsulate a helper function to centrally handle Intent construction and launching. This provides clearer control, especially when you need to pass complex parameters or configure other Intent settings.
local function startScriptActivity(context, scriptName, arg)
import "android.content.ComponentName"
import "android.content.Intent"
local intent = Intent()
-- Explicitly specify target Activity component as LuaHook's ScriptSetActivity
intent.setComponent(ComponentName("com.kulipai.luahook",
"com.kulipai.luahook.activity.ScriptSetActivity"))
-- Pass parameters via Intent.putExtra.
-- 'arg' is an example key name, you can define different keys as needed.
intent.putExtra("arg", arg)
-- Build the full path of the script file, this is key for ScriptSetActivity to load the Lua script
local packageName = context.getPackageName()
intent.putExtra("path", "/data/local/tmp/LuaHook/AppScript/" .. packageName .. "/" .. scriptName .. ".lua")
-- Start target Activity
context.startActivity(intent)
end4.2 Navigation via injectActivity Method
The injectActivity method is a more direct navigation way provided by LuaHook, typically used to inject and start a new Activity at runtime. Its underlying implementation principle is similar to starting ScriptSetActivity via encapsulated Intent, both passing Lua code or file path as parameters to ScriptSetActivity.
The basic usage of injectActivity is as follows:
-- injectActivity(currentActivityInstance, luaCodeString/luaFilePath)
-- Currently mainly supports lua code strings
injectActivity(currentActivity, "print('Hello from injected Activity')")Important Notes:
- Currently
injectActivitymainly supports directly passing Lua Code String. This means you need to pass the entire Lua logic of the settings page as a string. - If you need to pass parameters, whether using
startScriptActivityorinjectActivity, you still need to pass them via the primitiveIntent.putExtramethod. This is becauseScriptSetActivityuniformly receives all necessary startup info and parameters viaIntent.
4.3 Host Page Call Example
The following example shows how to call the encapsulated startScriptActivity function in the host app's Lua script to jump to the settings page and pass a string parameter. If you choose to use injectActivity directly, the logic is similar, but you need to pass the entire Lua code defined by ::set:: as a string.
hookcotr(
"com.tencent.mm.pluginsdk.ui.chat.ChatFooter", -- Target class
loader,
"android.content.Context",
"android.util.AttributeSet",
"int",
function(it) end,
function(it)
local button = getField(it.thisObject, "w") -- Get a button instance in the host app
local context = invoke(button, "getContext") -- Get current context
button.onLongClick = function() -- Button long click event
-- Call encapsulated function, jump to settings page named "CurrentScriptName", and pass parameter "Hello"
startScriptActivity(context, "CurrentScriptName", "Hello")
-- If using injectActivity, it would look roughly like this (need to convert ::set:: function to string):
-- local luaCode = [[
-- ::set::
-- function setActivity()
-- -- ... Your settings page code ...
-- end
-- ]]
-- injectActivity(context, luaCode)
end
end
)4.4 Settings Page Receiving Parameters Example
In the settings page script defined by ::set::, whether you jumped via startScriptActivity or injectActivity, you can get the passed parameters via the this.getIntent().getExtras() method:
::set::
function setActivity()
import "com.kulipai.luahook.util.*"
import "java.lang.*"
import "android.widget.Toast"
import "android.widget.*"
function print(...)
local text = table.concat({ ... }, " ")
Toast.makeText(this, tostring(text), Toast.LENGTH_SHORT).show()
end
-- Get string parameter "arg" passed from Intent
local argStr = this.getIntent().getExtras().getString("arg")
local layout = {
LinearLayout,
gravity = "center",
id = "filelayout",
orientation = 1,
layout_width = "fill",
layout_height = "fill",
{
TextView,
id = "tv",
textIsSelectable = true,
gravity = "center",
layout_width = "fill",
text = "Test Text",
},
{
Button,
id = "btn",
layout_marginTop = "16dp",
layout_marginBottom = "16dp",
gravity = "center",
layout_width = "fill",
text = "Test Button",
},
}
activity.setContentView(loadlayout(layout))
btn.onClick = function()
-- Set the received parameter to the text view
tv.setText(argStr)
end
end5. Future Outlook (To Be Implemented)
Currently, page navigation and parameter passing rely mainly on ScriptSetActivity as a unified entry point, and passing implementation via Intent.putExtra. Future plans include supporting more flexible navigation ways and parameter passing mechanisms, including:
- Passing Lua Function via
::set::: Allow passing Lua function references directly to implement more advanced callbacks and interactions. - Passing via Lua File Path: Simplify organization and loading of large Lua scripts, avoiding long strings.
These improvements will further enhance LuaHook's convenience and power in developing custom settings pages.
