Android app undefined reference linker error

I’m trying to build an android GUI App but a single line is causing a linker error

if (chooser.browseForFileToOpen()) {

producing this error

E:/___SOURCE_TREE/GHHHHH/threaded async updater demo/threadedAsync/Source/MainComponent.cpp:70: error: undefined reference to ‘juce::FileChooser::browseForFileToOpen(juce::FilePreviewComponent*)’
clang++: error: linker command

does anyone have any suggestions, please? This is working on Win, Mac, IOS

I’m on the develop branch at the tip as of today, Android Studio is 4.1.1

here’s the full error,

Build command failed.
Error while executing process F:\Android\android-sdk\cmake\3.10.2.4988404\bin\ninja.exe with arguments {-C E:___SOURCE_TREE\GHHHHH\threaded async updater demo\threadedAsync\Builds\Android\app.cxx\cmake\debug_Debug\x86 juce_jni}
ninja: Entering directory `E:__SOURCE_TREE\GHHHHH\threaded async updater demo\threadedAsync\Builds\Android\app.cxx\cmake\debug_Debug\x86’
[1/2] Building CXX object CMakeFiles/juce_jni.dir/E
/__SOURCE_TREE/GHHHHH/threaded_async_updater_demo/threadedAsync/Source/MainComponent.cpp.o
[2/2] Linking CXX shared library …\build\intermediates\cmake\debug_Debug\obj\x86\libjuce_jni.so
FAILED: …/…/…/…/build/intermediates/cmake/debug_Debug/obj/x86/libjuce_jni.so
cmd.exe /C "cd . && F:\Android\android-sdk\ndk\21.1.6352462\toolchains\llvm\prebuilt\windows-x86_64\bin\clang++.exe --target=i686-none-linux-android28 --gcc-toolchain=F:/Android/android-sdk/ndk/21.1.6352462/toolchains/llvm/prebuilt/windows-x86_64 --sysroot=F:/Android/android-sdk/ndk/21.1.6352462/toolchains/llvm/prebuilt/windows-x86_64/sysroot -fPIC -g -DANDROID -fdata-sections -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -D_FORTIFY_SOURCE=2 -Wformat -Werror=format-security -fexceptions -frtti -O0 -fno-limit-debug-info -O0 -Wl,–exclude-libs,libgcc.a -Wl,–exclude-libs,libgcc_real.a -Wl,–exclude-libs,libatomic.a -static-libstdc++ -Wl,–build-id -Wl,–fatal-warnings -Wl,–no-undefined -Qunused-arguments -shared -Wl,-soname,libjuce_jni.so -o …\build\intermediates\cmake\debug_Debug\obj\x86\libjuce_jni.so CMakeFiles/juce_jni.dir/E
/__SOURCE_TREE/GHHHHH/threaded_async_updater_demo/threadedAsync/Source/Main.cpp.o CMakeFiles/juce_jni.dir/E/__SOURCE_TREE/GHHHHH/threaded_async_updater_demo/threadedAsync/Source/MainComponent.cpp.o CMakeFiles/juce_jni.dir/0ef0b871368e359f3dcefd3c2e306cf3/threadedAsync/JuceLibraryCode/include_juce_audio_basics.cpp.o CMakeFiles/juce_jni.dir/0ef0b871368e359f3dcefd3c2e306cf3/threadedAsync/JuceLibraryCode/include_juce_audio_devices.cpp.o CMakeFiles/juce_jni.dir/0ef0b871368e359f3dcefd3c2e306cf3/threadedAsync/JuceLibraryCode/include_juce_audio_formats.cpp.o CMakeFiles/juce_jni.dir/0ef0b871368e359f3dcefd3c2e306cf3/threadedAsync/JuceLibraryCode/include_juce_audio_processors.cpp.o CMakeFiles/juce_jni.dir/E/__SOURCE_TREE/GHHHHH/threaded_async_updater_demo/threadedAsync/JuceLibraryCode/include_juce_audio_utils.cpp.o CMakeFiles/juce_jni.dir/E/__SOURCE_TREE/GHHHHH/threaded_async_updater_demo/threadedAsync/JuceLibraryCode/include_juce_core.cpp.o CMakeFiles/juce_jni.dir/0ef0b871368e359f3dcefd3c2e306cf3/threadedAsync/JuceLibraryCode/include_juce_data_structures.cpp.o CMakeFiles/juce_jni.dir/E/__SOURCE_TREE/GHHHHH/threaded_async_updater_demo/threadedAsync/JuceLibraryCode/include_juce_events.cpp.o CMakeFiles/juce_jni.dir/E/__SOURCE_TREE/GHHHHH/threaded_async_updater_demo/threadedAsync/JuceLibraryCode/include_juce_graphics.cpp.o CMakeFiles/juce_jni.dir/E/__SOURCE_TREE/GHHHHH/threaded_async_updater_demo/threadedAsync/JuceLibraryCode/include_juce_gui_basics.cpp.o CMakeFiles/juce_jni.dir/E/___SOURCE_TREE/GHHHHH/threaded_async_updater_demo/threadedAsync/JuceLibraryCode/include_juce_gui_extra.cpp.o -llog -landroid -lGLESv3 -lEGL libcpufeatures.a oboe/liboboe.a -llog -lOpenSLES -latomic -lm && cd ."
E:/___SOURCE_TREE/GHHHHH/threaded async updater demo/threadedAsync/Source/MainComponent.cpp:70: error: undefined reference to ‘juce::FileChooser::browseForFileToOpen(juce::FilePreviewComponent*)’
clang++: error: linker command failed with exit code 1 (use -v to see invocation)
ninja: build stopped: subcommand failed.

That function depends on modal loops, which are not supported on Android.

Could you try launching the file chooser with FileChooser::launchAsync instead?

Thank you, for this.

Can i just check that I’m getting the approach right in the callback

chooser.launchAsync(juce::FileBrowserComponent::openMode | juce::FileBrowserComponent::canSelectFiles,
                    [this] (const juce::FileChooser& fileChooser)
                    {
                     auto file = fileChooser.getResult();

                        if (file.getSize()>0)
                        {
                            doSomethingWithTheFile(file);
                        }
                    }
        );

This does open the file chooser, but the callback never seems to be called.

That looks alright to me. Does chooser definitely outlive the dialog box? It should probably be a class member rather than a local/stack variable.

Thanks, chooser was a stack variable.

Also noting here for any future readers in search of a similar resolution… it’s not possible to get the file in this way, use .getURLresult() instead and use the input stream.

just picking up on this again… I never got it to work in the end

the audioFormatReader is always NULL.

any thoughts?

chooser->launchAsync(juce::FileBrowserComponent::openMode | juce::FileBrowserComponent::canSelectFiles,
	                    [this] (const juce::FileChooser& fileChooser)
                        {
	                        auto url = fileChooser.getURLResult();

                            fileNameLabel.setText(url.getFileName(), juce::NotificationType::dontSendNotification); // shows the right file name
                            audioFormatReader = formatManager.createReaderFor(url.createInputStream(false));
                            fileLoaded = createTransport(audioFormatReader);
};

I haven’t tried your demo exactly, but I just tried running the DemoRunner in an Android emulator. The ConvolutionDemo has a “load file” button which launches an async FileChooser. When the FileChooser exits, the chosen URL is loaded using AudioFormatManager::createReaderFor, much like in your snippet. As far as I can tell, the ConvolutionDemo successfully loads a file (the file’s waveform is displayed).

Did you remember to call registerBasicFormats on your AudioFormatManager? Also, is the file that you’re loading definitely using a supported format?

If that doesn’t help, I’d recommend trying out the ConvolutionDemo yourself. Assuming the demo works on your device/simulator, then maybe you can start looking for differences between the working demo, and the broken app.