Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Unity Android Interop: Can I create a java.util.ArrayList from Unity code and use it?

Discussion in 'Scripting' started by ghostravenstorm, Oct 1, 2021.

  1. ghostravenstorm

    ghostravenstorm

    Joined:
    Oct 18, 2015
    Posts:
    88
    I'm fiddling with a card reader SDK where I'm trying to implement it without any plugin wrapper. Just straight `AndroidJavaObject` and/or `AndroidJNI`.

    This SDK has a method that returns a `java.util.ArrayList` of type `java.lang.String` that is a list of usb connected card readers. In my Unity code, I'm invoking the method to get the list like so:

    Code (CSharp):
    1. var deviceList = new AndroidJavaObject("java.util.ArrayList");
    2.  
    3. try {
    4.    long result = scard.Call<long>("SCardListReaders", unityContext, deviceList);
    5.    Debug.Log("SCardListReaders result: " + result);
    6. }
    7. catch (Exception e) {
    8.    Debug.LogError(e);
    9. }
    10.  
    11. int deviceCount = 0;
    12. try {
    13.    deviceCount = deviceList.Call<int>("size");
    14. }
    15. catch (Exception e) {
    16.    Debug.LogError(e);
    17. }
    18.  
    19. Debug.Log("Device count: " + deviceCount);
    20. Debug.Log("Connected devices:");
    21. for (int i = 0; i < deviceCount; i++) {
    22.    try {
    23.       // var device = deviceList.Call<string>("get", i); // Soft crash here
    24.       var device = deviceList.Call<AndroidJavaObject>("get", i); // Soft crash here
    25.       Debug.Log(device);
    26.    }
    27.    catch (Exception e) {
    28.       Debug.LogError(e);
    29.    }
    30. }
    Line 24 is where a soft crash happens and the rest of the script doesn't function. Not a single exception is caught either.

    I'm womdering if something is wrong with the way the ArrayList is being made, but the API call I'm using is putting data into the ArrayList and I can see there is a element count. The issue is when I'm trying to get data. I tried several types that would seem correct.

    To test the fuctionality of Java ArrayLists in Unity further, I made one and then tried to add elements to it just from Unity code. I get the same soft crash when invoking the `add` method like I did with the `get` method.
    Code (CSharp):
    1.    public void ArrayListTest () {
    2.       NanoDebug.Log("Array List Test derp");
    3.       try {
    4.          var arraylist = new AndroidJavaObject("java.util.ArrayList");
    5.          arraylist.Call("add", 1); // Soft crash here
    6.       }
    7.       catch (Exception e) {
    8.          NanoDebug.LogError(e);
    9.       }
    10.       NanoDebug.Log("Done");
    11.    }
    Note that an exception is never caught, and my "done" print statement never executes. The script also becomes unreponsive.

    Inspecting how Java ArrayLists work, I realize this invokcation from Unity is never giving the ArrayList a generic type. Shouldn't be invoked with something like this syntax?
    Code (CSharp):
    1. new AndroidJavaObject<string>("java.util.ArrayList")
    2. new AndroidJavaObject("java.util.ArrayList", typeOf(string))
    ???
    I have no idea how this would work. I just know that making an Java ArrayList from Unity code seems to not be giving it a generic type, so wonkyness starts to happen when I use `add` or `get` methods.

    So I'm asking, is it even possible to work with a Java ArrayList from the Unity side?
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,762
    Nothing shown in the
    adb logcat
    either??

    Unsure... I thought the Unity stuff was just sort of a reflecto-wrapper that takes objects and strings and tries to find related methods and calls them for you.

    Perhaps it is necessary to additionally wrap any arguments you give to add() rather than just passing an integer in??
     
  3. ghostravenstorm

    ghostravenstorm

    Joined:
    Oct 18, 2015
    Posts:
    88
    I'm having a difficult time using logcat because my tablet cannot stay plugged into my windows. I'm developing for a USB peripheral and that USB port on the tablet is always occupied.
     
  4. ghostravenstorm

    ghostravenstorm

    Joined:
    Oct 18, 2015
    Posts:
    88
    My best method at debugging without a debugger attached is to capture Unity's debug output and write it to a text field.
    This of course has issues if the GUI doesn't respond.
     
  5. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,762
    That's unfortunate. I don't think that log would contain exceptions thrown... maybe though??? Next thing is to try and find example code making one of those ArrayList objects from Unity and playing with it.

    Also what about some kind of USB hub thingy? Dunno how to owner / attacher rights are sorted out in USB though...
     
  6. ghostravenstorm

    ghostravenstorm

    Joined:
    Oct 18, 2015
    Posts:
    88
    I've tried a hub. The Samsung tablet I'm developing with doesn't recognize a computer through it where it can enable USB debugging. I'm figuring this out as I go. I hope to come across a better solution.
     
  7. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,762
    I think I would have reached for the plugin wrapper by now. :)

    BTW, can you bang on the API you want from native JNI? It's SUPER-easy to drop a C / C++ file into the Plugins/Android folder and its functions just gets linked in and available to your Unity code via the C# interop stuff.
     
  8. PizzaPie

    PizzaPie

    Joined:
    Oct 11, 2015
    Posts:
    103
    Have you considered running adb via tcp/ip to eliminate the need for USB.
     
  9. ghostravenstorm

    ghostravenstorm

    Joined:
    Oct 18, 2015
    Posts:
    88
    Unfortunately, the SDK I'm trying to use is written in Java, so Java methods are what I need to call.
     
  10. ghostravenstorm

    ghostravenstorm

    Joined:
    Oct 18, 2015
    Posts:
    88
    I have, but I haven't put the time into learning how to set it up yet. I was hoping for what I'm trying to investigate with this Smart Card Reader SDK written in Java would be a quick adventure, but I'm starting to get wrapped up in a bunch of different nuances of calling Java code from Unity. I may just need to set that up so I can properly debug things.
     
  11. ghostravenstorm

    ghostravenstorm

    Joined:
    Oct 18, 2015
    Posts:
    88
    I discovered some errors in my logging functions. They were silently throwing cast errors. I resolved that and went back to investigating using a Java ArrayList purely from Unity code.

    I can make an ArrayList.
    Code (CSharp):
    1. var arraylist = new AndroidJavaObject("java.util.ArrayList");
    I can retrieve properties of the arraylist
    Code (CSharp):
    1. var size = arraylist.Call<int>("size");
    2. Debug.Log(size); // 0
    3. var isEmpty = arraylist.Call<bool>("isEmpty");
    4. Debug.Log(isEmpty); // true
    But when I try to call `add` or `get` I get the following `AndroidJavaException`:
    Code (CSharp):
    1. var arraylist = new AndroidJavaObject("java.util.ArrayList");
    2. try {
    3.    arraylist.Call("add", 1);
    4. }
    5. catch (Exception e) {
    6.    Debug.LogError(e);
    7. }
    UnityEngine.AndroidJavaException: java.lang.NoSuchMethodError: no non-static method with name='add' signature='(I)V' in class Ljava.lang.Object;


    I've confirmed `add` does exist according to the Java API
    https://docs.oracle.com/javase/7/docs/api/java/util/ArrayList.html

    Is this an Android/Java bug, or does it not recognize these methods for techincal reasons?

    I've also noticed that ArrayList<E> being a part of generics, there is no way to declare what type of data the ArrayList handles when you use
    new AndroidJavaObject("java.util.ArrayList")
    .
    So, is managing a Java ArrayList from Unity code even possible? It seems like you can only pass it around and any such management has to be done on the Java native side.