在Android网页中嵌入Lua
在 Android 应用程序中集成 Web 服务器可以提高其灵活性,因为它能与其他终端进行更具交互性的通信。
引言
在 Android 应用程序中集成 Web 服务器可以提高其灵活性,因为它能与其他终端进行更具交互性的通信。对于 Web 服务器,程序员需要编写网页,并且这些网页应该能够与宿主应用程序进行交互。本文介绍了一种在服务器端将 Lua 作为动态语言嵌入网页的想法,并提供了一个基于 starcore 和 SRPSHtmlEnvEngine 的示例,后者是一个支持 HTTP GET 和 HTTP POST 请求的可嵌入 Web 服务器。
嵌入 Lua
Lua 是一种小巧易用的脚本语言。要将 Lua 嵌入网页,我们需要定义一个 Lua 脚本标签,服务器可以找到该标签,提取 Lua 代码并执行 Lua 代码。此外,Lua 代码还可以调用宿主应用程序中定义的函数来完成更多工作。
定义 Lua 标签很简单,例如,可以使用“<?lua> <?>”来标记一段 Lua 代码。当服务器处理 HTTP 请求时,它会读取网页,检查是否有 Lua 标签。然后服务器执行代码,接收代码的输出,并将输出添加到 HTML 页面。
例如
<!DOCTYPE html>
<html>
<body>
<h1><?lua echo([[hello from lua]]) /> </h1>
</body>
</html>
Lua 代码“echo([[hello from lua]])”应该从 HTML 页面中提取并执行。然后,输出值“hello from lua”应该插入到 HTML 页面中。结果是:
<!DOCTYPE html>
<html>
<body>
<h1>hello from lua</h1>
</body>
</html>
服务器引擎需要做更多的工作。
1. 它应该解析 HTTP 请求,为 Lua 脚本创建 HTTP GET 和 POST 请求的参数。
2. 它应该能够执行 Lua 脚本。
3. 它应该能够让 Lua 轻松地在 Android 上调用 Java。因此,大多数功能都可以由宿主应用程序实现。
本文的下一部分将通过一个示例介绍如何使用 Web 浏览器从 PC 发送短信。该示例基于 starcore 和“SRPSHtmlEnvEngine”。
使用 Web 浏览器从 PC 发送短信
1. 示例页面中嵌入的 Lua 代码
<?lua>
if( _GET["submit"] == nil ) then
echo(" ")
else
--send sms
print(_POST["number"],_POST["text"]) --output info to console
HostObject:SendSms(_POST["number"],_POST["text"])
echo(hcode("Send sms to ".._POST["number"])) --output result to web page
end
<?>
_GET 和 _POST 变量是 Web 服务器根据 HTTP 请求分配的表。“_GET”对应于 HTTP GET 请求,例如,对于 http://XXX/index.html?a=123&b=456,_GET 变量将是 {a="123",b="456"}。_POST 变量对应于 HTTP POST 请求,它从 HTML 请求正文中提取。代码首先检查请求 URL 是否有“submit”参数。如果没有,则请求是从带有要发送的消息的 Web 浏览器提交的。它获取发送电话号码和文本,并调用 HostObject 的 SemdSms 函数来发送短信。HostObject 定义在宿主应用程序中,如下所示。
2. 创建项目
创建项目并将 starcore 和 SRPSHtmlEnvEngine 的库添加到项目中。如下所示:
“libstar_java.so”是 Java 的接口,“libstarcore.so”是核心共享库。“libSRPHtmlEnvEngineBasicModule_android.so”是 Web 服务器的库。assets 目录中的“index.html”文件是网页。而“SRPSHtmlEnvEngine.xml”是 Web 服务器的服务描述文件。这些文件应添加到项目中。
3. 在“AndroidManifest.xml”文件中添加用户权限
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
<uses-permission android:name="android.permission.SEND_SMS"></uses-permission>
这些权限使应用程序能够发送短信并接收 Internet 请求。
4. 主代码“MainActivity”
a. 设置 starcore 的工作路径
StarCoreFactoryPath.StarCoreCoreLibraryPath = "/data/data/"+getPackageName()+"/lib";
StarCoreFactoryPath.StarCoreOperationPath= "/data/data/"+getPackageName()+"/files";
StarCoreFactoryPath.StarCoreShareLibraryPath = "/data/data/"+getPackageName()+"/lib";
StarCoreCoreLibraryPath 是“libstarcore.so”和“libstar_java.so”的路径。StarCoreOperationPath 是 starcore 的临时文件路径。此路径可以设置为 null。StarCoreShareLibraryPath 是 starcore 其他共享库的路径。
b. 初始化 starore。
starcore= StarCoreFactory.GetFactory();
SrvGroup =starcore._InitSimpleEx(0,0);
SrvGroup._ImportServiceFromXmlBuf(servicestr, true);
SrvGroup._CreateService( ""," test", "123",5,0,0,0,0,0,"" );
Service = SrvGroup._GetService("root","123");
Service._CheckPassword(false);
使用上述代码初始化 starcore。servicestr 是服务描述 xml 字符串,从 assets 加载。
首先,我们通过 GetFactory 函数获取“starcore”对象,并调用其 _InitSimpleEx 函数来初始化 starcore 中间件。其次,我们调用 _ImportServiceFromXmlBuf 函数和带服务描述的字符串来导入 Web 服务器。最后,我们调用 _CreateService 函数来创建一个新的 starcore 服务。有关这些函数的详细信息,请参阅 starcore 的文档。为了让 Web 服务器能够访问该服务,“_CheckPassword”函数必须与输入参数“false”一起调用。
InputStream dataSource = getAssets().open("SRPSHtmlEnvEngine.xml");
int size=dataSource.available();
byte[] buffer=new byte[size];
dataSource.read(buffer);
dataSource.close();
servicestr=new String(buffer);
c. 打开 Web 服务器端口
SrvGroup._SetWebServerPort("",8080,100,0);
第一个参数应设置为“” 。第二个参数是端口号。第三个参数是同时连接的最大数量。第四个参数是最大 POST 大小,单位是 KB。
d. 创建 SHtmlEnvSiteClass 实例以处理 Web 请求
StarObjectClass a = Service._GetObject("SHtmlEnvSiteClass")._New()._Assign(new StarObjectClass(){
public Object[] FileOpen(StarObjectClass self,String Name,String RequestPara){
if( Name.equals("/index.html"))
return new Object[]{1,false};
else
return new Object[]{0,false};
}
public int FileSize(StarObjectClass self,int Handle){
try{
InputStream dataSource = getAssets().open("index.html");
return dataSource.available();
}
catch(Exception e){
return 0;
}
}
public void FileClose(StarObjectClass self,int Handle){
return;
}
public int FileRead(StarObjectClass self,int Handle,StarBinBufClass Buf,int Size){
try{
InputStream dataSource = getAssets().open("index.html");
byte[] buffer = new byte[Size];
int result = dataSource.read(buffer);
Buf._Clear();
Buf._Write(0, buffer, result);
return result;
}
catch(Exception e){
Buf._Clear();
return 0;
}
}
public void ScriptInit(StarObjectClass self,String ScriptName){
if( ScriptName.equals("lua") ){
SrvGroup._InitRaw("lua", Service);
StarObjectClass lua = Service._ImportRawContext("lua", "", false, "");
lua._Set("HostObject", new SendSmsClass());
}
});
对于该实例,我们创建了五个函数:“FileOpen”、“FileRead”、“FileSize”、“FileClose”和“ScriptInit”。
在 FileOpen 函数中,我们返回一个文件句柄供其他函数使用。因为 index.html 在 assets 中,我们为其定义了一个伪句柄 1。
对于“FileRead”函数,输入参数是 Buf 和 Size。Buf 的类型是 StarBinBufClass,它在 starcore 中定义用于二进制缓冲区。Size 是每次读取操作的最大大小。在此示例中,网页未复制到应用程序目录。它存在于安装包的 assets 中。我们直接调用 Asset Manager 的“open”函数来读取文件内容,并调用 “_Write” 方法 “\) )” 来将页面返回给 Web 服务器。“FileRead”函数的返回值是以字节为单位的数据大小。
“ScriptInit”将在网页中执行的第一个脚本时被调用。输入参数是脚本名称,可能是“lua”或“python”。在此函数中,我们创建一个 SendSmsClass 实例,并将其分配给 Lua 以便脚本调用。
e. SendSmsClass
SendSmsClass 很简单。它有一个 SendSms 函数,以 number 和 txt 作为输入参数。
class SendSmsClass{
public void SendSms(String number,String txt){
if( number == null || txt == null )
return;
SmsManager sms=SmsManager.getDefault();
sms.sendTextMessage(number, null, txt, null, null);
}
};
f. 创建一个计时器来驱动 starcore
最后一步是创建一个计时器并调用 starcore 的 SRPDispatch 方法。
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg)
{
while( starcore._SRPDispatch(false) == true );
}
};
timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask()
{
@Override
public void run()
{
Message message = handler.obtainMessage(); //handler is an instance of type Handler
message.what = 1;
message.sendToTarget();
}
}, 0, 10); /*change from 10 to 100 */
5. 截图
关于示例
该示例使用 starcore 定义的一些函数。有关这些函数的详细信息,请参阅 starcore 的文档。该代码将 Lua 嵌入网页。此外,我们也可以将 Python 嵌入网页。这也很简单,因为 Python 也可以在 Android 上运行。