Has anyone here worked with native android plugin for Unity?
Was wondering if there was a way to get UnityPlayer Activity and Context from JNI_OnLoad on the native side, instead of passing from Unity C# as following:
var unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
var activity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
var context = activity.Call<AndroidJavaObject>("getApplicationContext");
My equivalent conversion on native side looks like:
However, at runtime getting: java.lang.NoSuchFieldError: no type “Landroid/app/Activity” found and so no field “currentActivity” could be found in class “Lcom/unity3d/player/UnityPlayer;” or its superclasses
Aren’t signatures for class types supposed to include a semicolon at the end?
Like: Landroid/app/Activity**;**
Same when searching for getApplicationContext method.
The bigger issue that I faced was getting methodID for “getApplicationContext” from the activity object. And indeed upon scouring through UnityPlayerActivity.java and UnityPlayer.class I couldn’t find the symbol via javap util. So I ended up getting this from ActivityThread class (probably what Unity does internally as well). Let me know if there’s better way for this.
@nfynt-zap were you able to successfully use JNI_OnLoad ? If so, would you mind showing a code snippet? And are you doing it straight from a c++ file in your unity project or building a library first then adding that to your unity project?
I keep getting the error “multiple definition of `JNI_OnLoad’” when building.
It seems it is also used in Initialize.cpp, but that seems to be part of the Unity source.
There is JNI_OnLoad in Unity code, so if you drop c++ file in the project and have stripping enabled, you get a clash.
Maybe disabling stripping would help, but the recommended way is to prelink your library.
I was able to get the AAssetManager without needing any c++. Hacked together some stuff and came up with this. It can be called from a native plugin. This circumvents the need for a custom activity or JNI_OnLoad. Maybe it is useful for someone in the future :
static IntPtr SetupAndroidJNICallback()
{
//starting point here : https://stackoverflow.com/questions/58980171/using-aassetmanager-fromjava-within-plugin-not-directly-called-from-java-vm-cal?rq=1
AndroidJNI.AttachCurrentThread();
IntPtr unity_player = AndroidJNI.FindClass("com/unity3d/player/UnityPlayer"); //TODO : this might need to be changed if the unity project uses a custom activity
IntPtr static_activity_id = AndroidJNI.GetStaticFieldID(unity_player, "currentActivity", "Landroid/app/Activity;");
IntPtr unity_activity = AndroidJNI.GetStaticObjectField(unity_player, static_activity_id);
IntPtr get_assets_id = AndroidJNI.GetMethodID(AndroidJNI.GetObjectClass(unity_activity), "getAssets", "()Landroid/content/res/AssetManager;");
IntPtr java_asset_manager = AndroidJNI.CallObjectMethod(unity_activity, get_assets_id, null);
Debug.Log("java_asset_manager : " + java_asset_manager);
IntPtr g_JavaAssetManager = AndroidJNI.NewGlobalRef(java_asset_manager); //HAS TO BE GARBAGE COLLECTED using Delete if desired
//hacked together from android sources found here :
//retrieved from : https://android.googlesource.com/platform/frameworks/base.git/+/android-4.2.2_r1/core/jni/android_util_AssetManager.cpp
//AND here : https://android.googlesource.com/platform/frameworks/base/+/master/native/android/asset_manager.cpp
//AND UPDATED VERSION HERE : https://github.com/aosp-mirror/platform_frameworks_base/blob/master/core/jni/android_util_AssetManager.cpp
IntPtr assetManager = AndroidJNI.FindClass("android/content/res/AssetManager");
IntPtr gAssetManagerOffsetsMObject = AndroidJNI.GetFieldID(assetManager, "mObject", "J");
IntPtr am = (IntPtr)AndroidJNI.GetLongField(g_JavaAssetManager, gAssetManagerOffsetsMObject);
Debug.Log("am : " + am); //make sure it isn't 0 (NULL), if so check for NULL in earlier variables
return am;
}
It can then be used directly with methods like AAssetManager_open.