Android之——JNI初探

来源:互联网 发布:centos 6.9 编辑:程序博客网 时间:2024/06/05 08:22

转自

http://blog.csdn.net/l1028386804/article/details/47405683


这里,我将用一个小例子的形式来帮助大家初探JNI的用法,首先,大家要先搭建好NDK环境,请大家先阅读《Android之——NDK环境搭建》一文。

一、实现

这个小例子实现的功能就是,通过Android中的java代码来调用C代码实现java代码与C代码之间的交互。

1、布局文件

我们首先在布局文件activity_main.xml中,添加一个按钮控件,并给按钮控件设置一个点击事件,具体代码如下:

[html] view plaincopy
  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     xmlns:tools="http://schemas.android.com/tools"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent"  
  5.     android:paddingBottom="@dimen/activity_vertical_margin"  
  6.     android:paddingLeft="@dimen/activity_horizontal_margin"  
  7.     android:paddingRight="@dimen/activity_horizontal_margin"  
  8.     android:paddingTop="@dimen/activity_vertical_margin"  
  9.     tools:context=".MainActivity" >  
  10.   
  11.     <Button  
  12.         android:layout_width="wrap_content"  
  13.         android:layout_height="wrap_content"  
  14.         android:onClick="click"  
  15.         android:text="调用C代码" />  
  16.   
  17. </RelativeLayout>  

2、完善类MainActivity

1)定义本地方法

要实现JNI方法的调用,首先要在MainActivity中定义一个本地方法,java中本地方法是以native关键字定义的。

具体代码如下:

[java] view plaincopy
  1. public native String helloFromC()  

2)用javah命令生成,h头文件

用javah命令生成,h头文件,前提是要配置好java环境变量,这里我就不说怎么配置环境变量了,相信稍微了解java的同学都知道。我们通过cmd命令行进入到MainActivity包所在的目录。

如下图:

然后输入命令

[java] view plaincopy
  1. javah -encoding UTF-8 包名.类名  
其中,-encoding UTF-8是指定生成的.h头文件的编码为UTF-8,包名是类所在的包,类名就是包含本地方法的类名,类名不带有.java后缀。

如下图:

此时,在当前目录下会生成一个.h头文件。

如下图:

3)实现C代码

com_lyz_hdk_helloworld_MainActivity.h中生成的代码如下:

[cpp] view plaincopy
  1. /* DO NOT EDIT THIS FILE - it is machine generated */  
  2. #include <jni.h>  
  3. /* Header for class com_lyz_hdk_helloworld_MainActivity */  
  4.   
  5. #ifndef _Included_com_lyz_hdk_helloworld_MainActivity  
  6. #define _Included_com_lyz_hdk_helloworld_MainActivity  
  7. #ifdef __cplusplus  
  8. extern "C" {  
  9. #endif  
  10. /* 
  11.  * Class:     com_lyz_hdk_helloworld_MainActivity 
  12.  * Method:    helloFromC 
  13.  * Signature: ()Ljava/lang/String; 
  14.  */  
  15. JNIEXPORT jstring JNICALL Java_com_lyz_hdk_helloworld_MainActivity_helloFromC  
  16.   (JNIEnv *, jobject);  
  17.   
  18. #ifdef __cplusplus  
  19. }  
  20. #endif  
  21. #endif  

在Android项目的根目录新建JNI目录,将com_lyz_hdk_helloworld_MainActivity.h文件拷贝到jni目录下,然后新建hello.c文件,引入所需要的库,

如下所示:

[cpp] view plaincopy
  1. #include <stdio.h>  
  2. #include <jni.h>  
  3. #include "com_lyz_hdk_helloworld_MainActivity.h"  
在hello.c中实现Java_com_lyz_hdk_helloworld_MainActivity_helloFromC方法,返回相应的字符串

具体代码如下:

[cpp] view plaincopy
  1. JNIEXPORT jstring JNICALL Java_com_lyz_hdk_helloworld_MainActivity_helloFromC(JNIEnv *env , jobject obj){  
  2.     char *str = "hello from c";  
  3.     jstring jstr = (**env).NewStringUTF(env, str);  
  4.     return jstr;  
  5. }  
hello.c完整代码如下:

[cpp] view plaincopy
  1. #include <stdio.h>  
  2. #include <jni.h>  
  3. #include "com_lyz_hdk_helloworld_MainActivity.h"  
  4.   
  5. JNIEXPORT jstring JNICALL Java_com_lyz_hdk_helloworld_MainActivity_helloFromC(JNIEnv *env , jobject obj){  
  6.     char *str = "hello from c";  
  7.     jstring jstr = (**env).NewStringUTF(env, str);  
  8.     return jstr;  
  9. }  

4)在jni目录下创建Android.mk

这个文件是Android实现JNI所必须的文件,而且文件名称固定为Android.mk不能更改。这个文件里的内容我们可以到ndk的docs目录下找到ANDROID-MK.html文件,打开这个文件,找到以下代码片段,拷贝到Android.mk文件中,注意要每一行不要有空格。

[plain] view plaincopy
  1. LOCAL_PATH := $(call my-dir)  
  2.   
  3. include $(CLEAR_VARS)  
  4.   
  5. LOCAL_MODULE    := hello-jni  
  6. LOCAL_SRC_FILES := hello-jni.c  
  7.   
  8. include $(BUILD_SHARED_LIBRARY)  
其在文件中的位置如下图:

其中:

LOCAL_PATH := $(call my-dir):当前文件所存在的目录
call my-dir 得到当前我的文件的目录
include $(CLEAR_VARS):配置信息初始化
LOCAL_MODULE    := hello-jni:指定编译完成后的2进制值可执行文件的名称
LOCAL_SRC_FILES := hello-jni.c:指定你要编译哪些C的源文件

include $(BUILD_SHARED_LIBRARY):编译成动态的链接库文件
include $(BUILD_STATIC_LIBRARY):编译成静态的链接库文件

我要编译的文件是hello.c,要生成的so为libhello.so所以我将上面的配置修改为以下代码:

[cpp] view plaincopy
  1. LOCAL_PATH := $(call my-dir)  
  2.   
  3. include $(CLEAR_VARS)  
  4.   
  5. LOCAL_MODULE    := hello  
  6. LOCAL_SRC_FILES := hello.c  
  7.   
  8. include $(BUILD_SHARED_LIBRARY)  
以上配置也就是Android.mk中的内容了。

如下图:

这时,我们项目的jni目录下的文件如下图所示:


5)编译生成so动态链接库

我们打开cygwin,进入到项目的jni目录下。

如下图:

执行命令ndk-build

如下图:

刷新项目工程,会在libs目录下自动生成一个.so动态链接库,

如下图:

6)完善MainActivity

在MainActivity类中,写一个静态代码块,用于加载.so动态链接库,注意,这里我们生成的.so文件是libhello.so,我们在加载这个.so文件的时候,只需要传入hello即可。

具体代码实现如下:

[java] view plaincopy
  1. //加载静态代码块  
  2. static{  
  3.     System.loadLibrary("hello");  
  4. }  
在按钮的点击事件中调动本地方法,同时将结果Toast出来。

具体代码如下:

[java] view plaincopy
  1. public void click(View v){  
  2.     Toast.makeText(this"c代码的内容是:"+helloFromC(), Toast.LENGTH_SHORT).show();  
  3. }  
MainActivity整体代码如下:

[java] view plaincopy
  1. package com.lyz.hdk.helloworld;  
  2.   
  3. import android.app.Activity;  
  4. import android.os.Bundle;  
  5. import android.view.Menu;  
  6. import android.view.View;  
  7. import android.widget.Toast;  
  8.   
  9. /** 
  10.  * 主程入口 
  11.  * @author liuyazhuang 
  12.  * 
  13.  */  
  14. public class MainActivity extends Activity {  
  15.       
  16.     public native String helloFromC();  
  17.     //加载静态代码块  
  18.     static{  
  19.         System.loadLibrary("hello");  
  20.     }  
  21.       
  22.     @Override  
  23.     protected void onCreate(Bundle savedInstanceState) {  
  24.         super.onCreate(savedInstanceState);  
  25.         setContentView(R.layout.activity_main);  
  26.     }  
  27.   
  28.     @Override  
  29.     public boolean onCreateOptionsMenu(Menu menu) {  
  30.         // Inflate the menu; this adds items to the action bar if it is present.  
  31.         getMenuInflater().inflate(R.menu.main, menu);  
  32.         return true;  
  33.     }  
  34.       
  35.     public void click(View v){  
  36.         Toast.makeText(this"c代码的内容是:"+helloFromC(), Toast.LENGTH_SHORT).show();  
  37.     }  
  38. }  

二、运行效果

三、温馨提示:

大家可以到链接http://download.csdn.net/detail/l1028386804/8987847下载完整的Android JNI示例源代码。

本实例中,为了方面,我把一些文字直接写在了布局文件中和相关的类中,大家在真实的项目中要把这些文字写在string.xml文件中,在外部引用这些资源,切记,这是作为一个Android程序员最基本的开发常识和规范,我在这里只是为了方便直接写在了类和布局文件中。


0 0
原创粉丝点击