IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    [原]第一个NDK程序

    lincyang发表于 2011-08-20 22:18:23
    love 0

    之前写了第一个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++代码吧。






沪ICP备19023445号-2号
友情链接