Current progress
Since the Infinite LiveCode project was funded we have been hard at work with all the unglamorous but important preparation needed to make it possible, including refactoring the LiveCode Builder virtual machine. We have also made significant progress on the Java foreign function interface (FFI) that sits between the LiveCode Builder world and the Java world. Once the remaining few pull requests are merged, it will possible to interface with loaded Java classes, in particular the Android API – enabling you to instantly add vast swathes of additional functionality to your Android apps.
The main ingredient for creating a successful interface between Java and LiveCode Builder is an interface definition file. This is essentially just a description of what methods, variables, constants and constructors are needed from a particular Java class. A parsing tool has been written which takes such interface definition files, checks them, and outputs an LCB file which manages all the interactions with features of the Java class.
For example, if we want the Battery Manager’s current charging / discharging state, the following interface definition suffices:
foreign package android.os named uk.co.alilloyd.androidbattery class BatteryManager constructor BatteryManager() constant ACTION_CHARGING is "android.os.action.CHARGING" constant ACTION_DISCHARGING is "android.os.action.DISCHARGING" method isCharging() returns boolean end class end package
Running the tool on the above definition outputs an LCB file which can be used to access the class and its methods.
constructor BatteryManager() -> BatteryManager_BatterManager() returns JObject
method isCharging() returns boolean -> BatteryManager_isCharging(in pBM as JObject) returns Boolean
constant ACTION_CHARGING is "android.os.action.CHARGING" constant ACTION_DISCHARGING is "android.os.action.DISCHARGING" -> BatteryManager_ACTION_CHARGING BatteryManager_ACTION_DISCHARGING
Using the generated LCB as a support module, it is very easy to write a charging/discharging battery widget that looks a bit like this:
Next steps
The next steps are to make the whole experience a little more user-friendly. Whilst it will always be possible to do the above once everything is merged, we would obviously like to make it as simple as we can for anyone to use. The two main ways we plan to do this is are:
- To provide some in-IDE support, so that you don’t have to fiddle around with command-line tools (if you don’t want to)
- To use Java’s reflection API to automate the generation of the interface definition files
Java provides a means of examining classes via its reflection API, which means in principle it could be wrapped in LCB and used to make a tool which extracts the interface definition from a loaded Java class. This would mean that you wouldn’t have to write definition files at all – all you would have to do is provide the name of the class you want access to in LCB.
As well as making those improvements to the ‘flow’, we will also be working on the Android portion of the stretch goals – the native sound recording library and the native field widget.
Postscript
It will be possible (although we don’t necessarily recommend it!) to use the Java FFI directly. The output from the above BatteryManager example should give you an idea of how it’s done:
module uk.co.alilloyd.androidbattery use com.livecode.foreign use com.livecode.java foreign handler _JNI_BatteryManager_isCharging(in pObj as JObject) returns CBool binds to "java:android.os.BatteryManager>isCharging()Z" public constant ACTION_CHARGING is "android.os.action.CHARGING" public constant ACTION_DISCHARGING is "android.os.action.DISCHARGING" public handler BatteryManager_isCharging(in pObj as JObject) returns Boolean variable tJNIResult as Boolean unsafe put _JNI_BatteryManager_isCharging(pObj) into tJNIResult end unsafe return tJNIResult end handler end module
The ‘binding string’ is the key to getting the appropriate call through the JNI to take place. In “java:android.os.BatteryManager>isCharging()Z”, android.os.BatteryManager
is the fully qualified Java class name, isCharging
is the method name and ()Z
is the signature. The signature is exactly the same as that which would be used in the JNI directly – as in the Java VM Type Signatures table here.
4 comments
Join the conversationQuartam - Jan Schenkel - November 9, 2016
Very exciting news, indeed! Any plans to extend this from Android to the desktop platforms?
I worked on an external years ago to write externals using java code, and it worked pretty well until you tried to bring up user interface elements and then event handling broke down – so threading is definitely a challenge.
The code is on github if anyone wants to take it for a spin on Windows or macOS.
Keep up the great work!
Ali Lloyd - November 9, 2016
Hi Jan,
Yes, ultimately we will have the Java – LCB bridge on desktop platforms too – currently it is working on Mac and Linux although we need to do a little tweaking to get the JVM to load dynamically on Mac.
Torsten - October 21, 2017
Hi Ali,
I would like to get the battery status of my MacBook in order to be warned if it is below some value. Is there a way to do this with LiveCode?
Ali Lloyd - October 23, 2017
Hi Torsten,
The easiest way is probably just to extract the info from `shell(“pmset -g batt”)`, but there is an IOKit API for power sources should you wish to do anything more sophisticated, which could certainly be accessed via Objective-C FFI:
https://developer.apple.com/documentation/iokit/iopowersources.h?language=objc