65.9K
CodeProject 正在变化。 阅读更多。
Home

在Android网页中嵌入Lua

starIconstarIconstarIconstarIconstarIcon

5.00/5 (1投票)

2013年4月7日

CPOL

5分钟阅读

viewsIcon

24525

downloadIcon

428

在 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("&nbsp;")
    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 上运行。

© . All rights reserved.