I need to use JNI to start an NSD service on mobile (For NDI android plugin).
I can package my app but it crashes when I call JNI because it can not find MethodID.
Other C++ codes (for example NSI SDK) works because I can use it with NDI HX Camera’s NSD service without a problem.
My Java code in UPL.xml is this.
<gameActivityImportAdditions>
<if condition="bCpuArchSupported">
<insert>
import android.os.IBinder;
import android.app.Service;
import android.net.nsd.NsdManager;
import android.net.nsd.NsdServiceInfo;
</insert>
</if>
</gameActivityImportAdditions>
<gameActivityClassAdditions>
<if condition="bCpuArchSupported">
<insert>
public NsdManager nsdManager;
public NsdServiceInfo nsdServiceInfo;
NsdManager.RegistrationListener listener;
public void startNsdService(int Port, String ServiceName) {
nsdManager = (NsdManager)Get().getApplicationContext().getSystemService(Context.NSD_SERVICE);
nsdServiceInfo = new NsdServiceInfo();
nsdServiceInfo.setServiceName(ServiceName);
nsdServiceInfo.setServiceType("_ndi._tcp.");
nsdServiceInfo.setPort(Port);
nsdManager.registerService(nsdServiceInfo, NsdManager.PROTOCOL_DNS_SD, new NsdManager.RegistrationListener() {
@Override
public void onRegistrationFailed(NsdServiceInfo nsdServiceInfo, int i) {}
@Override
public void onUnregistrationFailed(NsdServiceInfo nsdServiceInfo, int i) {}
@Override
public void onServiceRegistered(NsdServiceInfo nsdServiceInfo) {}
@Override
public void onServiceUnregistered(NsdServiceInfo nsdServiceInfo) {}
});
}
</insert>
</if>
</gameActivityClassAdditions>
<proguardAdditions>
<if condition="bCpuArchSupported">
<insert>
<![CDATA[
-keepattributes Signature,MethodParameters,InnerClasses
-dontskipnonpubliclibraryclassmembers
-keepclassmembers class com.epicgames.unreal.GameActivity
]]>
</insert>
</if>
</proguardAdditions>
In order to call it I use this C++ code.
JNIEnv* env = FAndroidApplication::GetJavaEnv(true);
if (FJavaWrapper::GameActivityClassID == nullptr)
{
OutCode = "Unable to get GameActivity class.";
return false;
}
jmethodID MethodID = env->GetMethodID(FJavaWrapper::GameActivityClassID, "startNsdService", "(ILjava/lang/String;)V");
if (MethodID == nullptr)
{
OutCode = "Unable to find \"startNsdService\" Java method in GameActivity class. Look at NDI_UPL_Android.xml";
return false;
}
auto ServiceName = env->NewStringUTF(TCHAR_TO_UTF8(*In_Name_Stream));
FJavaWrapper::CallVoidMethod(env, FJavaWrapper::GameActivityClassID, MethodID, In_Port, *ServiceName);
Also tried these
- I added UPL.xml and PrivateDependencyModuleNames.Add(“Launch”); to my build.cs for Android platform.
- I tried FJavaWrapper::GetMethod()
- I got method’s signature from “javac -h” and “javap -s”.
- I changed method’s arguments and signature to “()V”
- I tried to delete proguard section from UPL.xml
- I tried to add my java code in a class but FindClass functions didn’t find that class.
There are samples for additions without class.
https://github.com/EpicGames/UnrealEngine/blob/46544fa5e0aa9e6740c19b44b0628b72e7bbd5ce/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/OnlineSubsystemGoogle_UPL.xml - I tried Shipping Build
My log’s last section.
[2023.02.08-22.33.41:076][427]LogBlueprintUserMessages: [UI_Capture_Devices_C_2147482447] Unable to find "startNsdService" Java method in GameActivity class. Look at NDI_UPL_Android.xml