How to use JUCE on Android with a native GUI and NDK


#1

Hello all,
We have an iOS app that uses Juce with native widgets for the GUI. (See http://birdgenie.com.)
How does one do this on Android, i.e., build a static library from JUCE and app-specific C++ that a native Java GUI can access?
I’d love some advice or a contractor who can set this up for our build…

stp in SB/CA


#2

Hi,

Cool app! You can add a new target for Android in Projucer, which will generate Android Studio project for you.

All the main communication between Java and C++ is done for you already in JUCE. If you then need to do additional Java calls (like your native UI), you need Java Native Interface: https://www3.ntu.edu.sg/home/ehchua/programming/java/JavaNativeInterface.html

Using JNI you can call native C++ functions from Java and from C++ you can call Java too. The skeleton for Java is in JuceAppActivity.java that will be copied to your project and named after your project name. Some of the content of the file is generated during saving, which is why the file gets overwritten every time you save a project. Hence you will want to add all the code (including creation of Java native views) from C++. If you needed to add custom stuff to your manifest (~plist sort of equivalent on Android), Projucer allows you to customise any content of the manifest, that will override any default value. You will find quite a few Android specific settings in Projucer. You should be able to avoid the need of adding any Java code in majority of the cases.

While it is not officially exposed, in JUCE land there is AndroidSystem android global variable and android.activity member is the Activity from Java land you can work with. So if any of your Java classes requires Context, you can pass android.activity.get(). Lastly, JUCE has a very handy macro JNI_CLASS_MEMBERS which is used to declare a Java class that you will call in C++. This allows to avoid all sort of tedious code dealing with finding method and field IDs (more on that in JNI tutorial above).

I don’t know what your strategy with embedding native views is, one way to do it is to use JUCE’s AndroidViewComponent (on iOS it is UIViewComponent). You should be able to find examples on how we talk to Java in lots of places in JUCE while WebBrowserComponent implementations will show you how to use AndroidViewComponent and UIViewComponent.

I hope that helps.


#3

Unfortunately, JUCE currently takes control of the Android MainActivity, which is not ideal if you want to have an Android native UI on top of a JUCE app. I have a branch where I’ve separated things out but its for JUCE 4.2 and needs updating to 5. Creating the “bridge” outside of the MainActivity was done mainly for compatibility with React Native, but is also helpful for native Android+JUCE apps that have multiple activities.

The approach of compiling the C++ code into a static library may be simpler, as long as you don’t need any JUCE GUI components.


#4

Well my app is still using JUCE 3, so that’s not a problem…


#5

Do you have any advice on compiling the C++ code into a static library?


#6

Sorry not had experience with that myself… I think @robclouth has done something along those lines.

If you use my JUCE branch you should be able to achieve what you want without compiling as a static lib.


#7

Where’s your branch available??


#8

Are you talking about the ReactDrum fork?


#9

Actually you can use the master branch of my JUCE fork https://github.com/adamski/JUCE/tree/master

You will need to recompile Projucer, and re-save the project to work with it. There has been an update to Projucer since that means it does not rely on experimental-gradle any more. This will potentially save a lot of headache but I’ve not had time to merge it in yet.

ReactDrum was a demo project to show React Native and JUCE working together. If you look at the Android build folder, you can see how to use the JuceBridge class that I added, which allows you to interact with JUCE outside of the MainActivity, i.e. anywhere from your native Android app.

The MainActivity that creates the JuceBridge instance:

and my Main.cpp that contains the JNI methods:


#11

Thanks a million!