There are many Android NDK tutorials out there, but sometimes I feel they do things the hard way, and you end up disgusted, programming in plain old Java again, because getting all that JNI stuff working is so hard. But before you start using NDK, ask first if you really need it. I have found three valid reasons (well, reasons I consider valid, everything depends on your case)
- Write once, run everywhere. That is Java's motto, but actually native code is going to run on more devices than your Java. If you write your game proper in C/C++, you automatically have to create some sort of device interface to make it work under android, because in NDK you can not access the Android input and UI APIs (actually 2.3 supports that, but we are going to target 1.6). It is on you, where you draw the line.
- Using native libraries. If they have a Java binding, they probably do not have one for Android.
- Speed is the least important factor. Not many games are CPU bound and unless you are doing heavy physics simulation, it is not going to be an important factor.
All three points summed up are quite a big reason to write native code.
Simple JNI, the hard way
I assume you can make a sample OpenGL application. Make a simple project in Eclipse with just one activity and GLSurfaceView. The renderer might look similar to this:
public void onSurfaceCreated(GL10 gl, EGLConfig config)
{
activity.surfaceCreatedNativeCallback();
}
public void onSurfaceChanged(GL10 gl, int width, int height)
{
if(height == 0) {
height = 1;
}
gl.glViewport(0, 0, width, height);
}
public void onDrawFrame(GL10 gl) {
gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
}
Let's call our activity cz.badroid.FooActivity. We will define the surfaceNativeCallback like this:
public native void surfaceCreatedNativeCallback();
There is no method body, because, we are going to implement it in native code. Download android
NDK and extract it to folder we will call %NDKHOME% from now on. Create a directory called jni in your Eclipse project(on the same level as those src, res directories) and add two files there:
Android.mk:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := yourlibname
LOCAL_SRC_FILES := main.cpp
LOCAL_LDLIBS := -llog -lGLESv1_CM
include $(BUILD_SHARED_LIBRARY)
main.cpp:
#include <GLES/gl.h>
extern "C"{
JNIEXPORT void JNICALL Java_cz_badroid_FooActivity_surfaceCreatedNativeCallback
(JNIEnv * env, jobject activity)
{
glClearColor(0,0,1,1);
}
}
Now just build it by running %NDKHOME%/ndk-build in the jni directory. You have just set GL Clear Color in native code! There are common problems and misconeceptions:
- You need a JNI_OnLoad method. No you do not, but it is recommended, so that you can check if your library is being loaded.
- You need to register native methods -- no that's not needed at all.
- The Android Eclipse project does not depend on the jni libs. That means that whenever you rebuild your NDK project, you also have to make sure your parent Eclipse project is rebuilt. I do it by "touch ../AndroidManifest.xml"
The SWIG way
Just imagine writing a JNI methods for all your engine's methods(and converting all the parameters).... Ufff.... The javah tool will help you a little, but it works the other way around, it generates a native code for Java one.
The answer is SWIG -- Simple Wrapper and Interface Generator. There is also other tool, called gluegen, but it works only for plain C. There is our new set of files(I have not tried to compile them, I hope they work):
main.cpp:
#include "main.h";
#include <GLES/gl.h>
void NativeComponent::testNativeMethod(){
glClearColor(0,0,1,1);
}
main.h:
#ifndef MAIN_H
#define MAIN_H
class NativeComponent{
public:
void testNativeMethod();
};
#endif
Android.mk:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := yourlibname
LOCAL_SRC_FILES := main.cpp bindings_wrap.cxx
LOCAL_LDLIBS := -llog -lGLESv1_CM
include $(BUILD_SHARED_LIBRARY)
bindings.i:
%module nativecomponent
%{
/* Includes the header in the wrapper code */
#include "main.h"
%}
/* Parse the header file to generate wrappers */
%include "main.h"
That's it. Now we can generate all the bindings by calling:
swig -c++ -java -package cz.badroid.bindings -outdir ../src/cz/badroid/bindings/ bindings.i
Now you can do in your Java code:
BlogThis!Sdílet ve službě FacebookSdílet na Pinterestu