We picked up a new client project recently. Without going into too much detail, in a nutshell the brief is to develop a mobile app that incorporates a measurement tool, and will eventually need releasing on both Android and iOS. Weighing up the pros and cons of building such an app in the various cross-platform frameworks available, I opted for Corona SDK. I love Corona - it's built around the Lua programming language which I find really intuitive and quick to develop in, and although it's prodominantly a game programming kit, there's no reason why general apps can't be built with it too.
For the measurement tool we need users to be able to see what they're pointing their phone at, and to do this we want to show a camera preview in the background. Corona has a really nifty feature for this - you can simply create a standard rectangular display object and fill it with the camera preview. I'd planned this part of the app around this ability, but it turns out this only works on iOS, and we need Android support first...
The Android API does offer camera device access at this level, so with native Android code (Java) it's possible to receive a camera preview image to a surface object. One really cool feature of Corona is the ability to bridge between Lua code and native device code, by creating native plugins. On Android, a native plugin is a Java library that you load in to your Corona project during the compile, opening up its methods to your Lua code. As far as I understand it, when you build a Corona project, Lua is compiled into native Java when building for Android, or native C when building for iOS, so native plugins are simply pre-compiled Java or C classes that get added in during this phase, which is pretty logical really.
Since Corona doesn't offer a native camera preview method for Android, I decided to learn native plugin development. This proved to be a difficult process as there aren't any concise tutorials available, and the documentation and forum posts I managed to find were exceptionally brief and/or out of date, making references to things like Corona Native which is a tool for Mac users only, or Corona Enterprise which is now discontinued. Put simply, I struggled to figure out a lot of the steps needed or how to work with Android Studio, despite the fact that creating a native plugin is actually pretty easy.
So, if like me, you're trying to figure out how to build a native Android Java plugin for Corona SDK, here's a proper, concise tutorial concatenating the various steps I found throughout the documentation, my own findings, and some much appreciated guidance from Corona staff member, Vlad. This tutorial assumes that you're using Windows and building for Android. The steps for Mac users building for iOS differ.
new start(),
new stop(),
new status()
package plugin.myFirstPlugin;
import com.naef.jnlua.LuaState;
import com.naef.jnlua.NamedJavaFunction;
import com.ansca.corona.CoronaLua;
import com.ansca.corona.CoronaRuntime;
import com.ansca.corona.CoronaRuntimeListener;
import com.ansca.corona.CoronaRuntimeTask;
import com.ansca.corona.CoronaRuntimeTaskDispatcher;
import com.ansca.corona.storage.FileContentProvider;
import com.ansca.corona.storage.FileServices;
public class start implements com.naef.jnlua.NamedJavaFunction {
// This reports a class name back to Lua during the initiation phase.
@Override
public String getName() {
return "start";
}
// This is what actually gets invoked by the Lua call
@Override
public int invoke(final LuaState luaState) {
shared.status = "running";
return 1;
}
}
package plugin.myFirstPlugin;
import com.naef.jnlua.LuaState;
import com.naef.jnlua.NamedJavaFunction;
import com.ansca.corona.CoronaLua;
import com.ansca.corona.CoronaRuntime;
import com.ansca.corona.CoronaRuntimeListener;
import com.ansca.corona.CoronaRuntimeTask;
import com.ansca.corona.CoronaRuntimeTaskDispatcher;
import com.ansca.corona.storage.FileContentProvider;
import com.ansca.corona.storage.FileServices;
public class stop implements com.naef.jnlua.NamedJavaFunction {
// This reports a class name back to Lua during the initiation phase.
@Override
public String getName() {
return "stop";
}
// This is what actually gets invoked by the Lua call
@Override
public int invoke(final LuaState luaState) {
shared.status = "waiting";
return 1;
}
}
package plugin.myFirstPlugin;
import com.naef.jnlua.LuaState;
import com.naef.jnlua.NamedJavaFunction;
import com.ansca.corona.CoronaLua;
import com.ansca.corona.CoronaRuntime;
import com.ansca.corona.CoronaRuntimeListener;
import com.ansca.corona.CoronaRuntimeTask;
import com.ansca.corona.CoronaRuntimeTaskDispatcher;
import com.ansca.corona.storage.FileContentProvider;
import com.ansca.corona.storage.FileServices;
public class status implements com.naef.jnlua.NamedJavaFunction {
// This reports a class name back to Lua during the initiation phase.
@Override
public String getName() {
return "status";
}
// This is what actually gets invoked by the Lua call
@Override
public int invoke(final LuaState luaState) {
luaState.pushString(shared.status);
return 1;
}
}
package plugin.myFirstPlugin;
public class shared {
// global variables, basically
public static String status = "waiting";
}
local library = require "plugin.myFirstPlugin"
print("Status is currently: " .. library.status())
print("Calling our start() function!")
library.start()
print("Status is currently: " .. library.status())
print("Calling our stop() function!")
library.stop()
print("Status is currently: " .. library.status())
print("Done!")
That's it, you're done!
Blog posts written by former QWeb employees are not necessarily an accurate indication of the current opinions of QWeb Ltd and the information provided in tutorials might be biased or subjective, or might become out of date.
Leave a comment
Your email address is used to notify you of new comments to this thread, and also to pull your Gravatar image. Your name, email address, and message are stored as encrypted text and you won't be added to any mailing list and your details won't be shared with any third party.