android JNI 示例详解

android是使用java进行开发,但是在开发过程中可能会用到之前的c,c++代码,或者乳沟你想一套代码同时在iphone和android平台复用就会用到JNI啦。

JNI起的是一个桥梁的作用,可以转化java与c/c++的一些区别,比如数据类型等。之后我们将转换好的c代码生成动态链接库,供java调用。

下面以一个示例做说明,希望对刚接触的童鞋有所帮助。

1、安装NDK环境:这个可以参照我的前一篇文章“windows系统上安装与使用Android NDK r5”。这是一个童鞋写的,照着做就可以完全没有问题的安装好。

2、当你按照步骤1安装好环境后,比如安装在了D盘D:\android-ndk-r6,本文以下默认此路径,如果你的路径不同 做相应改变就好了。然后在D:\android-ndk-r6下新建apps文件夹,里面存放的就是你将来要搞的android jni 工程相关文件啦。

现在我在D:\android-ndk-r6\apps 下创建我的第一个工程目录Angry,注意这个Angry并不是你的android工程的根目录,在Angry下创建project文件,这下面存放的将是你的android工程。 以下是我的目录结构:

 

之所以这样是因为,大家可以看到在Angry下还有个Application.mk文件(下面讲这个文件的生成),这个文件里是我们将c/c++编译成动态链接库(.so)的时候需要使用到的配置信息。除这个文件外我们还会用到一个Android.mk文件,在下面会讲到。

3.好了,接下来就创建我们的android工程吧。创建Android工程,指定工程路径:D:\android-ndk-r6\apps\Angry\project,以下是我创建的工程:

              

创建好了之后就可以写我们的java接口了(相当于函数声明),真正的功能实现是要用c/c++实现的吆。你可以新建一个java文件,或者直接在你继承Activity的那个java中直接写,我是新建了一个Jni.java文件:

                                                               

Jni.java中的代码如下:
  1. <span style="font-family:Comic Sans MS;">package com.Angry;  
  2.   
  3. public class Jni {  
  4.     public native String getString ();  
  5. }  
  6. </span>  

注意接口要声明成native的吆。如果你不想单独放在一个文件中也可以直接放在MainAct.java中,将 public native String getString (); 放进去就好了。

4.生成头文件以及源文件:

将Jni.java复制到D:\android-ndk-r6\apps\Angry\project\bin下面,然后在D:\android-ndk-r6\apps\Angry\project\bin用“javac jni.java”编译生成Jni.class文件,将生成的Jni.class复制到 D:\android-ndk-r6\apps\Angry\project\bin\com\Angry下覆盖掉原先的Jni.class文件。

然后再在D:\android-ndk-r6\apps\Angry\project\bin(建个目录文件com/Angry目录,把class文件考进去)下使用命令 "javah -jni com.Angry.Jni" 这是将会在bin下生成一个com_Angry_Jni.h的头文件,大家可以看一下我的生成:、

  1. <span style="font-family:Comic Sans MS;color:#009900;">/* DO NOT EDIT THIS FILE - it is machine generated */  
  2. #include <jni.h>  
  3. /* Header for class com_Angry_Jni */  
  4.   
  5. #ifndef _Included_com_Angry_Jni  
  6. #define _Included_com_Angry_Jni  
  7. #ifdef __cplusplus  
  8. extern "C" {  
  9. #endif  
  10. /* 
  11.  * Class:     com_Angry_Jni 
  12.  * Method:    getString 
  13.  * Signature: ()Ljava/lang/String; 
  14.  */  
  15. JNIEXPORT jstring JNICALL Java_com_Angry_Jni_getString  
  16.   (JNIEnv *, jobject);  
  17.   
  18. #ifdef __cplusplus  
  19. }  
  20. #endif  
  21. #endif</span>  

其实就是将我们原先Jni.java中的public native String getString ();函数声明形式做了些许改动,使之符合JNI规则。

之后我们要在D:\android-ndk-r6\apps\Angry\project下即Android工程下新建jni文件夹,将com_Angry_Jni.h文件放入其中。这个jni文件夹将是盛放我们c/c++源文件以及头文件和Android.mk文件的场所。

接下来就是实现我们的函数功能了:新建c/c++源文件:com_Angry_Jni.c(同样放在jni文件夹下):

  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #includ"com_Angry_Jni.h"  
  4.   
  5. JNIEXPORT jstring JNICALL Java_com_Angry_Jni_getString  
  6.   (JNIEnv *env, jobject thiz) {  
  7.  return (*env)->NewStringUTF(env, "I,M ANGRY");  
  8. }  

像我就只是单纯的实现了返回一字符串的功能,具体功能大家可以自己添加。程序中的jstring 等数据类型其实jni对c/c++的数据类型做了形式的改变,jstring 就是String。

现在功能都实现好了,我们可以将上面的c代码编译成so文件供java调用(因为android是基于linux的,而linux的动态链接库文件是以.so为后缀,windows以.dll为后缀)。

5、编译生成.so文件需要两个.mk文件,就是我们上面提到的Application.mk文件和Android.mk,在D:\android-ndk-r6\apps\Angry\project\jni下创建Android.mk,内容如下:

  1. LOCAL_PATH := $(call my-dir)  
  2.   
  3. include $(CLEAR_VARS)  
  4.   
  5. LOCAL_MODULE    := Angry  
  6. LOCAL_SRC_FILES := com_Angry_Jni.c  
  7.   
  8. include $(BUILD_SHARED_LIBRARY)  


LOCAL_PATH: 表示位于工程的根目录。

include $(CLEAR_VARS) 功能还不太清楚我。

LOCAL_MODULE := Angry 这个表明你的一个动态链接库的名字,所以你的链接库生成后会叫libAngry.so,libxxx.so是系统加的,xxx即此处的名字。

LOCAL_SRC_FILES := com_Angry_Jni.c 这是你要编译的源文件。

还有好多配置指令,有兴趣大家可以自己查。

然后再在D:\android-ndk-r6\apps\Angry 下创建Applicetion.mk文件:

  1. APP_PROJECT_PATH := $(call my-dir)/project  
  2. APP_MODULES := Angry  

APP_MODULES := Angry  指明了你的应用模块。

6、到此为止,我们都把准备工作做好了,接下来生成.so文件:

启动cygwin,进入NDK根目录:D:\android-ndk-r6,运行命令:make APP=Angry   如果显示:

                                                                                        

则表示.so生成并安装成功,你可以看到在 D:\android-ndk-r6\apps\Angry\project 下多了一个两层目录libs\armeabi\ 下面放着我们生成的libAngry.so。

7、到此为止,基本大功告成,下面我们验证一下c函数的功能能否实现:

在MainAct.java中实现如下简单代码:

  1. package com.Angry;  
  2.   
  3. import android.app.Activity;  
  4. import android.os.Bundle;  
  5. import android.widget.TextView;  
  6.   
  7. public class MainAct extends Activity {  
  8.  private TextView tv;  
  9.     /** Called when the activity is first created. */  
  10.  static  
  11.  {  
  12.   System.loadLibrary("Angry");  
  13.  }  
  14.     @Override  
  15.     public void onCreate(Bundle savedInstanceState) {  
  16.         super.onCreate(savedInstanceState);  
  17.         setContentView(R.layout.main);  
  18.           
  19.         Jni jni = new Jni();  
  20.         tv = (TextView)findViewById(R.id.tv);  
  21.           
  22.         tv.setText(jni.getString());  
  23.     }  
  24. }  

运行下,看看效果:

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值