On Android target platforms Storyboard provides an additional level of platform integration. In order to access the native Java service API on Android platforms Storyboard has incorporated the LuaJava module to provide a bridge from Storyboard Lua script functions to the Android Java API.
The general mapping of standard Lua/Java types such as strings and numbers is handled transparently so that Lua strings can be used in Java constructors and methods in the same way that that the Java String class would normally be used and similarly for Lua numbers and vice/versa.
When a Lua variable is created that is a reference or proxy to a Java object, then access to the
methods of that object are performed using the colon (:
) notation with the Lua
variable, i.e. lua_variable:method_name()
notation. When accessing static member
variables of an object, this can be performed using the traditional dot (.
) notation
lua_variable.member_variable_name
. This is further demonstrated in the examples shown below.
A description of the complete Android Java API is beyond the scope of this document. For
a complete coverage of the Android API refer to
http://developer.android.com/reference/packages.html
Depending on the functionality that your appication is going to access, there may be additional
restrictions that must be explicitely declared in the AndroidManifest.xml
file.
A template file can be imported to a Storyboard project in Storyboard Designer by selecting
File > Import > Storyboard > Android Manifest
. Select this custom manifest file
when exporting your Android project to ensure the appropriate permissions are applied to the
Android application package.
The mapping of Lua referenced objects to Android Java objects is releatively straightforward.
All of the API functionality is accessed via the luajava
Lua global variable. This
variable provides four functions that can be used to access and manipulate standard Java objects
and one variable that provides the Android Activity
that is required.
This function creates a new Java object based on the fully qualified class name. Any additional parameters that are provided are passed through to the standard Java constructor.
The return value is a Lua variable that is a proxy to the Java object or nil
if
the class could not be instantiated.
-- Create an instance of a Java string tokenizer local strTk = luajava.newInstance("java.util.StringTokenizer", "a,b,c,d", ",") while strTk:hasMoreTokens() do print(strTk:nextToken()) end -- Create a new Android Intent object (unpopulated) local intent = luajava.newInstance("android.content.Intent")
This function creates a reference to a Java class based on a fully qualified class name. This
is difference from newInstance()
in that a new Java object is not created and the
constructor is not invoked, but simply a reference to the class is returned. Use this when
you need access to static fields or methods of a Java object.
The return value is a Lua variable that is a proxy to the Java Class object specified or nil
if
the class could not be found.
-- Get the current system time local sys = luajava.bindClass("java.lang.System") print ( sys:currentTimeMillis() ) -- Parse a string into an Android Uri local uriClass = luajava.bindClass("android.net.Uri") local phoneURI = uriClass:parse("tel:6135951999")
This function is similar to the newInstance()
function but rather than taking a
fully qualified class name it takes an existing Class reference, generally obtained from
calling bingClass(). Additional parameters can be passed to the Java constructor.
.
The return value is a Lua variable that is a proxy to the Java object or nil
if the
class could not be instantiated.
-- Create a new string instance str = luajava.bindClass("java.lang.String") strInstance = luajava.new(str)
If a Java API requires an interface to be implemented or provided as a set of callbacks,
then is is where the createProxy()
function can be used. The
interfaceNames parameter is a comma seperated list of fully qualified
Java interfaces that will be implemented by the Lua variable luaObject.
The names of the interface methods must be present in the luaObject
variable.
The return value is a Lua variable that can be passed to any function or method that
requires an implementation of that interface. If the creation of the proxy fails, then
nil
is returned.
-- Create a Lua variable with the same interface as an ActionListener local button_cb = {} function button_cb.actionPerformed(ev) -- I would do something interesting here ... end -- Map the Lua variable to the Java interface buttonProxy = luajava.createProxy("java.awt.ActionListener", button_cb) -- Use the newly created interface instance on a Java object button = luajava.newInstance("java.awt.Button", "execute") button:addActionListener(buttonProxy)
All significant interaction on an Android system involves working with an Activity
(see http://developer.android.com/reference/android/app/Activity.html)
Storyboard applications that are deployed to Android devices run as native activities which
is a special class of the general Activity that allows those applications to interact directly with the
graphics context and are generally C/C++ applications rather than pure Java applications.
The return value of this function is a Lua variable that is a proxy for the NativeActivity Java
class used by this application or nil
if the class could not be instantiated.
-- Start an activity specified by a previously created Intent object local na = luajava.nativeActivity() if(na ~= nil) then na:startActivity(intent) else print("No Native Activity") end
This example demonstrates how a phone call could be invoked as part of a Lua callback.
In order for this example to work, the AndroidManifest.xml file must be changed to give
permission for calls to be made:
%<uses-permission android:name="android.permission.CALL_PHONE"></uses-permission>
-- Log message routine to route diagnostic messages local function lm(msg) print(msg) end -- Call a selected phone number using the Android API -- Input is the string number value that is to be called local function call_phone_number(number) if(luajava == nil) then lm("No luajava Lua object") return end local na = luajava.nativeActivity() if(na == nil) then lm("No native activity available") return end local uriClass = luajava.bindClass("android.net.Uri") if(uriClass == nil) then lm("No java.lang.String object") return end local phoneURI = uriClass:parse("tel:" .. tostring(number)) if(phoneURI == nil) then lm("No java.net.URI object") return end local intentClass = luajava.bindClass("android.content.Intent") if(intentClass == nil) then lm("No intent class") return end local intent = luajava.newInstance("android.content.Intent", intentClass.ACTION_CALL, phoneURI) if(intent == nil) then lm("No intent object") return end lm("Calling " .. number) na:startActivity(intent) end