Build and use libgdx for x86 in Android Studio

Jul 06

So I went through this morning and figured out how to get libgdx compiled for x86 and running in Android Studio. It’s a bit of a PITA to figure out, but pretty easy to do once you know how.

Run libgdx for x86 in Android Studio

This will enable you to use libgdx in the Android Emulator with an x86 image. Add in HAX and you should be able to get pretty decent performance.

I. Install the Android NDK

  1. Download the NDK for 64-bit OSX: http://developer.android.com/tools/sdk/ndk/
  2. Unzip the NDK to your Desktop, which should produce a folder named android-ndk-r8e. (You may move this someplace else, but if you do then you’ll need to change a few paths later.)
  3. Don’t touch anything else. It should work out of the box.

II. Compile libgdx shared objects

  1. Open Terminal.
  2. Clone the libgdx repo (do not just use the zip):

    cd ~/Desktop
    git clone git@github.com:libgdx/libgdx.git
    
  3. In the libgdx folder, create or edit gdx/jni/Application.mk to include:

    APP_ABI := armeabi armeabi-v7a x86
    
  4. Run ndk-build in that jni folder:

    cd ~/Desktop/libgdx/gdx/jni
    ~/Desktop/android-ndk-r8e/ndk-build
    

    You should see a whole bunch of Compile... lines for arm and x86.

  5. When the build finishes, check the libgdx/gdx/libs folder. You should now have folders for armabi, armabi-v7a, and x86. Each folder should have a libgdx.so file in it.

III. Compile libandroidgl20 shared objects

This is the same process as before.

  1. In Terminal, clone the gl2-android repository:

    cd ~/Desktop
    svn checkout http://gl2-android.googlecode.com/svn/trunk/gl2-android
    
  2. In the gl2-android folder, create or edit jni/Application.mk to include:

    APP_ABI := armeabi armeabi-v7a x86
    
  3. Run ndk-build in that jni folder:

    cd ~/Desktop/gl2-android/jni
    ~/Desktop/android-ndk-r8e/ndk-build
    
  4. When the build finishes, check the gl2-android/libs folder. You should now have folders for armabi, armabi-v7a, and x86. Each folder should have a libandroidgl20.so file in it.

IV. Package the shared objects

  1. On your Desktop, create a new folder named lib.
  2. From your libgdx/gdx/libs folder, move the three armabi, armabi-v7a, and x86 folders into into the new lib folder.
  3. From your gl2-android/libs folder, move each .so file into its matching folder in the lib folder you created above. You should have each of the libgdx.so files sitting next to its matching libandroidgl20.so file.
  4. Right-click the lib folder and choose “Compress”. This should produce a lib.zip file.
  5. Rename lib.zip to gdx-so.jar. Finder may ask to confirm that you want to change the extension from .zip to .jar, which is okay.

V. Add the JAR to your Android Studio project

  1. Drag the gdx-so.jar file into the libs folder inside your Android Studio project. (It should already have the android-support-v4.jar in it.) You will probably be asked to confirm the move, which is okay.
  2. If you haven’t already done so, do the same for the gdx.jar and gdx-backend-android.jar files you get from the official libgdx download.
  3. Go into your “Project Structure” window by using the File > Project Structure menu.
  4. In the Project Settings menu, select the Libraries option.
  5. Use the + button to add a new Java library. When asked to select files, navigate to your gdx-so.jar file, select it, and use OK to add it.
  6. Repeat the last step for your gdx.jar and gdx-backend-android.jar if you have not already done so.
  7. In the Project Settings menu, select the Modules option.
  8. For each project in the middle list: a. Select the project. b. Select the Dependencies tab on the right. c. Use the + button to add the Library items you just created for your JARs. d. Check the Export box for each.
  9. Use Apply or OK to apply your changes.
  10. Rebuild the project using the Build > Rebuild Project menu.

VI. Use libgdx in one of your activities

  1. Open an activity .java source file.
  2. Do something similar to:

    package com.example.mygame;
    import android.os.Bundle;
    import android.view.Menu;
    import com.badlogic.gdx.backends.android.AndroidApplication;
    import com.badlogic.gdx.backends.android.AndroidApplicationConfiguration;
    public class GameActivity extends AndroidApplication {
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            AndroidApplicationConfiguration cfg = new AndroidApplicationConfiguration();
            cfg.useGL20 = true;
            initialize(new MyGame(), cfg);
        }
    }
    
  3. Your game’s .java source should be something like:

    package com.example.mygame;
    import com.badlogic.gdx.ApplicationListener;
    import com.badlogic.gdx.Gdx;
    import com.badlogic.gdx.graphics.GL10;
    import com.badlogic.gdx.graphics.OrthographicCamera;
    import com.badlogic.gdx.graphics.Texture;
    import com.badlogic.gdx.graphics.Texture.TextureFilter;
    import com.badlogic.gdx.graphics.g2d.Sprite;
    import com.badlogic.gdx.graphics.g2d.SpriteBatch;
    import com.badlogic.gdx.graphics.g2d.TextureRegion;
    public class MyGame implements ApplicationListener {
        private OrthographicCamera camera;
        private SpriteBatch batch;
        private Texture texture;
        private Sprite sprite;
        @Override
        public void create() {
            float w = Gdx.graphics.getWidth();
            float h = Gdx.graphics.getHeight();
            camera = new OrthographicCamera(1, h/w);
            batch = new SpriteBatch();
            texture = new Texture(Gdx.files.internal("data/libgdx.png"));
            texture.setFilter(TextureFilter.Linear, TextureFilter.Linear);
            TextureRegion region = new TextureRegion(texture, 0, 0, 512, 275);
            sprite = new Sprite(region);
            sprite.setSize(0.9f, 0.9f * sprite.getHeight() / sprite.getWidth());
            sprite.setOrigin(sprite.getWidth()/2, sprite.getHeight()/2);
            sprite.setPosition(-sprite.getWidth()/2, -sprite.getHeight()/2);
        }
        @Override
        public void dispose() {
            batch.dispose();
            texture.dispose();
        }
        @Override
        public void render() {
            Gdx.gl.glClearColor(1, 1, 1, 1);
            Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
            batch.setProjectionMatrix(camera.combined);
            batch.begin();
            sprite.draw(batch);
            batch.end();
        }
        @Override
        public void resize(int width, int height) {
        }
        @Override
        public void pause() {
        }
        @Override
        public void resume() {
        }
    }
    
  4. If you need to, copy the data folder from the libgdx zip or repo, and the libgdx.png within it, to your src/main/assets/ folder in your project.

  5. Rebuild and run your app using the Run menu.
  6. Choose a virtual device using an intel (x86) image.
  7. When the activity opens you should see the libgdx test graphic on a white background.