Android: Re-structuring of JUCE’s low-level Android code

With commit 9a4548a (on develop), we have completely re-structured JUCE’s low-level Android code. JUCE’s Android support is now much more flexible, allowing you to choose which parts of JUCE you want to use for your app’s code/GUI and which parts you would like to implement natively.

Before this change, JUCE’s android support was substantially different compared to all other JUCE platforms. On all other JUCE platforms, it was always possible to only use just “a bit of” JUCE and write the rest of your app/GUI with native code. For example, on macOS/Windows/Linux/iOS, it was always possible to write a native app and only use JUCE for the audio engine part of your app. This was not possible on Android as JUCE would need to provide your app’s main Activity making it impossible to use JUCE without JUCE also providing all of the GUI.

This restriction had a big impact. For example, It was not possible to create JUCE android projects which did not use the juce_gui_basics module. It also wasn’t possible to create Android libraries with JUCE, targeting apps which did not necessarily also use JUCE. And finally, the “nativeWindowToAttachTo” parameter of Component::addToDesktop was ignored on Android, making it impossible to embed JUCE components in a native view container.

To alleviate the above restrictions, most of the low-level native Android code needed to be re-written. Although no public JUCE APIs (any APIs listed on have changed, this commit may introduce breaking changes if you used any of JUCE’s internal JNI helper macros (modules/juce_core/juce_android_JNIHelpers.h) or invoked native android code directly. See more about this in this forum post.

If you want to know more about how you can now mix & match native and JUCE code/GUI elements, have a look at this post here.


Woop! Congrats guys, its finally on develop :metal:

1 Like

Hi @fabian - do I need to do anything? since pulling the latest my Android apps don’t start and I just get a blank screen. thx

Oh dear! I thought it was too good to be true to not get any bug reports.

So there is nothing special that you need to do other than the usual Projucer rebuild and re-saving the project. For example, we did not need to change any of the sample codes (for example DemoRunner or Hello World), so the new Android backend “should” be backward compatible.

I’m happy to look at your code (full or stripped-down). If that’s not possible then have a look at your GUI setup code. Do you do anything different than the HelloWorld or DemoRunner app? Do the android logs give you any hint.

ok, let me first rebuild everything from scratch just in case I’ve missed a step.

Hi, so done a rebuild of Projucer with latest develop, rebuilt everything and just getting a blank screen. Demorunner starts up fine. Don’t think I’m doing anything different from default base code apart from building with:


I’ll check if anything has changed in the StandaloneFilterApp implementation as I obv have to provide my own.

So if I start up the demorunner I get the following:
11-28 18:55:09.745 8599-8599/com.juce.demorunner I/JUCE: JUCE v5.4.1
11-28 18:55:10.128 8599-8599/com.juce.demorunner I/JUCE: Audio device - min buffers: 8464, 5376; 44100 Hz; input chans: 2
11-28 18:55:10.199 8599-8599/com.juce.demorunner I/JUCE: OpenSL: numInputChannels = 1, numOutputChannels = 2, nativeBufferSize = 661, nativeSampleRate = 44100, actualBufferSize = 4627, audioBuffersToEnqueue = 1, sampleRate = 44100, supportsFloatingPoint = true

which makes sense. If I start my own app I just get a blank screen and no output in Logcat. What would it be useful for you to see from my side?

Can we see the whole thing from startup to where it settles on a black screen then exit/destroy?

I am curious what else is in the os logs.

This just shows how many code for Android on the bleeding edge. :slight_smile:


ok, so this is where I’m at:

  1. I’ve removed JUCE_USE_CUSTOM_PLUGIN_STANDALONE_APP and replaced it with JUCE_STANDALONE_FILTER_WINDOW_USE_KIOSK_MODE=0 as this is what I was using my own standalone filter for on Android. Kiosk mode has never worked for me and causes random screen resizes and glitches.
  2. On the emulator, the display totalArea and userArea are now different (as documented in the other thread). However, on my real device these are still the same.
  3. On the emulator the user height isn’t being reported as correct - I’m having to make an adjustment of half of the height difference between userArea height and totalArea height in order for it to fit the screen bounds correctly.

I’ll continue to explore further tomorrow.

@fabian I am in the bleeding edge Android camp here as well, so there will be at least another. :wink:

Hi, so this is what my Zen M 10 returns:


This info is the same for kiosk or not kiosk mode so in non-kiosk mode the graphics are written off the bottom of the screen, i.e. the 768 is correct for the whole screen res, but not user area.


1 Like

So I can’t reproduce this issue exactly on the hardware I have, but getting the actual usable window area in Android is insanely hard (I have no idea why, just search stackoverflow to find multiple competing suggestions).

Can you set a breakpoint in juce_android_Windowing.cpp:1381? The only reliable way to get the correct usable area that I found was by listening to layout changes. When your app starts you should get several layout change callbacks. The last one that comes in will have the correct geometry (at least on my physical machines). It could be maybe that your setKioskMode method is issued too early before the latest layout change callback occurred - although JUCE should normally update the kiosk mode size when it sees that the screen size has changed.

Hi, I’m having other problems when in Kiosk mode - sometimes the app decides that it’s going to come out of kiosk mode and put the status bar back at the top. Obv then the bottom of the screen is not visible.

Is anything other than:


in the preprocessor defs required? Is there anything I can be doing code-wise that would cause kiosk mode to be exited?