Register a callback function that can be called from JavaScript.
webView:registerCallback("methodName", function(data)
-- data: JavaScript data automatically converted to Lua types
print("Received data:", json.prettify(data))
-- Return value will be converted to JavaScript types
return {
message = "Response from Lua",
timestamp = os.time(),
received = data
}
end)
Listen for events sent from JavaScript.
webView:on("eventName", function(data)
-- data: Event data from JavaScript
print("Received event:", json.prettify(data))
-- Send response back
webView:send("responseEvent", {
message = "Event processed",
timestamp = os.time(),
originalData = data
})
end)
Send events to JavaScript.
webView:send("eventName", {
message = "Event from Lua",
timestamp = os.time()
})
Inject JavaScript code into WebView.
webView:injectJS([[
// Injected code can access DOM
var target = document.getElementById("targetId");
if (target) {
target.innerHTML = "Updated by injection";
target.style.backgroundColor = "#" + Math.floor(Math.random()*16777215).toString(16);
}
// Can use NativeBridge
NativeBridge.sendToLua("injectionComplete", {
success: true,
time: new Date().toLocaleTimeString()
});
]])
Important Notes:
- Must inject after NativeBridge is ready (in onNativeBridgeReady)
- Check for DOM element existence
- Handle multiple executions
- Avoid global namespace pollution
Best Practice:
window.onNativeBridgeReady = function() {
// Safe to inject JavaScript here
webView:injectJS([[
// Your injection code
]]);
};
window.onNativeBridgeReady = function() {
// NativeBridge is ready
console.log("NativeBridge ready");
initializeFeatures();
};
Call registered Lua callbacks.
// Call Lua function
NativeBridge.callNative("methodName", {
message: "Test message",
timestamp: Date.now()
}).then(result => {
console.log("Response from Lua:", result);
}).catch(error => {
console.error("Error:", error);
});
Send events to Lua.
// Send event to Lua
NativeBridge.sendToLua("eventName", {
message: "Event from JS",
timestamp: Date.now()
});
Listen for events from Lua.
// Listen for Lua events
NativeBridge.on("eventName", function(data) {
console.log("Received from Lua:", data);
});
Lua Type | JavaScript Type | Notes |
---|---|---|
number | number | Both integers and floats preserved |
string | string | Including empty strings and Unicode |
boolean | boolean | Direct true/false mapping |
table (array) | Array | Sequential tables become arrays |
table (object) | Object | Hash tables become objects |
nil | undefined | nil becomes undefined |
JavaScript Type | Lua Type | Notes |
---|---|---|
number | number | Both integers and floats preserved |
string | string | Including empty strings and Unicode |
boolean | boolean | Direct mapping |
Array | table | Becomes table with numeric keys |
Object | table | Becomes hash table |
null/undefined | nil | Both become nil |
Date | string | Becomes ISO date string |
Function | nil | Functions not preserved |
Edge Cases:
- Sparse arrays preserve gaps:
[1,,3]
→{1, nil, 3}
- Deep nesting is supported for both objects and arrays
- Complex types (Function, Symbol) become nil
- Date objects are converted to strings
local json = require("json")
local webView = native.newWebView(
display.contentCenterX,
display.contentCenterY,
display.actualContentWidth,
display.actualContentHeight
)
webView:registerCallback("getDeviceInfo", function()
return {
platform = system.getInfo("platform"),
version = system.getInfo("architectureInfo"),
language = system.getPreference("locale", "language"),
deviceModel = system.getInfo("model")
}
end)
webView:registerCallback("consoleLog", function(data)
print("[JS]", data.message)
end)
webView:on("buttonClicked", function(data)
webView:send("buttonResponse", {message = "Received click for button " .. data.buttonId})
end)
local function injectJS()
webView:injectJS[[
function updateDeviceInfo() {
NativeBridge.callNative("getDeviceInfo").then(info => {
document.getElementById("deviceInfo").innerHTML =
`Platform: ${info.platform}<br>
Version: ${info.version}<br>
Language: ${info.language}<br>
Model: ${info.deviceModel}`;
});
}
["updateButton", "greetButton"].forEach(id => {
document.getElementById(id).addEventListener('click', () => {
if(id === "updateButton") updateDeviceInfo();
NativeBridge.sendToLua("buttonClicked", {buttonId: id.replace("Button", "")});
});
});
NativeBridge.on("buttonResponse", data => {
document.getElementById("response").textContent = data.message;
});
]]
end
webView:request("index.html", system.ResourceDirectory)
webView:addEventListener("urlRequest", function(event)
if event.type == "loaded" then injectJS() end
end)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<script>
window.onNativeBridgeReady = function() {
console.log("NativeBridge is ready!");
updateDeviceInfo();
}
</script>
</head>
<body>
<div id="deviceInfo"></div>
<button id="updateButton">Update Info</button>
<button id="greetButton">Greet</button>
<div id="response"></div>
</body>
</html>