JME3 from Eclipse, target Android

Hi,
I’m new to JME3, so I’m experimenting with different possible workflows, test codes etc. I’ve used the JME3 SDK for 3 days now, and it works just fine, deployed the test samples on Android, no issues there. However, I’ve been using Eclipse for 2 years now, and I just wanted to check if I can keep working with Eclipse and use JME3 for Android.

What I did was this:

  1. Created new Android project on Eclipse (the latest Android Bundle thingy)
  2. Added all needed libraries from JME3 latest nightly build (06/12/2012)
  3. Created 2 public classes MainActivity and Test.
    MainActivity has the onCreate method Android needs.
    Test is the public class with JME3 code, extending SimpleApplication. The code here is the Hello SimpleApplication give in the tutorial.
    4.From within the onCreate of MainActivity I instantiated the Test class object.

All of this compiled correctly. I connected my Android device and hit Run.
The app opened on phone, but crashed with an exception. In the ADB Logcat , I could see that it’s a ClassNotFoundException, that occurred in MainActivity, when I tried to instantiate Test (JME3 Class).

Then I removed all JME3 reference from my Test class, and just made it toast “Hello”, and ran again. This time it ran all correctly (obviously this is just a simple android app, no JME3 reference, but it proves that class Test can be found :stuck_out_tongue: )

So basically, when I extend Test with SimpleApplication and add JME3 code, I get the ClassNotFound exception. Weird?
I know I can do all my work with JMonkey3 SDK, and I’ve done that. It’s just a nagging factor that I’ve been unable to get the combination “JME3+Eclipse+Android” to work properly. It’s good to have multiple options in hand when it comes to having a workflow.

Here’s the code:
MainActivity.java:

[java]
package com.hello.jme3test;

import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;

import com.jme3.app.SimpleApplication;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Box;

public class MainActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	//setContentView(R.layout.activity_main);
	
	Test T = new Test();
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
	// Inflate the menu; this adds items to the action bar if it is present.
	//getMenuInflater().inflate(R.menu.activity_main, menu);
	return true;
}

}
[/java]

Test.java

[java]
package com.hello.jme3test;

import com.jme3.app.SimpleApplication;

public class Test extends SimpleApplication
{
public Test()
{
System.out.println(“hellooooo”);
}

@Override
public void simpleInitApp() {
	// TODO Auto-generated method stub
}

}
[/java]

Thanks,
Sanjeev Mk

You need to leave out all desktop related jars and include the android jar, also you have to set up the natives for bullet if you want to use it and use the native bullet jar. Additionally you have to extend the com.jme3.app.AndroidHarness class instead of Activity.
https://wiki.jmonkeyengine.org/legacy/doku.php/jme3:jme3_source_structure#structure_of_jmonkeyengine3_jars

However, in the SDK you can run your application on desktop to debug and then switch to android and run it in the emulator or on a device, additionally you can distribute the same app to desktop, web and in a few months also iOS. This will not work in eclipse :slight_smile: You can set the keyboard shortcuts in the SDK to the Eclipse configuration, then you will find out theres virtually no difference between the two applications, I use both regularly.

Hi,
Doing now as you suggested, I referenced only jme3-android, jme3-core and jme-android-bullet. And also extended AndroidHarness. However, when my MainActivity extends AndroidHarness, DVM is unable to load the MainActivity itself and throws an exception.

First I thought it’s a VM problem, so I played around with my -xms and -xms values, didn’t work.

Yes, I’m working with the JME3 SDK only now, so no gating of work. :slight_smile:

So, yeah, how about posting that exception?

Here you go:

[java]
12-14 22:06:09.639: E/AndroidRuntime(18148): FATAL EXCEPTION: main
12-14 22:06:09.639: E/AndroidRuntime(18148): java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{com.jme3.test.jme3test/com.jme3.test.jme3test.MainActivity}: java.lang.ClassNotFoundException: com.jme3.test.jme3test.MainActivity in loader dalvik.system.PathClassLoader[/data/app/com.jme3.test.jme3test-2.apk]
12-14 22:06:09.639: E/AndroidRuntime(18148): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1575)
12-14 22:06:09.639: E/AndroidRuntime(18148): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1669)
12-14 22:06:09.639: E/AndroidRuntime(18148): at android.app.ActivityThread.access$1500(ActivityThread.java:117)
12-14 22:06:09.639: E/AndroidRuntime(18148): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:931)
12-14 22:06:09.639: E/AndroidRuntime(18148): at android.os.Handler.dispatchMessage(Handler.java:99)
12-14 22:06:09.639: E/AndroidRuntime(18148): at android.os.Looper.loop(Looper.java:130)
12-14 22:06:09.639: E/AndroidRuntime(18148): at android.app.ActivityThread.main(ActivityThread.java:3737)
12-14 22:06:09.639: E/AndroidRuntime(18148): at java.lang.reflect.Method.invokeNative(Native Method)
12-14 22:06:09.639: E/AndroidRuntime(18148): at java.lang.reflect.Method.invoke(Method.java:507)
12-14 22:06:09.639: E/AndroidRuntime(18148): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:894)
12-14 22:06:09.639: E/AndroidRuntime(18148): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:652)
12-14 22:06:09.639: E/AndroidRuntime(18148): at dalvik.system.NativeStart.main(Native Method)
12-14 22:06:09.639: E/AndroidRuntime(18148): Caused by: java.lang.ClassNotFoundException: com.jme3.test.jme3test.MainActivity in loader dalvik.system.PathClassLoader[/data/app/com.jme3.test.jme3test-2.apk]
12-14 22:06:09.639: E/AndroidRuntime(18148): at dalvik.system.PathClassLoader.findClass(PathClassLoader.java:240)
12-14 22:06:09.639: E/AndroidRuntime(18148): at java.lang.ClassLoader.loadClass(ClassLoader.java:551)
12-14 22:06:09.639: E/AndroidRuntime(18148): at java.lang.ClassLoader.loadClass(ClassLoader.java:511)
12-14 22:06:09.639: E/AndroidRuntime(18148): at android.app.Instrumentation.newActivity(Instrumentation.java:1021)
12-14 22:06:09.639: E/AndroidRuntime(18148): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1567)
12-14 22:06:09.639: E/AndroidRuntime(18148): … 11 more
12-14 22:06:09.649: E/AndroidRuntime(18148): [Blue Error Handler] Make Debugging Report file for main
12-14 22:06:09.649: E/AndroidRuntime(18148): java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{com.jme3.test.jme3test/com.jme3.test.jme3test.MainActivity}: java.lang.ClassNotFoundException: com.jme3.test.jme3test.MainActivity in loader dalvik.system.PathClassLoader[/data/app/com.jme3.test.jme3test-2.apk]
12-14 22:06:09.649: E/AndroidRuntime(18148): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1575)
12-14 22:06:09.649: E/AndroidRuntime(18148): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1669)
12-14 22:06:09.649: E/AndroidRuntime(18148): at android.app.ActivityThread.access$1500(ActivityThread.java:117)
12-14 22:06:09.649: E/AndroidRuntime(18148): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:931)
12-14 22:06:09.649: E/AndroidRuntime(18148): at android.os.Handler.dispatchMessage(Handler.java:99)
12-14 22:06:09.649: E/AndroidRuntime(18148): at android.os.Looper.loop(Looper.java:130)
12-14 22:06:09.649: E/AndroidRuntime(18148): at android.app.ActivityThread.main(ActivityThread.java:3737)
12-14 22:06:09.649: E/AndroidRuntime(18148): at java.lang.reflect.Method.invokeNative(Native Method)
12-14 22:06:09.649: E/AndroidRuntime(18148): at java.lang.reflect.Method.invoke(Method.java:507)
12-14 22:06:09.649: E/AndroidRuntime(18148): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:894)
12-14 22:06:09.649: E/AndroidRuntime(18148): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:652)
12-14 22:06:09.649: E/AndroidRuntime(18148): at dalvik.system.NativeStart.main(Native Method)
12-14 22:06:09.649: E/AndroidRuntime(18148): Caused by: java.lang.ClassNotFoundException: com.jme3.test.jme3test.MainActivity in loader dalvik.system.PathClassLoader[/data/app/com.jme3.test.jme3test-2.apk]
12-14 22:06:09.649: E/AndroidRuntime(18148): at dalvik.system.PathClassLoader.findClass(PathClassLoader.java:240)
12-14 22:06:09.649: E/AndroidRuntime(18148): at java.lang.ClassLoader.loadClass(ClassLoader.java:551)
12-14 22:06:09.649: E/AndroidRuntime(18148): at java.lang.ClassLoader.loadClass(ClassLoader.java:511)
12-14 22:06:09.649: E/AndroidRuntime(18148): at android.app.Instrumentation.newActivity(Instrumentation.java:1021)
12-14 22:06:09.649: E/AndroidRuntime(18148): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1567)
12-14 22:06:09.649: E/AndroidRuntime(18148): … 11 more
[/java]

Well did you set up an android project with eclipse? Obviously you have to do that as like I said, Eclipse doesn’t support multiple deployment targets.

Yes, I did create an Android Project with Eclipse. Eclipse auto-created the activity class, extending from Activity. I also changed this to be extended from AndroidHarness instead.

The goal here is to use JME purely as a library. So linking my project to the library and instantiating the object should have worked.
The code is building properly, so there’s no syntax issue. DVM is unable to link to the library during run time.

Phew, finally made it work, happy! May be this is an issue with the latest Android SDK Bundle.

What I had to do was:

  1. Copy relevant JME3 jar files inside the “libs” folder of your Eclipse project in your Workspace. Having these JAR files outside the “libs” folder causes the above mentioned runtime exception.
  2. Extend from AndroidHarness and set the “appClass” variable of AndroidHarness to the JME3 class that extends SimpleApplication. Do not do this in onCreate, do this in a constructor or another function of the main android Activity class.
  3. Then run the app and enjoy, it works!

So the fix was to have jar files inside the Eclipse workspace libs folder.

So, if you want to use JME purely as a set of library calls from Eclipse, these are the steps:

  1. Create New Android Project.
  2. Copy the necessary JME3 jars inside the “libs” folder of your project inside the Eclipse workspace. You will now see these jars under ‘libs’ in your Eclipse project explorer.
  3. Add a new class to your package. This class should extend SimpleApplication, and this is where all your JME3 work should begin. In order to start the game, just do a “this.start()” call inside the constructor of this call.
  4. Step 1 must have auto created a main activity class that extends Activity. Change this to extend AndroidHarness instead.
  5. Inside onCreate , comment out the setContentView call that was auto-created by 1, as we don’t need this call.
  6. Create a constructor inside your Activity class, or create another function inside your main activity and have it called from onCreate. Inside this constructor or another function, set the appClass variable to the class you created in step 3 , the one that extends SimpleApplication. Specify this name in the long format (packageName.className)
  7. Build and Run.

Here is my final code.

MainActivity.java:
[java]
package com.jme3.test.jme3test;

import android.os.Bundle;
import android.view.Menu;
import com.jme3.app.AndroidHarness;

public class MainActivity extends AndroidHarness {

@Override
public void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
}

public MainActivity()
{
	appClass = "com.jme3.test.jme3test.SimpleApp";
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
	// Inflate the menu; this adds items to the action bar if it is present.
	//getMenuInflater().inflate(R.menu.activity_main, menu);
	return true;
}

}
[/java]

SimpleApp.java:
[java]
package com.jme3.test.jme3test;

import com.jme3.app.SimpleApplication;
import com.jme3.material.Material;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Box;
import com.jme3.math.ColorRGBA;

/** Sample 1 - how to get started with the most simple JME 3 application.

  • Display a blue 3D cube and view from all sides by

  • moving the mouse and pressing the WASD keys. */
    public class SimpleApp extends SimpleApplication {

    public SimpleApp(){
    this.start(); // start the game
    }

    @Override
    public void simpleInitApp() {
    Box b = new Box(Vector3f.ZERO, 1, 1, 1); // create cube shape at the origin
    Geometry geom = new Geometry(“Box”, b); // create cube geometry from the shape
    Material mat = new Material(assetManager,
    “Common/MatDefs/Misc/Unshaded.j3md”); // create a simple material
    mat.setColor(“Color”, ColorRGBA.Blue); // set color of material to blue
    geom.setMaterial(mat); // set the cube’s material
    rootNode.attachChild(geom); // make the cube appear in the scene
    }
    }
    [/java]

Note that copying the jars inside the project, seriously bloats the game size!! :frowning: So we still don’t know why it’s unable to link during runtime and needs it at build time only. Hence, obviously, the best way is to use JME3 SDK :slight_smile:

Hello.
I followed the “sanjeevmk” steps, but I have errors in the LogCat:

12-20 15:50:24.000: W/dalvikvm(2559): threadid=9: thread exiting with uncaught exception (group=0xb3fd14f0) 12-20 15:50:24.000: E/AndroidHarness(2559): Exception thrown in Thread[GLThread 12,5,main] 12-20 15:50:24.000: E/AndroidHarness(2559): java.lang.StringIndexOutOfBoundsException: String index out of range: 18 12-20 15:50:24.000: E/AndroidHarness(2559): at java.lang.String.substring(String.java:1625) 12-20 15:50:24.000: E/AndroidHarness(2559): at com.jme3.renderer.android.OGLESShaderRenderer.extractVersion(OGLESShaderRenderer.java:141) 12-20 15:50:24.000: E/AndroidHarness(2559): at com.jme3.renderer.android.OGLESShaderRenderer.initialize(OGLESShaderRenderer.java:172) 12-20 15:50:24.000: E/AndroidHarness(2559): at com.jme3.system.android.OGLESContext.initInThread(OGLESContext.java:217) 12-20 15:50:24.000: E/AndroidHarness(2559): at com.jme3.system.android.OGLESContext.onSurfaceCreated(OGLESContext.java:189) 12-20 15:50:24.000: E/AndroidHarness(2559): at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1348) 12-20 15:50:24.000: E/AndroidHarness(2559): at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1118)

I use BlueStacks emulator.

Also I have some ClassNotFound problems when using string in appClass, use this method instead:
[java]appClass = com.jme3.test.jme3test.SimpleApp.class.getName();[/java]