Android + Visual Studio + native C++ [updated: how to make it work, in a reply]

I just can’t get it to work. It throws “An error occurred that wasn’t supposed to. Contact support.”.

This was done with my initial attempt of “hey, let’s just link libraries, put them into apk, what could go wrong” and resulted in:

fmod    : System::create                           : Header version = 2.00.00. Current version = 2.00.00.
fmod    : Manager::init                            : maxchannels = 512 studioflags = 00000000 flags 00000304 extradriverdata 0x0.
fmod    : FMOD_JNI_GetEnv                          : JNI_OnLoad has not run, should have occurred during System.LoadLibrary.
fmod    : SystemI::init                            : Initialize version=20000 (101145), maxchannels=512, flags=0x00020304
fmod    : FMOD_OS_Init                             : Detected CPU family: 4, features: 0x7F, cores: 8.
fmod    : FMOD_JNI_GetEnv                          : JNI_OnLoad has not run, should have occurred during System.LoadLibrary.
fmod    : LiveUpdate::release                      :
fmod    : LiveUpdate::reset                        : Reset connection (reason Disconnected)

I can’t imagine a reason why a native library does require to be loaded through Java, but I am new to Android and I only use lowlevel stuff of FMOD, so I thought to not question that too much and instead, to dig into the issue.

Decided to just link the lib but remove it from apk and this is what I got:

AndroidRuntime: java.lang.UnsatisfiedLinkError: Unable to load native library "/data/app/com.teaForGodQuest-2/lib/arm64/libteaForGodQuest.so": dlopen failed: library "libfmodL.so" not found
AndroidRuntime:        at android.app.NativeActivity.onCreate(NativeActivity.java:182)
AndroidRuntime:        at android.app.Activity.performCreate(Activity.java:6713)
AndroidRuntime:        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1119)
AndroidRuntime:        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2632)
AndroidRuntime:        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2740)
AndroidRuntime:        at android.app.ActivityThread.-wrap12(ActivityThread.java)
AndroidRuntime:        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1477)
AndroidRuntime:        at android.os.Handler.dispatchMessage(Handler.java:102)
AndroidRuntime:        at android.os.Looper.loop(Looper.java:154)
AndroidRuntime:        at android.app.ActivityThread.main(ActivityThread.java:6144)
AndroidRuntime:        at java.lang.reflect.Method.invoke(Native Method)
AndroidRuntime:        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
AndroidRuntime:        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)

So actually it tries to load the library through the java but it is beyond my reach, hidden somewhere in the Visual Studio project. And the app doesn’t run this way.

I decided to get it back and then to call java code directly from C++ through jni:

if (auto systemClass = env->FindClass("java/lang/System"))
{
	if (auto loadLibraryFunc = env->GetStaticMethodID(systemClass, "loadLibrary", "(Ljava/lang/String;)V"))
	{
		auto libString = env->NewStringUTF("fmodL");
		env->CallStaticVoidMethod(systemClass, loadLibraryFunc, libString);
	}
}

Which fails (because it is neither in /system nor /system/vendor). Tried “System.load” but it failed too, for other reason though (null reference to ClassLoader).

I also have fmod.jar added to packaging but it really doesn’t matter if it’s there or not. I know that I managed to include that in the apk but now I can’t, I can’t even tell why.

What I still need to try is to compile java code with build.xml and include it in the apk and run it. So far I managed to compile anything but not with android.app.

Help!

Got it working, it’s quite easy.

Assumptions: you’ve got only c++ code in a project created in Visual Studio (VS2019 in my case, VS2017 gives the same project) basing on “Native-Activity application (Android)”. You haven’t changed AndroidManifest.xml nor build.xml (maybe only to get assets automatically).

I will be using MyGame in code etc

  1. in packaging project (MyGame.Packaging) create “libs” folder. Add fmod.jar there. Open its properties and choose “Copy to output directory” to be “Copy always”.

  2. in the same project create “src” folder. Add a new file in it, java code, MyGameActivity.java. Its content:

    package com.myPackage;
    
    import android.app.NativeActivity;
    
    public class MyGameActivity extends android.app.NativeActivity
    {
    	static
    	{
    		System.loadLibrary("fmod");
    		System.loadLibrary("fmodstudio");
    	}
    }
    

Go to its properties and set to always copy it (as in 1)

  1. Open AndroidManifest and set hasCode to true:
    <application android:label="@string/app_name" android:hasCode="true">
    and change android:name for activity to your class name (full path):
    <activity android:name="com.myPackage.MyGameActivity"

And that’s it.

You have to use mentioned folder names as build.xml relies on them. If you choose to use different names, you have to either modify build.xml (the original one in SDK folder) or provide dir variables. Assuming its you only java code, keep the names the way they are.

What should happen: build.xml will notice that hasCode is set to true, will then look for .java files in src folder and will compile them creating .class files. After that, it will get both .class file and fmod.jar (from libs folder) and turn it into classes.dex that will end up in apk.

Because android:name is changed and is based on android.app.NativeActivity two things happen:

  1. Both System.loadLibrary calls will get executed, this way fmod will be properly initialised and when calling “initialize” method you won’t get error and info in android log about missing call to JNI_OnLoad .
  2. Your app will run just as it was running before.

How to check if apk was prepared properly. Open apk file (change its extension to .zip and open is as zip) and unpack classes.dex. View it in any text viewer and look for “fmod” and “MyGame”. Both those phrases should be found.

It’s really easy but without any knowledge of how android stuff is built with build.xml you don’t know where to start (I did it the other way around, calling java from C++, then compiling java by hand, creating jars and trying to get them into apk, when I learned that build.xml can do all of that for me).

1 Like