您的位置:首页 > 其它

第一个NDK程序

2011-08-20 22:18 183 查看
之前写了第一个JNI程序,有翻译了一篇NDK的入门教程,今天从头到尾自己写了一个。

环境:linux+ndk r6

开始之前:java和ndk的环境变量已经设置好

目标:一个简单的例子,从c中传给java int数组和字符串数组

开始:

新建一个项目,名称为FirstNDK

一个包是package com.linc.FirstNDK;放activity

另一个是package com.linc.lib;放lib文件,主要处理jni

布局:两个按钮+一个textview

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
<Button
	android:id="@+id/btnOne"
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="int Array!"
/>
<TextView  
	android:id="@+id/Result"
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="Result:"
    />
<Button
	android:id="@+id/btnTwo"
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="string Array!"
/>    
</LinearLayout>
package com.linc.lib包下新建一个类FirstLib

package com.linc.lib;

public class FirstLib {
	// Native implementation  
	static {  
	System.loadLibrary("FirstLib"); 
	}  
	
	//传递数组
	public static native int[] intMethod();
	//传递字符串数组
	public static native String[] stringMethod();
}
这里主要有两个本地方法,

下面用它生成jni的头文件:用终端来到项目bin目录(前提是FirstLib这个类已经编译完成),

[linc@localhost bin]$ javah -jni com.linc.lib.FirstLib
项目中新建一个jni目录,用来存放jni相关文件,并把刚刚生成的头文件放进去

[linc@localhost bin]$ mv com_linc_lib_FirstLib.h ../jni
在jni中新建一个c文件与上面的对应叫FirstLib.c,

#include "com_linc_lib_FirstLib.h"
const static int length=10;

//传递整型数组
JNIEXPORT jintArray JNICALL Java_com_linc_lib_FirstLib_intMethod
  (JNIEnv *env, jclass obj)
{
	jintArray array;//数组
	array=(*env)->NewIntArray(env,10);
	int i=1;
	for(;i<=10;++i)
	{
		(*env)->SetIntArrayRegion(env,array,i-1,1,&i);
	}

	//获取数组长度
	int len=(*env)->GetArrayLength(env,array);

	//获得数组中的所有元素
	jint* elems=(*env)->GetIntArrayElements(env,array,0);

	return array;
}

//字符串数组
JNIEXPORT jobjectArray JNICALL Java_com_linc_lib_FirstLib_stringMethod
  (JNIEnv *env, jclass obj)
{
	jclass class=(*env)->FindClass(env,"java/lang/String");
	jobjectArray string=(*env)->NewObjectArray(env,(jsize)length,
			class,0);
	jstring jstr;
	char* _char[]={"my ","name ","is ",
					"linc!!","正在","学习",
					"JNI","和","NDK","技术!"
					};
	int i=0;
	for(;i<length;++i)
	{
		jstr=(*env)->NewStringUTF(env,_char[i]);
		(*env)->SetObjectArrayElement(env,string,i,jstr);
	}

	return string;
}


在jni目录下新建一个mk文件,Android.mk

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := FirstLib
LOCAL_SRC_FILES := FirstLib.c
include $(BUILD_SHARED_LIBRARY)


好,下面将其编译成共享库:回到项目目录

[linc@localhost FirstNDK]$ cd ..
[linc@localhost FirstNDK]$ ndk-build
Compile thumb  : FirstLib <= FirstLib.c
SharedLibrary  : libFirstLib.so
Install        : libFirstLib.so => libs/armeabi/libFirstLib.so


下面在activity中调用之:

package com.linc.FirstNDK;

import java.io.UnsupportedEncodingException;

import com.linc.lib.FirstLib;
import com.linc.lib.PersonalInfo;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class FirstNDK extends Activity {
	TextView textResult;  
	Button buttonOne;  
	Button buttonTwo;
	
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        textResult = (TextView) findViewById(R.id.Result);  
        buttonOne = (Button) findViewById(R.id.btnOne);  
        buttonOne.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {
				// TODO Auto-generated method stub
				int[] nums=FirstLib.intMethod();
				for(int i=0;i<nums.length;++i)
				{
					textResult.append("  "+nums[i]);
				}
			}
		}); 
        
        buttonTwo = (Button) findViewById(R.id.btnTwo);  
        buttonTwo.setOnClickListener(btnTwo_Click);
    }
    
    private OnClickListener btnTwo_Click = new OnClickListener()
    {
    	public void onClick(View v)
    	{    		
    		String[] string=FirstLib.stringMethod();
    		for(int i=0;i<string.length;++i)
    		{
    			try {
    				string[i]=new String(string[i].getBytes("gb2312"),"GBK");
    			} catch (UnsupportedEncodingException e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			}
    			textResult.append("  "+string[i]);
    		}
    	}
    };
	
}
最后就可以运行看效果了!

ndk的使用,首先要具备jni的相关知识,在本blog中有相关记载。

希望大家用ndk来开发游戏时,玩的开心!

后记:

1.ndk 未找到。。。类的错误。

今天发现这个错误,主要是因为项目bin路径下还有一层classes。如下处理就可以了:

~/workspace/TestNDK/bin$ javah -classpath ./classes -d ./jni com.linc.lib.FirstLib


2.loadlibrary相关

Android.mk 可以这样写(摘自cocos2d-x中的demo):

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := game_shared

LOCAL_MODULE_FILENAME := libgame

LOCAL_SRC_FILES := hellocpp/main.cpp \
                   ../../Classes/AppDelegate.cpp \
                   ../../Classes/HelloWorldScene.cpp \
                   ../../Classes/GameOverScene.cpp
                   
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../Classes                   

LOCAL_WHOLE_STATIC_LIBRARIES := cocos2dx_static cocosdenshion_static
            
include $(BUILD_SHARED_LIBRARY)

$(call import-module,CocosDenshion/android)
$(call import-module,cocos2dx)
LOCAL_MODULE 是game_shared,如果没有定义LOCAL_MODULE_FILENAME,那么编译出来的so就是libgame_shared.so,

而在java文件中load时就必须要

static {
        System.loadLibrary("game_shared");
    }
有趣的是,定义LOCAL_MODULE_FILENAME为libgame后,编译出来的so当然是libgame.so了,而java中load “game”就可以了。

3.NDK r7之后直接对编译的支持

在整理NDK r7的特性时,直接提供对编译的支持,在windows下就不用cygwin了。

现在我已经使用r9b了,项目右键--->Android Tools--->Add Native Support...

你会发现帮你添加了jni的文件夹,并且项目属性中在Builders里面有多了两项,一个是CDT Builder,一个是Scanner Configuration Builder。

更贴心的,属性都为你设置好了,直接添加编辑你的C、C++代码吧。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: