3

I am working on a Unity application that runs on Android (lets call it App A). I have to move some code from another Android Unity app (App B) into my Unity app.

This code that I need to move to App A is responsible for querying an IMU (Internal Measurement Unit). This is the relevant code that exists in App B

AndroidJavaObject ActivityObject;
AndroidJavaClass ActivityClass;

AndroidJNI.AttachCurrentThread();
ActivityClass = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
ActivityObject = ActivityClass.GetStatic<AndroidJavaObject>("currentActivity");

tagID = ActivityObject.Call<string>("getTAGID");

And here is the manifest file for App B

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.indotraq.rtls" android:versionName="1.0.0" android:versionCode="1">

  <supports-screens android:smallScreens="true" android:normalScreens="true" android:largeScreens="true" android:xlargeScreens="true" android:anyDensity="true" />
  <application android:icon="@drawable/app_icon" android:label="@string/app_name" android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen" android:debuggable="false">

    <meta-data android:name="com.samsung.android.vr.application.mode" android:value="vr_only"/>

    <activity
            android:name="com.indotraq.android.rtls.MainActivity"
            android:screenOrientation="landscape" 
            android:launchMode="singleTask"
            android:configChanges="screenSize|orientation|keyboardHidden|keyboard"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
                 <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"/> 
            </intent-filter>
            <meta-data android:name="unityplayer.UnityActivity" android:value="true" />
            <meta-data android:name="unityplayer.ForwardNativeEventsToDalvik" android:value="false" />
             <meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" android:resource="@xml/device_filter" /> 
    </activity>

  </application>

  <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="19" />
  <uses-feature android:glEsVersion="0x00020000" />
  <uses-permission android:name="android.permission.INTERNET" />
  <uses-permission android:name="android.permission.WAKE_LOCK" />
  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  <uses-permission android:name="android.permission.CAMERA" />
  <uses-permission android:name="android.permission.BLUETOOTH" />
  <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
</manifest>

This is the manifest from App A

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.sensics.palace" android:versionName="1.0" android:versionCode="1" android:installLocation="preferExternal">
  <supports-screens android:smallScreens="true" android:normalScreens="true" android:largeScreens="true" android:xlargeScreens="true" android:anyDensity="true" />
  <application android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen" android:icon="@drawable/app_icon" android:label="@string/app_name" android:debuggable="false">
    <activity android:name="com.unity3d.player.UnityPlayerNativeActivity" android:label="@string/app_name" android:screenOrientation="sensorLandscape" android:launchMode="singleTask" android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale">
      <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
        <category android:name="android.intent.category.LEANBACK_LAUNCHER" />
      </intent-filter>
      <meta-data android:name="unityplayer.UnityActivity" android:value="true" />
      <meta-data android:name="unityplayer.ForwardNativeEventsToDalvik" android:value="false" />
    </activity>
  </application>
  <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="25" />
  <uses-feature android:glEsVersion="0x00020000" />
  <supports-gl-texture android:name="GL_AMD_compressed_ATC_texture" />
  <supports-gl-texture android:name="GL_ATI_texture_compression_atitc" />
  <uses-feature android:name="android.hardware.touchscreen" android:required="false" />
  <uses-feature android:name="android.hardware.touchscreen.multitouch" android:required="false" />
  <uses-feature android:name="android.hardware.touchscreen.multitouch.distinct" android:required="false" />
  <uses-permission android:name="android.permission.WAKE_LOCK" />
  <uses-permission android:name="android.permission.INTERNET" /> 
</manifest>

I need to copy the relevant parts of the manifest for App B into the manifest for App A and this is where I am getting stuck.

So in App A, there is a secondary thread. This thread exists so that our app can do some processing when the app is placed into the background. This thread has existed for a long time an dutifully runs continues to execute when App A is placed into the background.

I did try various thing to merge the manifest files together. The first thing I tried was merging the activities into one. What I discovered is that unless the activity is named "com.unity3d.player.UnityPlayerNativeActivity", my background thread would not run when the app was place into the background.

This is the manifest from my most recent attempt.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.indotraq.rtls" android:versionName="1.0.0" android:versionCode="1">

  <supports-screens android:smallScreens="true" android:normalScreens="true" android:largeScreens="true" android:xlargeScreens="true" android:anyDensity="true" />
  <application android:icon="@drawable/app_icon" android:label="@string/app_name" android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen" android:debuggable="false">

    <meta-data android:name="com.samsung.android.vr.application.mode" android:value="vr_only"/>
    <activity android:name="com.unity3d.player.UnityPlayerNativeActivity" android:label="@string/app_name" android:screenOrientation="sensorLandscape" android:launchMode="singleTask" android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
            <category android:name="android.intent.category.LEANBACK_LAUNCHER" />
            <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"/>
        </intent-filter>
        <meta-data android:name="unityplayer.UnityActivity" android:value="true" />
        <meta-data android:name="unityplayer.ForwardNativeEventsToDalvik" android:value="false" />
        <meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" android:resource="@xml/device_filter" />
    </activity> 
    <activity
            android:name="com.indotraq.android.rtls.MainActivity"
            android:screenOrientation="landscape" 
            android:launchMode="singleTask"
            android:configChanges="screenSize|orientation|keyboardHidden|keyboard"
            android:label="@string/app_name" >
            <meta-data android:name="unityplayer.UnityActivity" android:value="true" />
            <meta-data android:name="unityplayer.ForwardNativeEventsToDalvik" android:value="false" />
    </activity>
  </application>

  <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="19" />
  <uses-feature android:glEsVersion="0x00020000" />
  <uses-permission android:name="android.permission.INTERNET" />
  <uses-permission android:name="android.permission.WAKE_LOCK" />
  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  <uses-permission android:name="android.permission.CAMERA" />
  <uses-permission android:name="android.permission.BLUETOOTH" />
  <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
</manifest>

With this manifest my thread runs just fine in the background, but this code

  LogManager.Log("At pos 1");
  AndroidJNI.AttachCurrentThread();
  LogManager.Log("At pos 2");
  ActivityClass = new AndroidJavaClass("com.indotraq.android.rtls.MainActivity");

  if(ActivityClass == null) {
    LogManager.Log("ActivityClass == null");
  }
  else {
    LogManager.Log("ActivityClass != null");
  }

  LogManager.Log("At pos 3");
  ActivityObject = ActivityClass.GetStatic<AndroidJavaObject>("currentActivity");
  LogManager.Log("At pos 4");

  tagID = ActivityObject.Call<string>("getTAGID");
  LogManager.Log("At pos 5");

Produces this output.

At pos 1 At pos 2 ActivityClass != null At pos 3
AndroidJavaException: java.lang.NoSuchFieldError: no "Ljava/lang/Object;" field "currentActivity" in class "Lcom/indotraq/android/rtls/MainActivity;" or its superclasses
java.lang.NoSuchFieldError: no "Ljava/lang/Object;" field "currentActivity" in class "Lcom/indotraq/android/rtls/MainActivity;" or its superclasses at com.unity3d.player.UnityPlayer.nativeRender(Native Method) at com.unity3d.player.UnityPlayer.c(Unknown Source) at com.unity3d.player.UnityPlayer$c$1.handleMessage(Unknown Source) at android.os.Handler.dispatchMessage(Handler.java:98) at android.os.Looper.loop(Looper.java:145) at com.unity3d.player.UnityPlayer$c.run(Unknown Source) at UnityEngine.AndroidJNISafe.CheckException () [0x00000] in :0 at UnityEngine.AndroidJNISafe.GetStaticFieldID (IntPtr clazz, System.String name, System.String sig) [0x00000] in :0 at UnityEngine._AndroidJNIHelper.GetFieldID (IntPtr jclass, System.String fieldName, System.String signature, Boolean isStatic) [0x00000]

Any insight into what I need to do to get this working would be greatly appreciated.

Thank you John Lawrie

Balagurunathan Marimuthu
  • 2,927
  • 4
  • 31
  • 44
Dalanchoo
  • 177
  • 1
  • 3
  • 17
  • Could it be because of android:minSdkVersion="xx" android:targetSdkVersion="xx". I had something similar before. And i made those version number equal to each other in both,By both i mean you have 2 manifest files. I used the lower value for them. And voila! my problem solved. Have no clue for yours but this might help – Thalthanas Jul 21 '17 at 07:33

1 Answers1

0

It is as the error states, there is no 'currentActivity' Field in your com.indotraq.android.rtls.MainActivity Class. currentActivity is a member of com.unity3d.player.UnityPlayer. You could create a static field in the class and assign it yourself in the constructor of MainActivity. Something like this will do

public class MainActivity extends AppCompatActivity
{
  static public MainActivity currentActivity;
  MainActivity()
  {
    currentActivity = this;
  }

}  

Then you can successfully call the non-static method tagID = ActivityObject.Call<string>("getTAGID");

PS: It does not actually get the "activity",just the instance of the class so, currentInstance would be more appropriate.

Suraj S
  • 1,019
  • 7
  • 18
  • I don't have the source code for the activity, just a .jar file. – Dalanchoo Jul 21 '17 at 17:34
  • @Dalanchoo This ought to do it ... Just change the code and rebuild the Android module https://stackoverflow.com/questions/5107187/extract-source-code – Suraj S Jul 22 '17 at 01:02