AndroidJavaObject and Null References

At the moment I am trying to hook in a dynamically-generated IntentFilter object against a ‘sticky’ or, in some cases, ignorable broadcast. As such, I need to pass in a Null BroadcastReceiver object into the first parameter of Context.registerReceiver. This is the expected usage of the method.

The problem is I can’t determine how to create such a thing.

The AndroidJavaObject binding isn’t intelligent enough to turn a C# null into a Java null of the correct type. So, my bet was to cast the Java null reference to the correct type. The problem with that is that 0xFFFFFFFF is interpreted as a weak reference by the JNI and exhibits an exception.

So, I tried building the correct object via first creating a new AndroidJavaObject of type java.lang.Object, which appears to default to the Java null object reference, then casting it with the java.lang.Class static method fromName. But that generates a null reference exception.

The casting itself is necessary because a java.lang.Object is not of the correct type and the Unity AndroidJavaObject can’t find the correct method to invoke via Call if that’s the case.

Is there no way to pass a null reference to a Java method as a parameter? :face_with_spiral_eyes:

Bump, no one?

Figured it out:

	public static void RegisterFilter(AndroidJavaObject filter) {
		System.IntPtr clazz = Activity.GetRawClass();
		// http://www.rgagnon.com/javadetails/java-0286.html
		System.IntPtr method = AndroidJNI.GetMethodID(clazz, "registerReceiver", "(Landroid/content/BroadcastReceiver;Landroid/content/IntentFilter;)Landroid/content/Intent;");
		UnityEngine.jvalue[] args = AndroidJNIHelper.CreateJNIArgArray(new [] { null, filter });
		AndroidJNI.CallObjectMethod(Activity.GetRawObject(), method, args);
	}

I just spent some time trying to figure out the opposite problem, getting a null value from a java object into Unity. Using null doesn’t work, because the object itself is valid. What I did was test the raw object’s integral value for 0 to find out if it was null.

C# code:

AndroidJavaClass cls = new AndroidJavaClass("com.mycompany.myproduct.myclass");
AndroidJavaObject obj = cls.CallStatic<AndroidJavaObject>("getStringArray");
if (obj.GetRawObject().ToInt32() != 0)
{
  // String[] returned with some data!
  String[] result = AndroidJNIHelper.ConvertFromJNIArray<String[]>(obj.GetRawObject());
  foreach (String str in result)
  {
    // Do something with the strings
  }
}
else
{
  // null String[] returned
}
obj.Dispose();
cls.Dispose();

java code:

public static String[] getStringArray()
{
  String[] strs = { "Test1", "Test2" };
  return strs;   // Or alternatively, return null;
}

The reason I point this out is that 1) I couldn’t find an example of getting String[ ] from Android through the Unity JNI (and this works), so hopefully someone will stumble on it. and 2) I’ll bet, but I can not promise, that if you sent a JNIObject with it’s Raw Object (i.e. the IntPtr) set to 0, that would be an alternative to sending null to the java function. Unfortunately I don’t need to do that, so I can’t verify right now.

1 Like

@supernat, I am trying to implement your solution and keep coming up with:

JNI: Unable to find method id for ‘getStringArray’ (static)
UnityEngine.AndroidJavaObject:CallStatic(String, Object[ ])
inAppBillingHandler:Instantiate(Int32) (at Assets/customScripts/inAppBillingHandler.cs:14)
inAppBillingManager:Start() (at Assets/customScripts/inAppBillingManager.cs:10)

and

JNI: Init’d AndroidJavaObject with null ptr!
UnityEngine.AndroidJavaObject:CallStatic(String, Object[ ])
inAppBillingHandler:Instantiate(Int32) (at Assets/customScripts/inAppBillingHandler.cs:14)
inAppBillingManager:Start() (at Assets/customScripts/inAppBillingManager.cs:10)

First, are you able to test this in editor or must you move to android device?
Second, I changed the (new AndroidJavaClass(“com.mycompany.myproduct.myclass”):wink: to what it is in my package identifier as well as myclass to IabHelper (trying to implement in-app billing) IabHelper.java is located in Plugins/Android folder.

Does all of the above sound correct or am I missing some step?

@MFen getStringArray was just an example method that would return a string[ ]. In other words, if you have a method that is returning a string[ ], you would use the name of your method in place of getStringArray. You have to test on the device, so you should wrap this in a #if ANDROID (or whatever constant there is for Android, I forget now). If you’re only doing Android, you could also just say if (!Application.isEditor).

You are correct in setting the class name. It should be your fully qualified package name. I should have chosen a better name for the getStringArray method, as that isn’t a real method, but it sounds like one, lol. Sorry.

I wonder how this call seems to work for you.

The internal constructor for AndroidJavaObject is set to throw in case it’s initialized with a “null pointer” (IntPtr.Zero):

2071536--135182--upload_2015-4-16_19-48-38.png

Sorry, I don’t follow your question. Could you describe the problem in more detail?

I am using code that may return null from Java, for example:

var intent = AndroidUtil.Activity.Call<AndroidJavaObject>("getIntent");
var extras = intent.Call<AndroidJavaObject>("getExtras"); // can return null

The second line will throw an exception since the AndroidJavaObject constructor will throw in case it’s initialized as “null” (with IntPtr.Zero).

I asked - how did that code work for you ?

Oh I see, yes that part is out of date, I get an exception now. I ended up not sending a null but a single string with a unique entry to identify null. Maybe you could put a try/catch block and catch it.

Not specific to JNI, but when calling methods on AndroidJavaObjects in C#, which require passing a null parameter you will need to pass in a null referenced AndroidJavaObject.

Example:

AndroidJavaObject nullObject = null;
AndroidJavaClass javaClass = new AndroidJavaClass("com.my.class")
AndroidJavaObject returnObject = javaClass.CallStatic<AndroidJavaObject>("staticFunctionNameWithNullParameter", "parameter1", "parameter2", nullObject );

Passing a C# null, or IntPtr.Zero both get filtered out before binding with the Java method, which causes an incorrect number of parameters to be passed along to Java, which ultimately results in a method signature mismatch.

Edit: Not to resurrect an old thread. However, when trying to solve this problem for myself this is the thread that kept being the top pick from Google. I figured it was a good enough place to store the solution to my problem in hopes that it helps others.

1 Like

Have you tested that ? Seems very unlikely that would work to me.
Looking at the code in Unity 5.1 beta 5, the arguments passed to JNI are parsed like this (peeked using MonoDevelop’s decompilation):

2095531--137155--upload_2015-5-2_19-42-44.png
As you can see, a null value passed does not have any “type” associated to it at all, so it wouldn’t make any different whether you have a null string or a null AndroidJavaObject.

I also think that at the C# language level, a null reference does not have any type, so again, this shouldn’t make any difference.