折腾笔记[46]-在安卓手机运行基于java8的lua解释器
摘要
不走寻常路, 在安卓手机通过java虚拟机PojavLauncher运行基于java8的lua解释器.
Abstract
Running a Java 8-based Lua interpreter on Android phones through the Java virtual machine PojavLauncher;
AGENTS.md声明
本文用于投喂龙虾(openclaw).
关键信息
- java8 (jdk 1.8)
- gradle 8.5
- swing
- gradle
- luaj
- rsyntaxtextarea
简介
LuaDroid简介
[https://play.google.com/store/apps/details?id=com.alif.ide.lua&hl=zh_CN]
- LuaDroid - ide for lua
LuaDroid is an integrated development environment (IDE) designed for creating Lua scripts directly on your Android device.
J2ME Loader简介
[https://github.com/nikita36078/J2ME-Loader]
J2ME Loader是一款开源的Android平台J2ME(Java 2 Micro Edition)模拟器,由Nikita Shakarun开发。它允许用户在现代安卓设备上运行绝大多数2D及部分3D(不支持Mascot Capsule)的经典JAR游戏和应用,支持自定义虚拟键盘、屏幕缩放和屏幕尺寸设置,是重温诺基亚老游戏的最佳工具之一。
PojavLauncher简介
[https://github.com/PojavLauncherTeam/PojavLauncher]
[https://github.com/AngelAuraMC/Amethyst-Android]
PojavLauncher 是一款基于 Boardwalk 开发的、开源的、适用于 Android 和 iOS 的《我的世界》Java 版移动端启动器。它能让用户在手机上游玩几乎所有版本的 Minecraft Java 版(包含支持最新的 Java 21),支持离线和正版登录。
主要特色与功能:
- 移动端运行 Java 版: 可以在安卓/iOS设备上无缝体验原汁原味的沙盒冒险。
- 多版本切换: 支持从旧版本到最新版本的Java版游戏。
- 模组安装: 内置高度自由度,允许安装各类模组(如NPC、任务、道具)。
- 自定义控制: 支持高度可自定义的触屏控制键、背景音乐和标题。
- 在线体验: 支持自定义服务器IP和端口,确保多人协作与在线交互。
Java Runtime Environment (JRE): Download the jre8-pojav artifact from our CI auto builds. This package contains pre-built JREs for all supported architectures. If you need to build the JRE yourself, follow the instructions in the android-openjdk-build-multiarch repository.
fatjar简介
Fat JAR(也称Uber-JAR)是一种包含Java应用程序所有类、资源以及第三方依赖库的归档文件(JAR)。相比普通JAR,它“胖”在将所有依赖组件打包在一起,实现了“一次打包,处处运行”。它主要用于简化项目部署,直接用java -jar运行,极其方便。
核心特性与优势:
- all-in-one(一体化): 将业务代码和依赖项合并,无需处理复杂的CLASSPATH配置。
- 部署简便: 只需要分发一个jar文件。
- 适用场景: 非常适合微服务、命令行工具和容器化部署(如Docker),符合Java开发中便捷发布的需求。
- 构建方式: 常用 Maven(使用 maven-shade-plugin 或 maven-assembly-plugin)或 Gradle 工具生成。
luaj简介
[https://github.com/luaj/luaj]
Luaj 是一个基于 Java 实现的轻量级、高性能 Lua 解释器与虚拟机,主要用于在 Java 应用(SE、EE、ME)中无缝集成 Lua 脚本。它基于 Lua 5.2.x 版本,允许 Java 与 Lua 互相调用、互操作,广泛应用于游戏逻辑、动态扩展和配置。
核心特征:
- Java 原生实现: 无需 JNI(Java Native Interface),直接在 Java 虚拟机中运行,易于跨平台部署。
- 轻量高性能: 占用资源少,执行速度快。
- 互操作性: 支持 Java 调用 Lua 函数,以及 Lua 调用 Java 的静态方法和类。
- 完整库支持: 提供 Lua 5.2.x 标准的库,兼容性好。
Lightweight, fast, Java-centric Lua interpreter written for JME and JSE, with string, table, package, math, io, os, debug, coroutine & luajava libraries, JSR-223 bindings, all metatags, weak tables and unique direct lua-to-java-bytecode compiling.
rsyntaxtextarea简介
[https://github.com/bobbylight/RSyntaxTextArea]
RSyntaxTextArea是一个功能强大、开源的Java Swing文本编辑器组件,专为需要语法高亮和代码折叠功能的应用程序设计。它支持超过50种编程语言,并具备代码补全、搜索替换、行号显示等类似IDE的功能,是构建Java桌面应用代码编辑器的理想选择。
以下是RSyntaxTextArea的核心特点:
- 语法高亮:支持50多种主流编程语言,可高度定制。
- 代码折叠:支持代码块折叠与展开,方便查看结构。
- 高级编辑功能:包括行号、标记当前行、搜索和替换、撤销/重做。
- 扩展性强:结合AutoComplete和SpellChecker库,可实现代码补全和拼写检查。
- 易于集成:基于Java Swing框架,可直接嵌入到Java桌面应用中。
该组件通过性能优化和不断增加新语言支持,已成为Java Swing开发中进行代码编辑的常用组件。
A syntax highlighting, code folding text editor for Java Swing applications.
实现
1. 安装jdk8
[https://openjdk.org/]
[https://github.com/ojdkbuild/ojdkbuild/]
[https://github.com/ojdkbuild/ojdkbuild/releases/download/java-1.8.0-openjdk-1.8.0.322-1.b06-x86/java-1.8.0-openjdk-1.8.0.322-1.b06.ojdkbuild.windows.x86.msi]
[https://github.com/openjdk/jdk]
[https://github.com/ojdkbuild/ojdkbuild/releases/tag/java-1.8.0-openjdk-1.8.0.332-1.b09-x86]
[https://www.azul.com/downloads/]
[https://www.azul.com/downloads/#zulu]
- 记得设置JAVA_HOME系统变量
2. 构建程序
- 投喂本文给龙虾或者Claude可以直接获得jar.
- jar内嵌中文字体ttf以防乱码 🫱 [https://github.com/atelier-anchor/smiley-sans]
项目结构
.
├── build.gradle # Gradle 构建配置
├── settings.gradle # Gradle 设置
├── gradlew # Gradle 包装脚本
├── gradle/wrapper/ # Gradle 包装文件
├── src/main/java/
│ ├── HelloLua.java # 控制台示例
│ └── LuaEditor.java # GUI 编辑器(RSyntaxTextArea)
└── README.md
关键代码
build.gradle
plugins {
id 'java'
id 'application'
}
java {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.luaj:luaj-jse:3.0.1'
implementation 'com.fifesoft:rsyntaxtextarea:3.3.4'
}
application {
mainClass = 'LuaEditor'
}
jar {
manifest {
attributes 'Main-Class': 'LuaEditor'
}
from {
configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
}
// 将字体文件打包到 JAR 根目录
from('SmileySans-Oblique.ttf') {
into ''
}
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}
tasks.register('fatjar', Jar) {
group = 'build'
description = 'Creates a fat JAR with all dependencies'
archiveClassifier = 'fat'
manifest {
attributes 'Main-Class': 'LuaEditor'
}
from {
configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
}
// 将字体文件打包到 JAR 根目录
from('SmileySans-Oblique.ttf') {
into ''
}
with jar
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
destinationDirectory = file("${buildDir}/fatjar")
}
settings.gradle
rootProject.name = 'java-lua-hello'
src/main/java/HelloLua.java
import org.luaj.vm2.*;
import org.luaj.vm2.lib.jse.*;
/**
* HelloLua - LuaJ 控制台示例程序
*
* 演示内容:
* 1. 基本的 Lua 脚本执行
* 2. 获取 Lua 返回值
* 3. 定义和调用 Lua 函数
* 4. Java 与 Lua 互操作
*/
public class HelloLua {
public static void main(String[] args) {
// 创建 Lua 全局环境(包含标准库)
Globals globals = JsePlatform.standardGlobals();
// ========== 示例 1: 简单的 Hello World ==========
System.out.println("=== Lua 入门示例 ===\n");
// 加载并执行 Lua 代码
LuaValue chunk = globals.load("print '你好,来自 Lua 的世界!'");
chunk.call();
// ========== 示例 2: 数学运算 ==========
System.out.println("\n--- 数学运算示例 ---");
// 执行表达式并获取返回值
chunk = globals.load("return 10 + 20 * 2");
LuaValue result = chunk.call();
System.out.println("10 + 20 * 2 = " + result.toint());
// ========== 示例 3: 函数定义与调用 ==========
System.out.println("\n--- 函数示例 ---");
// 在 Lua 中定义阶乘函数
globals.load(
"function factorial(n)\n" +
" if n <= 1 then return 1 end\n" +
" return n * factorial(n - 1)\n" +
"end\n"
).call();
// 从 Java 中获取 Lua 函数并调用
LuaValue factorialFunc = globals.get("factorial");
LuaValue factResult = factorialFunc.call(LuaValue.valueOf(5));
System.out.println("factorial(5) = " + factResult.toint());
// ========== 示例 4: Java 与 Lua 互操作 ==========
System.out.println("\n--- Java 互操作示例 ---");
// 在 Lua 中访问 Java 类
chunk = globals.load(
"local Math = luajava.bindClass('java.lang.Math')\n" +
"print('Java Math.PI = ' .. Math.PI)\n" +
"print('sqrt(16) = ' .. Math:sqrt(16))\n" +
"return Math:max(10, 25)\n"
);
LuaValue maxResult = chunk.call();
System.out.println("max(10, 25) = " + maxResult.toint());
System.out.println("\n=== 完成 ===");
}
}
src/main/java/LuaEditor.java
import org.luaj.vm2.*;
import org.luaj.vm2.lib.jse.*;
import org.fife.ui.rsyntaxtextarea.*;
import org.fife.ui.rtextarea.*;
import javax.swing.*;
import javax.swing.border.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.URL;
/**
* Lua 编辑器 - 使用 LuaJ + RSyntaxTextArea 的 Swing GUI 编辑器
*
* 功能:
* - Lua 语法高亮显示
* - 代码折叠
* - 运行 Lua 脚本
* - 加载/保存 .lua 文件
* - 快捷键支持 (Ctrl+R 运行)
*/
public class LuaEditor extends JFrame {
private RSyntaxTextArea codeArea; // 代码编辑区域
private JTextArea outputArea; // 输出显示区域
private Globals globals; // Lua 全局环境
private Font customFont; // 自定义中文字体
public LuaEditor() {
// 加载内嵌字体
loadEmbeddedFont();
// 设置窗口标题
setTitle("Lua 编辑器 - LuaJ + RSyntaxTextArea");
// 关闭窗口时退出程序
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// 设置窗口大小
setSize(900, 700);
// 窗口居中显示
setLocationRelativeTo(null);
// 初始化 Lua 全局环境(包含标准库)
globals = JsePlatform.standardGlobals();
// 将 Lua 的 print 函数重定向到我们的输出区域
globals.set("print", new PrintFunction());
// 初始化界面组件
initComponents();
}
/**
* 加载内嵌的中文字体
*/
private void loadEmbeddedFont() {
try {
// 从 JAR 内加载字体文件
URL fontUrl = getClass().getResource("/SmileySans-Oblique.ttf");
if (fontUrl != null) {
customFont = Font.createFont(Font.TRUETYPE_FONT, fontUrl.openStream());
// 注册字体到图形环境
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
ge.registerFont(customFont);
System.out.println("成功加载内嵌字体: SmileySans-Oblique.ttf");
} else {
System.err.println("警告: 未找到内嵌字体文件,使用系统默认字体");
customFont = new Font(Font.MONOSPACED, Font.PLAIN, 14);
}
} catch (Exception e) {
System.err.println("加载字体失败: " + e.getMessage());
customFont = new Font(Font.MONOSPACED, Font.PLAIN, 14);
}
}
/**
* 获取指定大小的自定义字体
*/
private Font getCustomFont(float size) {
if (customFont != null) {
return customFont.deriveFont(size);
}
return new Font(Font.MONOSPACED, Font.PLAIN, (int) size);
}
/**
* 初始化界面组件
*/
private void initComponents() {
setLayout(new BorderLayout(5, 5));
// === 代码编辑面板 ===
codeArea = new RSyntaxTextArea(20, 60);
// 设置 Lua 语法高亮
codeArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_LUA);
// 启用代码折叠
codeArea.setCodeFoldingEnabled(true);
// 启用抗锯齿
codeArea.setAntiAliasingEnabled(true);
// 设置自定义字体(支持中文)
codeArea.setFont(getCustomFont(14f));
// 设置默认代码示例
codeArea.setText(
"-- 欢迎使用 Lua 编辑器\n" +
"-- 在这里编写 Lua 代码,然后点击运行\n\n" +
"-- 定义一个函数\n" +
"function greet(name)\n" +
" return \"你好,\" .. name .. \"!\"\n" +
"end\n\n" +
"-- 调用函数并输出\n" +
"print(greet(\"世界\"))\n\n" +
"-- 循环示例\n" +
"for i = 1, 5 do\n" +
" print(\"计数: \" .. i)\n" +
"end\n\n" +
"-- Java 互操作示例\n" +
"local Math = luajava.bindClass('java.lang.Math')\n" +
"print('Java PI = ' .. Math.PI)\n"
);
// 代码滚动面板
RTextScrollPane codeScrollPane = new RTextScrollPane(codeArea);
codeScrollPane.setBorder(BorderFactory.createTitledBorder(
new EtchedBorder(), "Lua 代码", TitledBorder.LEFT, TitledBorder.TOP));
// === 输出面板 ===
RTextArea outputTextArea = new RTextArea(10, 60);
outputTextArea.setEditable(false);
outputTextArea.setFont(getCustomFont(13f));
// 深色背景
outputTextArea.setBackground(new Color(30, 30, 30));
// 浅色文字
outputTextArea.setForeground(new Color(200, 200, 200));
outputArea = outputTextArea;
RTextScrollPane outputScrollPane = new RTextScrollPane(outputTextArea);
outputScrollPane.setBorder(BorderFactory.createTitledBorder(
new EtchedBorder(), "输出", TitledBorder.LEFT, TitledBorder.TOP));
// === 分割面板(上下分割) ===
JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, codeScrollPane, outputScrollPane);
// 设置分割比例(代码区占 60%)
splitPane.setResizeWeight(0.6);
add(splitPane, BorderLayout.CENTER);
// === 工具栏 ===
JToolBar toolBar = new JToolBar();
toolBar.setFloatable(false);
// 设置工具栏字体
toolBar.setFont(getCustomFont(13f));
// 运行按钮
JButton runButton = new JButton("▶ 运行");
runButton.setFont(getCustomFont(13f));
runButton.setToolTipText("运行 Lua 脚本 (Ctrl+R)");
runButton.addActionListener(e -> runScript());
// 清空输出按钮
JButton clearButton = new JButton("🗑 清空输出");
clearButton.setFont(getCustomFont(13f));
clearButton.addActionListener(e -> outputArea.setText(""));
// 加载文件按钮
JButton loadButton = new JButton("📂 打开");
loadButton.setFont(getCustomFont(13f));
loadButton.addActionListener(e -> loadFile());
// 保存文件按钮
JButton saveButton = new JButton("💾 保存");
saveButton.setFont(getCustomFont(13f));
saveButton.addActionListener(e -> saveFile());
// 添加按钮到工具栏
toolBar.add(runButton);
toolBar.addSeparator();
toolBar.add(loadButton);
toolBar.add(saveButton);
toolBar.addSeparator();
toolBar.add(clearButton);
add(toolBar, BorderLayout.NORTH);
// === 状态栏 ===
JLabel statusLabel = new JLabel(" 就绪");
statusLabel.setFont(getCustomFont(12f));
statusLabel.setBorder(BorderFactory.createLoweredBevelBorder());
add(statusLabel, BorderLayout.SOUTH);
// === 键盘快捷键 ===
InputMap inputMap = getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
ActionMap actionMap = getRootPane().getActionMap();
// Ctrl+R 运行脚本
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_R, InputEvent.CTRL_DOWN_MASK), "run");
actionMap.put("run", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
runScript();
}
});
}
/**
* 运行 Lua 脚本
*/
private void runScript() {
String code = codeArea.getText();
outputArea.setText("");
outputArea.append("=== 正在运行 Lua 脚本 ===\n\n");
try {
// 加载并执行 Lua 代码
LuaValue chunk = globals.load(code);
Varargs result = chunk.invoke();
// 显示返回值
if (result.narg() > 0 && !result.arg1().isnil()) {
outputArea.append("\n=== 返回值 ===\n");
for (int i = 1; i <= result.narg(); i++) {
outputArea.append(result.arg(i).toString() + "\n");
}
}
outputArea.append("\n=== 脚本执行成功 ===");
} catch (LuaError e) {
// 显示错误信息
outputArea.append("\n=== 错误 ===\n");
outputArea.append(e.getMessage() + "\n");
}
}
/**
* 加载 Lua 文件
*/
private void loadFile() {
JFileChooser chooser = new JFileChooser();
chooser.setFileFilter(new javax.swing.filechooser.FileNameExtensionFilter("Lua 文件 (*.lua)", "lua"));
if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
File file = chooser.getSelectedFile();
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
StringBuilder content = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
content.append(line).append("\n");
}
codeArea.setText(content.toString());
setTitle("Lua 编辑器 - " + file.getName());
} catch (IOException e) {
JOptionPane.showMessageDialog(this,
"加载文件失败: " + e.getMessage(),
"错误",
JOptionPane.ERROR_MESSAGE);
}
}
}
/**
* 保存 Lua 文件
*/
private void saveFile() {
JFileChooser chooser = new JFileChooser();
chooser.setFileFilter(new javax.swing.filechooser.FileNameExtensionFilter("Lua 文件 (*.lua)", "lua"));
if (chooser.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) {
File file = chooser.getSelectedFile();
// 自动添加 .lua 扩展名
if (!file.getName().endsWith(".lua")) {
file = new File(file.getAbsolutePath() + ".lua");
}
try (PrintWriter writer = new PrintWriter(new FileWriter(file))) {
writer.print(codeArea.getText());
setTitle("Lua 编辑器 - " + file.getName());
} catch (IOException e) {
JOptionPane.showMessageDialog(this,
"保存文件失败: " + e.getMessage(),
"错误",
JOptionPane.ERROR_MESSAGE);
}
}
}
/**
* 自定义 print 函数,将输出重定向到输出区域
*/
private class PrintFunction extends org.luaj.vm2.lib.VarArgFunction {
@Override
public Varargs invoke(Varargs args) {
StringBuilder sb = new StringBuilder();
for (int i = 1; i <= args.narg(); i++) {
if (i > 1) sb.append("\t");
sb.append(args.arg(i).toString());
}
outputArea.append(sb.toString() + "\n");
return NONE;
}
}
public static void main(String[] args) {
// 设置系统外观
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {
e.printStackTrace();
}
// 在事件调度线程中创建和显示 GUI
SwingUtilities.invokeLater(() -> {
new LuaEditor().setVisible(true);
});
}
}
3. 效果
| macOS | android |
|---|---|
![]() |
![]() |

不走寻常路, 在安卓手机通过java虚拟机PojavLauncher运行基于java8的lua解释器.Running a Java 8-based Lua interpreter on Android phones through the Java virtual machine PojavLauncher.


浙公网安备 33010602011771号