Plugins allow you to extend the functionality of Corona. This guide outlines the fundamental details.
Corona plugins leverage Lua's module system in which plugins are lazily loaded by a corresponding call to the Lua require() function.
Typically, these plugins are just shared native libraries which are supported on platforms like .dylib
).dll
).so
)
.a
)..jar
).In these two cases, Corona adds special loaders which ensure that these plugins can be easily loaded, assuming certain conventions are followed.
Library plugins are simply Lua modules which can be used to wrap native functionality. These libraries are namespaced with the prefix plugin.
. The prefix helps avoid namespace collisions with Corona libraries.
These libraries should be loaded with the Lua require() function. For example, if there were a new library plugin named myLibraryPlugin
, you could access it in Lua like this:
local myLibraryPlugin = require( "plugin.myLibraryPlugin" )
Provider plugins are also Lua modules, but you do not load them directly via require(). Instead, the wrapper library (or function) allows you to specify the provider and then it loads the plugin for you.
In order for the provider to be loaded, it needs to follow a specific namespace convention. Provider plugins are prefixed with CoronaProvider.
followed by the name of the wrapper and the provider plugin name.
Most plugins you create will be library plugins, not provider plugins. The main difference is that library plugins are just standard Lua libraries, whereas provider plugins are a Corona convention. In particular, provider plugins are designed to be used in conjunction with specific Corona wrapper interfaces such as native.showPopup().
Plugins are hosted on our servers. You can incorporate a plugin by adding entries to the plugins
table of build.settings
. When added, the build server will integrate the plugin during the build phase.
For details on adding a specific plugin, please locate the appropriate plugin documentation.
Native plugins can easily be added to your iOS or Android project.
On iOS, plugins will be in the form of static library (.a
) files that need to be linked into your app executable.
On Android, plugins can come in the form of .so
(shared library) or .jar
files.
When you add a plugin via Corona Enterprise, be aware of the following:
If you want to create/submit a plugin for availability in the Corona Marketplace, you can use our App
project templates to simplify development of your plugin, as well as test it. After all, a plugin itself is not an executable and it must be run inside an actual application. The project templates can be located within the Corona Enterprise download package CoronaEnterprise.2016.2949.tgz
)
CoronaEnterprise/ProjectTemplates/App/
This folder has separate
ios
android
There's also a Corona
folder that sits alongside these folders which contains a classic Corona project (main.lua
). You can modify these files to test the Lua APIs that are offered by your plugin.
In the ios
folder, there are two Xcode projects:
App.xcodeproj
— This is the project that builds the .app
executable which runs on the device. It automatically builds the plugin as an implicit dependency.
Plugin.xcodeproj
— For plugin development, you should modify this project. It builds the plugin as a static library (.a
) and you can use this project directly if you want to share your plugin outside of the App
project.
Most often, you will want to create a universal binary for your plugin. In other words, you'd like to ship one static library that supports both the device and the
You can accomplish this via the lipo
tool. In the following example, we are creating a universal library for staticlibrary.a
:
lipo -create "/path/to/iphoneos/staticlibrary.a" "/path/to/iphoneos-simulator/staticlibrary.a" -output "/path/to/dst/staticlibrary.a"
In the android
folder, the contents include:
app
— This module builds the .apk
that installs on the device. The app
module automatically builds the plugin as an explicit dependency per this entry in the dependencies
block of the build.gradle
script for the app
module (compile project(':plugin')
).
plugin
— This module builds the plugin as a .jar
file, only including the Java files under plugin/src/main/java
in your project. You can use this project directly if you want to share your plugin outside of the App
project.
Plugins build upon Lua's module system, so they can come in threee different flavors:
If you've created a plugin and wish to submit it to the Corona Marketplace, please see the Plugin Submission Guide.
A Lua library plugin can be created using the CoronaLibrary class. Here's how a library called plugin.myLibrary
might look:
-- Create library local Library = require( "CoronaLibrary" ) local lib = Library:new{ name="plugin.myLibrary", publisherId="com.mycompany" } -- Create a function for the library lib.doSomething = function() print( "I did something!" ) end -- Return "lib" return lib
In addition to the plugin naming conventions discussed above, Corona expects plugins to follow some additional conventions that ensure Lua can locate these modules. In C, these conventions are just the standard Lua naming conventions for modules:
luaopen_
..
), it is replaced by an underscore (_
) in the name of the function, since C does not allow dots in symbol names.For example, the Lua library plugin.myLibrary
would have a Lua function called luaopen_plugin_myLibrary
:
static int doSomething( lua_State *L ) { lua_getglobal( L, "print" ); lua_pushstring( "I did something!" ); CoronaLuaDoCall( L, 1, 0 ); return 0; } // Export so it's visible to "require()" CORONA_EXPORT int luaopen_plugin_myLibrary( lua_State *L ) { static const luaL_Reg kFunctions[] = { { "doSomething", doSomething }, { NULL, NULL } }; // Create "myLibrary" // Lua version assumes version and revision default to 1 int result = CoronaLibraryNew( L, "myLibrary", "com.mycompany", 1, 1, kFunctions, NULL ); return result; }
If you write the module in Java, Corona has set up Lua to load Java code and to let that Java code define the Lua library via JNLua. Here, Lua looks for the Java class LuaLoader
and instantiates it.
Corona assumes the following conventions:
LuaLoader
class has a default (empty) constructor.LuaLoader
class must implement the JNLua interface com.naef.jnlua.JavaFunction
.LuaLoader
should be the same as the name passed to require()
.For example, the Lua library plugin.myLibrary
would be implemented by the plugin.myLibrary.LuaLoader
and that class would implement the invoke()
method of the com.naef.jnlua.JavaFunction
interface.
You can also create plugins in a hybrid fashion. For example, you can create the library via Lua code and then do further initialization in C.
Below is an example for creating the myLibrary
library from Lua and then adding additional functions on the native C side. Here, we assume kBuffer
stores the Lua bytecodes corresponding to myLibrary.lua
.
// The bytecodes for "myLibrary.lua" are contained in kBuffer static const unsigned char kBuffer[] = { ... } static int bufferLoader( lua_State *L ) { return luaL_loadbuffer( L, (const char*)kBuffer, sizeof( kBuffer ), "myLibrary" ); } static int somethingElse( lua_State *L ) { printf( "I'm doing something else!" ); return 0; } CORONA_EXPORT int luaopen_myLibrary( lua_State *L ) { lua_CFunction factory = Corona::Lua::Open< bufferLoader >; int result = CoronaLibraryNewWithFactory( L, factory, NULL, NULL ); if ( result ) { const luaL_Reg kFunctions[] = { { "somethingElse", somethingElse }, { NULL, NULL } }; luaL_register( L, NULL, kFunctions ); } return result; }