OK, let’s go ahead and get this out of the way. This post is not for beginners or the faint of heart. There is no way to access Android’s Magnetic Field Sensor (aka the compass) directly from Unity, so in order to do that we’re going to have to write a custom plugin. This is not an easy task, and I honestly don’t know how well I can explain it – so… stick with me and hopefully we’ll get through this together. (Note: At the time of this writing I’m using Unity 3.4 so if you’re a traveler from the distant future, I don’t know how much of this will still be valid)
Quick Overview of custom plug-ins:
Writing a custom plugin is very poorly documented, and anyone who does it pretty much has to figure it all out by themselves. For Android, here’s the process:
1. Write a custom Java jar file.
2. Write a C(++) library using JNI to access the jar file and compile it into a .so file using Android NDK
3. Import the DLL (.so file) into C# script inside unity and access all the magic.
Now, I’m not that great of a C developer, so I opted to do the following instead:
1. Write a custom Java jar file.
2. Use the AndroidJNI helper function embedded in Unity to access the jar file.
The latter method is the one we’re going to use today.
Step 1: Setting up your environment
Here is a list of things that you should already have installed on your computer:
– Java
– Android SDK
You should also have your version of Java’s bin directory in your path – that way you can call different java commands from anywhere.
After you’ve created a new Unity Project, you’ll need to create the following folders:
Plugins\Android\src\com\yourcompany\yourgamename
* The namespace here is incredibly important. It doesn’t matter what you call com.yourcompany.yourgamename, it just matters that we use it everywhere in this game and plugin. So with that in mind, in Unity go to File->Build Settings -> Player Settings and put your namespace in the Bundle Identifier field. Last note – Case totally matters.
Now that we’ve got everything set up it’s time for…
Step 2: Writing our Java plugin
In the Plugins\Android\src folder create a new file called CompassActivity.java. Open this with your favorite text editor.
Copy and paste the Java code below but know that you’re going to have to change the package to the namespace we created in step 1:
package com.yourcompany.yourgamename; import com.unity3d.player.UnityPlayerActivity; import android.content.Context; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.os.Bundle; import android.util.Config; import android.util.Log; import android.app.Activity; public class CompassActivity extends UnityPlayerActivity { private static final String TAG = "Compass"; private SensorManager mSensorManager; private Sensor mSensor; static public float xmag; static public float ymag; static public float zmag; private final SensorEventListener mListener = new SensorEventListener() { public void onSensorChanged(SensorEvent event) { if (Config.DEBUG) Log.d(TAG, "sensorChanged (" + event.values[0] + ", " + event.values[1] + ", " + event.values[2] + ")"); xmag = event.values[0]; ymag = event.values[1]; zmag = event.values[2]; } public void onAccuracyChanged(Sensor sensor, int accuracy) { } }; @Override protected void onCreate(Bundle icicle) { super.onCreate(icicle); mSensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE); mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION); } @Override protected void onResume() { if (Config.DEBUG) Log.d(TAG, "onResume"); super.onResume(); mSensorManager.registerListener(mListener, mSensor, SensorManager.SENSOR_DELAY_GAME); } @Override protected void onStop() { if (Config.DEBUG) Log.d(TAG, "onStop"); mSensorManager.unregisterListener(mListener); super.onStop(); } public static float getX() { return xmag; } public static float getY() { return ymag; } public static float getZ() { return zmag; } }
Once you’ve changed the package namespace and saved the file, open a command prompt and cd to the src directory. We’re going to run the following java commands to compile, sign, and jar our plugin: (note: You may need to alter the classpath and bootclasspath to match your system)
1.> javac CompassActivity.java -classpath C:\Program Files (x86)\Unity\Editor\Data\PlaybackEngines\androidplayer\bin\classes.jar -bootclasspath C:\android-sdk-windows\platforms\android-8\android.jar -d .
2.> javap -s com.yourcompany.yourgamename.CompassActivity
3.> jar cvfM ../Compass.jar com/
Once you’ve finished those three steps you should now have a file called Compass.jar in your Plugins\Android\ folder.
Step 3: Setting up our AndroidManifest.xml
The AndroidManifest.xml is very important. When your Unity App launches on the Android device, this file will tell it to load our .jar file instead of the UnityPlayer.jar file. Our jar file takes over because it extends the UnityPlayer Activity (which loads the UnityPlayer Activity). You’ll want to create the file AndroidManifest.xml in our \Plugins\Android folder. (Note: Don’t forget to change your package here as well)
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.yourcompany.yourgamename" android:versionCode="1" android:versionName="1.0"> <uses-sdk android:minSdkVersion="8" /> <application android:icon="@drawable/icon" android:label="@string/app_name"> <activity android:name=".CompassActivity" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
Step 4: Accessing the Plugin from Unity
At this point we could build our application and push it to our phone and everything would work correctly, but we haven’t pulled any information out of it. If you look at the Java code I’ve written three methods called GetX, GetY, and GetZ. We’re going to call those methods from Unity and get the output (which in turn will give us the X, Y, and Z values from the Magnetic Sensor). For this example we’re going to output the values to the GUI. First, create a new C# file (it doesn’t matter what you call it). Here’s what we need to put in it: (don’t forget to change the namespace)
using UnityEngine; using System.Collections; using System; public class CompassJNI : MonoBehaviour { static float xValue; static float yValue; static float zValue; // Use this for initialization void Start () { AndroidJNI.AttachCurrentThread(); } void Update() { using (AndroidJavaClass cls_UnityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer")) { using (AndroidJavaObject obj_Activity = cls_UnityPlayer.GetStatic("currentActivity")) { AndroidJavaClass cls_CompassActivity = new AndroidJavaClass("com.yourcompany.yourgamename.CompassActivity"); cls_CompassActivity.CallStatic("Init", obj_Activity); xValue = cls_CompassActivity.CallStatic("getX"); yValue = cls_CompassActivity.CallStatic("getY"); zValue = cls_CompassActivity.CallStatic("getZ"); } } Debug.Log("Compass values are " + xValue.ToString() + "," + yValue.ToString() + "," + zValue.ToString()); } void OnGUI() { GUI.Label(new Rect(Screen.width / 2 -200, Screen.height / 2, 400,100), "xmag = " + xValue.ToString() + " ymag = " + yValue.ToString() + " zmag = " + zValue.ToString()); } }
Attach this script to your camera and build your application. You should see the 3 Values change as you move your Android Device around. And there you go – we’re now accessing the compass.
Hopefully these steps will give you a better understanding of how Unity custom plugins work. There’s a lot of information in here and plenty of places for things to screw up, so if you have any issues leave a comment and I’ll do my best to help.
If this tutorial helped you out, why don’t you go buy one of my video games =)
This is very close to what I had, but I still can’t get it working, granted I am using Eclipse with my source in a different folder. I managed to get it so the app doesn’t crash but something is still amiss because my values are all 0, yet the java app I write shows them all just fine.
What is the importance of the Plugins/Android/com/company/app foider structure, ie. what files actually go in there?
Is it important to have the source located in the plugin folder too?
I’m a little concerned that you create and destroy the activity class every update frame. I can only imagine that this doesn’t allow anything to happen, because you create it, register the sensors, read the values and immediately destroy it before the system even gets a chance to fire the events.
I’m not a java expert, I’ve only been doing a crash course in it for a couple of days now, so I’m afraid I have no idea what I’m doing wrong. Like most others, my attempts to get help from UT have gone unanswered.
Also I’m not sure how you got your C# code working, as CallStatic returns void, not float.
Hey Blitzwing, the CallStatic function can return anything actually. Sometimes you need to specify the return type, but in this case I didn’t need to. You can do this:
or
*In the (float) above substitute the parenthesis for Greater Than and Less Than. For some reason wordpress isn’t letting me type that out correctly.
As to your first question, the folder path is important when you’re compiling your .java file – all of the .class files are created in there. Later when you use the jar command it’ll put all of the .class files in your folder path into the jar file.
I tried using Eclipse at first when doing this and I got all sorts of errors and ended up just doing it all manually like the steps I mentioned.
Also, are you using logcat to get the logging off of your phone after you compile and start Unity? That’s how I found out all of my errors and worked my way from there. If you are getting errors, please tell me what they are and I’ll try to help.
Thanks Timothy,
I am aware of the generic versions of CallStatic yes, and that’s what I am using, I just wasn’t sure if that is what Joshua intended.
I’m like a total n00b with java and I have no idea how to make a project without using Eclipse yet, but I had a go with putting code in the right folders, and the code is a pain to edit with wordpad too :/. I also downloaded Tapjoy plugin to see how they are doing it, and it mostly looks the same. When I put the manifest file in I got compile errors in Unity.
I also notice Joshua talks about signing the jar (I’ve heard others say they needed to sign it to get it to work), but I don’t see any commands there to sign it.
I’m not using logcat no, but I think I had better start.
Seems the call to the constructor is failing
I/Unity ( 7051): (Filename: /Applications/buildAgent/work/842f9557127e852/Runt
ime/Export/Generated/UnityEngineDebug.cpp Line: 34)
I/Unity ( 7051):
E/Unity ( 7051): getMethodID(“Init”, “(Lcom.unity3d.player.UnityPlayerActivity
;)V”) FAILED!
I/Unity ( 7051): JNI: Unable to find method id for ‘Init’ (static)
I/Unity ( 7051): UnityEngine.Debug:Internal_Log(Int32, String, Object)
I’ve moved my eclipse project into Plugins/Android and I compile my .jar to the bin folder now. At best I can stop errors in logcat if I remove the call to the constructor, but of course, nothing happens then. Ive tried Init, init and but it never seems to be able to find a constructor.
I have succeeded in getting it working (with Eclipse!). I had to remove the call to the constructor, and use static variables in the java (as in the example). I tried to use instance variables.
The main thing I am not happy with now is the garabage that will be generated by creating new Android interface objects every update.
I am noticing however that the app freezes after a few minutes, every time.
I also switched out the using clauses and only created the objects once, but the error still occurs.
I put the reading of the sensors in the onSensorChanged event in a synchronized block like I saw IBM do in their IBMEyes app, and that seems to have cured the problem.
So glad you got everything working BLiTZWiNG. The C# I posted was what I used when I first got everything working. I re-worked it to be much less processor intensive in my final project. Hope to see your project/game once you’ve completed it!
Hey, I wrote a complete android sensor library for Unity3d (in a quite similar aproach to yours) – it provides access to every single sensor android has to offer, but has many more advantages, like automatic fallback for less accurate sensors and so on. It also creates zero garbage :-). You can see it in action here: goo.gl/oLkOQ. This is the link to the forum thread about GyroDroid, available from the asset store: goo.gl/8ZIM7.
Thanks Timothy, it was a massive help in getting me to where I am. Sadly now I have to wrestle with conversion of android axis to unity! I do pick the hard projects…
its not working for me..but thanks a lot for your tutorial!
can you please post files?
or just explain better the steps for compiling class-file?
thanks
+1 to upload files idea 🙂
I guess I could post the files, but they would be exactly what I have posted above. To compile class files you have to run the java commands posted above
– javac is the command you use to turn a .java file into the compiled class files
– javap -s prints out the type signatures
– jar cvfM compresses all of the .class files into a .jar file.
If you guys are still confused I’ll see what I can do. This is all pretty much Java 101 stuff, so perhaps some Java tutorials might help you out.
Hey, I really appreciate the tutorial.
When I run the above scripts on my phone, it crashes immediately without an error. By trial and error I determined that the crash is caused by the following line:
new AndroidJavaClass(“com.company.game.CompassActivity”);
I’ve taken this to mean that the java class file was not found in the jar file. I had to change the directories for the javac, javap, and jar cvfm commands, but the jar was created without errors and all my packaging seems to be correct. I’ve tried several times without any success.
So, I took a step backwards and downloaded the JavaScriptExample unity file from the unity plugin official page. (there is a rar you can download that has source code very similar to that from this tutorial.) Using their .jar file the program runs just fine. Using a jar file I generate using –their .class files and directors– the program crashes on my phone.
So my problem is definitely caused by the jar creation process. Here are my guesses as to why;
– I do not have the Android NDK installed, only the SDK
– Your javac command usies the “android-8” platform, which I changed arbitrarily to 9 because my SDK install does not include 8.
Any help would be greatly appreciated.
You did replace “com.company.game.CompassActivity” with the name of your namespace and class right?
Yes,
The App runs correctly when using the .class included in the plugin example source code. It is only when using a .class file that I compiled myself that I encounter a problem. I’m using a .java file that was included, and the package is correct.
The following are the lines I use to create the .class and .jar files. The namespace and class are changed to reflect that of the plugin example, and not the ones from this tutorial.
>javac JavaClass.java -classpath D:\Programs\Unity\Editor\Data\PlaybackEngines\androidplayer\bin\classes.jar -bootclasspath D:\Programs\AndroidSDK\platforms\android-8\android.jar -d .
>javap -s org.example.ScriptBridge.JavaClass
>jar cvfM ../JavaClass.jar org/
The .jar created using the INCLUDED .class file works just fine. So the problem is caused by something in the first two lines. My only guess is that the androidSDK I have installed is corrupt.
Thanks for the reply
Alright, I got it working! I’ll try to summarize the problems I found.
1.) Every “GetStatic” method needs to have a return type specified. For example;
AndroidJavaObject obj_Activity = cls_UnityPlayer.GetStatic(“currentActivity”)
should be replaced by
AndroidJavaObject obj_Activity = cls_UnityPlayer.GetStatic(“currentActivity”)
2.) One line in the manifest file will cause a “repackage” error that is caught by unity. This is fixed by changing the following line;
to
3.) If your app crashes with no error when running on the actual phone, it could be because you are trying to use the newest version of java. You need to be using jdk1.6.0_27 and jre. This tripped me up for a while.
Hope this helps
it looks like wordpress parsed out your manifest lines. please re-post your snippets using < (& l t ; — with no spaces) and such (or without brackets)
Okay so Unity can pull data from the Android Java side… but how do you send data from Android Java side to Unity?
You don’t. You make it available to Unity and read it from there. It’s exactly the same thing.
Got this to work… but am hzing Blitzwing’s problem of the app freezing after about 10-20 seconds…
11-04 23:39:01.455: D/WindowManager(23630): call unlinkToDeath, this=Window{410c2e58 Starting com.company.app paused=false}
Figured it out… app not freezing anymore! 🙂 – apparently AndroidJavaClass variable should be a global, newe AndroidJavaClass called once in Start(), and not called in Update (though its value may be updated!)
Er yes I should have mentioned that…
Hi. Thank you for telling us how to DIY plugins.
But I don’t know how to combine more than one plugins. For example, I downloaded two or three android plugins but the Manifest.xml will be overwritten if put all of them together. Could you teach me how? Thank you!
That sounds like a good focus for a separate blog post. As soon as I get some time I’ll get an example up…
Any ideas on how to get this to work? Otherwise a great tutorial – thanks 🙂
I haven’t touched this code in a while so I’m not sure if it still works on the latest version of Unity. Are you getting an error?
I think I got the Manifest OK, which was my original problem. I just included my new activity with a fully qualified name (and kept the original package as the qualcomme one).
I’m actually not using your CompassActivity, but rather trying to use the Android Gallery in a plugin. I’m not getting any errors, but the app doesn’t seem to do anything. Also it’s kind of hard to debug, because I can’t check if pictures are saved while the device is plugged in (which I need it to be to use the adb, if I’m not mistaken). Also sorry for the unrelated spam – feel free to delete my spam comment 😀
Can unity set a value and send to jar, then jar file send that value back to unity?
No, the activity flow is in only one direction (Hardware Sensors, Jar Activity, Unity Activity)
Hello,
The tutorial is good. but i couldn’t get the answer yet.
you said that, after created CompassActivity.java and drag into Assets->Plugins->Android->src->CompassActivity.java
after this step in command prompt need to set path of project directory. isn’t ? now i got this error. can u say where am missing the step?
and i set bundle identifier correctly.
AndroidPluginJan16-Me sriram$ javac CompassActivity.java -classpath /Applications/Unity/Unity.app/Contents/PlaybackEngines/AndroidPlayer/bin/classes.jar -bootclasspath /Users/sriram/Android/android-sdk-macosx/platforms/android-14/android.jar -d
javac: file not found: CompassActivity.java
Usage: javac
use -help for a list of possible options
am using mac os, unity 3.4.0.
Hello, I have been trying to make this works with some version updates:
– Unity 3.5
– Android-15
– Java jdk1.7.0_03 jre7
Here are my findings so far:
I needed to substitute the line:
using (AndroidJavaObject obj_Activity = cls_UnityPlayer.GetStatic(“currentActivity”)) {
with:
using (AndroidJavaObject obj_Activity = cls_UnityPlayer.GetStatic<AndroidJavaObject>(“currentActivity”))
It also seems that the name of the cs does matter now. I needed to rename it as the name of the class: “CompassJNI”.
I get the APK, but it breaks as soon as it starts. I have read that it may be caused because of the java version and I shoud use a lower one, but I would like to have it running with the current version.
Can anyone give me a hand with this?
Thank you very much in advance.
WOOT! I got it working! Heres is what I found I had to do…
1. Insure the Plugins folder is in the Assets directory, as it will be if you create them through the Unity interface. (I created them through explorer, and put them in the base project folder… 😦 )
2. As already mentioned, add the return types to the calls in the unity c# file. As that has been discussed, I won;t give the details here, as word press apparently likes to eat lines with angle brackets in them.
3. Use Java 1.6.0_27. It’s possible others would work, but I tried 7 after I got it working, and it broke it again, so I went back to 1.6.0U27.
4. In the android manifest file, change drawable/icon to drawable/app_icon (line 8ish) I think this is what Samuel was saying before, but his lines got eaten. This must be due to a change in the newer versions of unity.
5. Lastly, in CompassActivity.java I had to comment out the if (Config.DEBUG) line in the onSensorChanged method (line 12ish). No idea why, but that was the final fix for me.
Thanks again for the tutorial! Its a bummer things keep changing to break it, but I learned a lot! 🙂 Very happy, and yes, Ill definitely be buying your games in support!
Glad to hear you got it working! Unity and Java both are in a constant state of change/update so it’s difficult to keep this article current and 100% correct. Thanks for adding how you got it working!
Hello!
Thank you very much, floatingcoder, I finally got it running!
My problem now is that I always get 0 values for x, y and z.
Any ideas about what can be happening?
Thank you very much in advance!
Ok. Now I am really confused. After a lot of trials I have ended with just this code:
public class CompassActivity extends UnityPlayerActivity
{
private static final String TAG = “Compass”;
static public float xmag = 2;
@Override
protected void onCreate(Bundle icicle)
{
super.onCreate(icicle);
xmag = 3;
}
@Override
protected void onResume()
{
super.onResume();
}
@Override
protected void onStop()
{
super.onStop();
}
public static float getX()
{
return xmag;
}
}
When I call the getX method from Unity, I find out that ¡¡¡Xmag=2!!!. I don’t know why but it is not even calling the oncreate method.
Any help would be very appreciated.
great tutorial! its the best one on the interne so far!! it helped alot!! thanx!!
Hey, for some reason the code is cut off for me on step 2 and 4. Is there another website that I could view this tutorial or is there a way that you could email it to me?
Odd… Here you go!
Step 2: Writing our Java plugin
In the Plugins\Android\src folder create a new file called CompassActivity.java. Open this with your favorite text editor.
Copy and paste the Java code below but know that you’re going to have to change the package to the namespace we created in step 1:
package com.yourcompany.yourgamename;
import com.unity3d.player.UnityPlayerActivity;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.util.Config;
import android.util.Log;
import android.app.Activity;
public class CompassActivity extends UnityPlayerActivity {
private static final String TAG = “Compass”;
private SensorManager mSensorManager;
private Sensor mSensor;
static public float xmag;
static public float ymag;
static public float zmag;
private final SensorEventListener mListener = new SensorEventListener() {
public void onSensorChanged(SensorEvent event) {
if (Config.DEBUG) Log.d(TAG,
“sensorChanged (” + event.values[0] + “, ” + event.values[1] + “, ” + event.values[2] + “)”);
xmag = event.values[0];
ymag = event.values[1];
zmag = event.values[2];
}
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
};
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
mSensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE);
mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
}
@Override
protected void onResume()
{
if (Config.DEBUG) Log.d(TAG, “onResume”);
super.onResume();
mSensorManager.registerListener(mListener, mSensor,
SensorManager.SENSOR_DELAY_GAME);
}
@Override
protected void onStop()
{
if (Config.DEBUG) Log.d(TAG, “onStop”);
mSensorManager.unregisterListener(mListener);
super.onStop();
}
public static float getX() {
return xmag;
}
public static float getY() {
return ymag;
}
public static float getZ() {
return zmag;
}
}
Once you’ve changed the package namespace and saved the file, open a command prompt and cd to the src directory. We’re going to run the following java commands to compile, sign, and jar our plugin: (note: You may need to alter the classpath and bootclasspath to match your system)
1.> javac CompassActivity.java -classpath C:\Program Files (x86)\Unity\Editor\Data\PlaybackEngines\androidplayer\bin\classes.jar -bootclasspath C:\android-sdk-windows\platforms\android-8\android.jar -d .
2.> javap -s com.yourcompany.yourgamename.CompassActivity
3.> jar cvfM ../Compass.jar com/
Once you’ve finished those three steps you should now have a file called Compass.jar in your Plugins\Android\ folder.
Step 3: Setting up our AndroidManifest.xml
The AndroidManifest.xml is very important. When your Unity App launches on the Android device, this file will tell it to load our .jar file instead of the UnityPlayer.jar file. Our jar file takes over because it extends the UnityPlayer Activity (which loads the UnityPlayer Activity). You’ll want to create the file AndroidManifest.xml in our \Plugins\Android folder. (Note: Don’t forget to change your package here as well)
Step 4: Accessing the Plugin from Unity
At this point we could build our application and push it to our phone and everything would work correctly, but we haven’t pulled any information out of it. If you look at the Java code I’ve written three methods called GetX, GetY, and GetZ. We’re going to call those methods from Unity and get the output (which in turn will give us the X, Y, and Z values from the Magnetic Sensor). For this example we’re going to output the values to the GUI. First, create a new C# file (it doesn’t matter what you call it). Here’s what we need to put in it: (don’t forget to change the namespace)
using UnityEngine;
using System.Collections;
using System;
public class CompassJNI : MonoBehaviour {
static float xValue;
static float yValue;
static float zValue;
// Use this for initialization
void Start () {
AndroidJNI.AttachCurrentThread();
}
void Update() {
using (AndroidJavaClass cls_UnityPlayer = new AndroidJavaClass(“com.unity3d.player.UnityPlayer”)) {
using (AndroidJavaObject obj_Activity = cls_UnityPlayer.GetStatic(“currentActivity”)) {
AndroidJavaClass cls_CompassActivity = new AndroidJavaClass(“com.yourcompany.yourgamename.CompassActivity”);
cls_CompassActivity.CallStatic(“Init”, obj_Activity);
xValue = cls_CompassActivity.CallStatic(“getX”);
yValue = cls_CompassActivity.CallStatic(“getY”);
zValue = cls_CompassActivity.CallStatic(“getZ”);
}
}
Debug.Log(“Compass values are ” + xValue.ToString() + “,” + yValue.ToString() + “,” + zValue.ToString());
}
void OnGUI() {
GUI.Label(new Rect(Screen.width / 2 -200, Screen.height / 2, 400,100), “xmag = ” + xValue.ToString() + ” ymag = ” + yValue.ToString() + ” zmag = ” + zValue.ToString());
}
}
Hey all, seriously… these posts that you all made was great!
But as everybody here… i had my problems too.
So reading and re-reading all posts again and again… i finally got my own stuff working great! (hours after… sleep time lost… :P)
I’m using:
– Unity 3.5.5
– Android-15
– Java jdk1.6.0_17
So, here goes my solution to get this working:
1º – Do all the things as Timothy Johnson said at the beggining (using the last CompassActivity.java posted above).
-Remember to put Java’s Path in system enviroment Path.
-Put the “Pluging” folder inside the “Assets” folder, but i left a copy outside too, on the project folder.
2º – As floatingcoder said: In the android manifest file, change drawable/icon to drawable/app_icon (line 8ish) I think this is what Samuel was saying before, but his lines got eaten. This must be due to a change in the newer versions of unity.
3º – To use the Pluging and not crash, declare globals and iniciate them on Start. The values keeps updating still.
4º – Declare types, with “greater then” and “less then”, like in example below (which i used “[” “]” in place of “greater and lesser then”):
using UnityEngine;
using System.Collections;
using System;
public class ViewControl : MonoBehaviour {
private static float CompassX;
private static float CompassY;
private static float CompassZ;
private AndroidJavaClass cls_UnityPlayer;
private AndroidJavaObject obj_Activity;
private AndroidJavaClass cls_CompassActivity;
void Update ()
{
CompassX = cls_CompassActivity.CallStatic[float](“getX”);
CompassY = cls_CompassActivity.CallStatic[float](“getY”);
CompassZ = cls_CompassActivity.CallStatic[float](“getZ”);
Debug.Log(“Compass values are ” + CompassX.ToString() + “,” + CompassY.ToString() + “,” + CompassZ.ToString());
}
void Start ()
{
AndroidJNI.AttachCurrentThread();
cls_UnityPlayer = new AndroidJavaClass(“com.unity3d.player.UnityPlayer”);
obj_Activity = cls_UnityPlayer.GetStatic[AndroidJavaObject](“currentActivity”);
cls_CompassActivity = new AndroidJavaClass(“com.Seiva.WalkThrough.CompassActivity”);
cls_CompassActivity.CallStatic(“Init”, obj_Activity);
}
}
5º – Finally, remember old school times: http://en.wikipedia.org/wiki/Euler_angles
Iniciate = Initiate (portuguese-english messing up with me :D)
“com.Seiva.WalkThrough.CompassActivity” is my Company.GameName, remeber to change to yours….
Hope this help you guys!
Cya
Only one problem now…
When i turn my phone to horizontal (rotate the screen), the game crashes….
Anyone having the same? any fix ?
Ty
Hi,
I just wrote a article on my website:
http://romainpedra.fr/?p=149
It’s in french(yes i have translated your article but i made some code modifications on the Unity part) but i put link to your website and your games.
merci!
De rien / You’re welcome 😉
Hi, I updated my Unity to 3.5.6f4 and i have now an error on each frame:
10-12 13:57:18.731: E/Unity(2099): getMethodID(“Init”, “(Lcom.mycompany.mygame.CompassActivity;)V”) FAILED!
Do you know what is the problem?
y are you using cvfm it requires manifest file too where should i get it
hi, forget about my previous post i resolved the issue but its still not working its
i am using this code right now
using UnityEngine;
using System.Collections;
using System;
public class CompassJNI : MonoBehaviour {
static float xValue;
static float yValue;
static float zValue;
// Use this for initialization
void Start () {
AndroidJNI.AttachCurrentThread();
using (AndroidJavaClass cls_UnityPlayer = new AndroidJavaClass(“com.unity3d.player.UnityPlayer”)) {
using (AndroidJavaObject obj_Activity = cls_UnityPlayer.GetStatic(“currentActivity”)) {
AndroidJavaClass cls_CompassActivity = new AndroidJavaClass(“com.Mango.BurkaMadness.CompassActivity”);
/*cls_CompassActivity.CallStatic(“Init”, obj_Activity);
xValue = cls_CompassActivity.CallStatic(“getX”);
yValue = cls_CompassActivity.CallStatic(“getY”);
zValue = cls_CompassActivity.CallStatic(“getZ”);*/
}
}
}
void Update() {
Debug.Log(“Compass values are ” + xValue.ToString() + “,” + yValue.ToString() + “,” + zValue.ToString());
}
void OnGUI() {
GUI.Label(new Rect(Screen.width / 2 -200, Screen.height / 2, 400,100), “xmag = ” + xValue.ToString() + ” ymag = ” + yValue.ToString() + ” zmag = ” + zValue.ToString());
}
}
but its giving me an error in logcat
FATAL EXCEPTION: GLThread 10
java.lang.ClassNotFoundException: com.Mango.BurkaMadness.CompassActivity
at java.lang.Class.classForName(Native Method)
at java.lang.Class.forName(Class.java:234)
at java.lang.Class.forName(Class.java:181)
at com.unity3d.player.UnityPlayer.nativeRender(Native Method)
at com.unity3d.player.UnityPlayer.onDrawFrame(Unknown Source)
at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1363)
at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1118)
Caused by: java.lang.NoClassDefFoundError: com.Mango.BurkaMadness.CompassActivity
… 7 more
Caused by: java.lang.ClassNotFoundException: com.Mango.BurkaMadness.CompassActivity in loader dalvik.system.PathClassLoader[/mnt/asec/com.Mango.BurkaMadness-1/pkg.apk]
at dalvik.system.PathClassLoader.findClass(PathClassLoader.java:240)
at java.lang.ClassLoader.loadClass(ClassLoader.java:551)
at java.lang.ClassLoader.loadClass(ClassLoader.java:511)
… 7 more
as you can see my package name is correct i have crossed check it in java file and in player settings its same
thanks
forget about this too i created a folder in unity editor by the name of assets instead of it i should have moved the plugins folder to assets folder in directory structure in the first place.
Thanks for the great article its really helpfull
After completing Step3 i tried to build my app but received and error. 😦
Failed to re-package resources with the following parameters:
package -v -f -m -J gen -M AndroidManifest.xml -S “res” -I “C:/Users/sumit/Documents/android-sdk-windows/platforms/android-16\android.jar” -F bin/resources.ap_
I followed each step correctly.. Anyone having same issues…
Hey Thanks ……….Got it working……
Is there any way to build this plugin on latest JDK and android version….
Thanks again.. 🙂
Can you send me the sample project? I am not getting it work.
I’m afraid that the sample project would only be using whatever project namespace I’m using, meaning that you wouldn’t be able to use the .jar files in your own project.
i just want to check how it works, and I have done all and working fine only if i first export my project to eclipse and then build. Can anybody explain why this is so?
D:\UTIL\Unity3d\Grow\Unity\Assets\Plugins\Android\src>javac CompassActivity.java
-classpath C:\Program Files (x86)\Unity\Editor\Data\PlaybackEngines\androidplay
er\bin\classes.jar -bootclasspath D:\adt-bundle\sdk\platforms\android-17\android
.jar -d .
javac: invalid flag: (x86)\Unity\Editor\Data\PlaybackEngines\androidplayer\bin\c
lasses.jar
Usage: javac
use -help for a list of possible options
–>
D:\UTIL\Unity3d\Grow\Unity\Assets\Plugins\Android\src>javac CompassActivity.java
-classpath “C:\Program Files (x86)\Unity\Editor\Data\PlaybackEngines\androidplay
er\bin\classes.jar” -bootclasspath D:\adt-bundle\sdk\platforms\android-17\android
.jar -d .
i attached “C:\Program Files ~~~~”
wow im so silly …
have a nice day~~ ^^ Thanx
Hi great tutorial,
i’ve done your steps without compiling errors or issues, but on the eclipse emulator it crashes at the start (on my phone too) and logcat says:
unable to instantiate activity componentinfo {…}: java.lang.classnotfoundexception
Where could be the mistake?
GREAT tutorial~~ I’ve tried it and it really works, but there are some tips if you want to run it under Unity 4.x
1. I guess the code was designed for Unity 3.x when the classes.jar still work. For Unity 4.x, you have to find a classes.jar from Unity 3.x and use that one to compile.
2. In Unity 4.x, the GetStatic should have return type specified, GetStatic()