Infinite Livecode: Java progress

by Ali Lloyd on November 9, 2016 4 comments

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:

screen-shot-2016-10-10-at-10-58-59

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.

Ali LloydInfinite Livecode: Java progress

Related Posts

Take a look at these posts

4 comments

Join the conversation
  • Quartam - Jan Schenkel - November 9, 2016 reply

    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 reply

    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 reply

    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 reply

    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

Join the conversation

*