Android之——JNI初探
2015-08-12 14:23
691 查看
转自
http://blog.csdn.net/l1028386804/article/details/47405683
这里,我将用一个小例子的形式来帮助大家初探JNI的用法,首先,大家要先搭建好NDK环境,请大家先阅读《Android之——NDK环境搭建》一文。
这个小例子实现的功能就是,通过Android中的java代码来调用C代码实现java代码与C代码之间的交互。
我们首先在布局文件activity_main.xml中,添加一个按钮控件,并给按钮控件设置一个点击事件,具体代码如下:
[html] view
plaincopy
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="click"
android:text="调用C代码" />
</RelativeLayout>
1)定义本地方法
要实现JNI方法的调用,首先要在MainActivity中定义一个本地方法,java中本地方法是以native关键字定义的。
具体代码如下:
[java] view
plaincopy
public native String helloFromC()
2)用javah命令生成,h头文件
用javah命令生成,h头文件,前提是要配置好java环境变量,这里我就不说怎么配置环境变量了,相信稍微了解java的同学都知道。我们通过cmd命令行进入到MainActivity包所在的目录。
如下图:
然后输入命令
[java] view
plaincopy
javah -encoding UTF-8 包名.类名
其中,-encoding UTF-8是指定生成的.h头文件的编码为UTF-8,包名是类所在的包,类名就是包含本地方法的类名,类名不带有.java后缀。
如下图:
此时,在当前目录下会生成一个.h头文件。
如下图:
3)实现C代码
com_lyz_hdk_helloworld_MainActivity.h中生成的代码如下:
[cpp] view
plaincopy
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_lyz_hdk_helloworld_MainActivity */
#ifndef _Included_com_lyz_hdk_helloworld_MainActivity
#define _Included_com_lyz_hdk_helloworld_MainActivity
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_lyz_hdk_helloworld_MainActivity
* Method: helloFromC
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_lyz_hdk_helloworld_MainActivity_helloFromC
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
在Android项目的根目录新建JNI目录,将com_lyz_hdk_helloworld_MainActivity.h文件拷贝到jni目录下,然后新建hello.c文件,引入所需要的库,
如下所示:
[cpp] view
plaincopy
#include <stdio.h>
#include <jni.h>
#include "com_lyz_hdk_helloworld_MainActivity.h"
在hello.c中实现Java_com_lyz_hdk_helloworld_MainActivity_helloFromC方法,返回相应的字符串
具体代码如下:
[cpp] view
plaincopy
JNIEXPORT jstring JNICALL Java_com_lyz_hdk_helloworld_MainActivity_helloFromC(JNIEnv *env , jobject obj){
char *str = "hello from c";
jstring jstr = (**env).NewStringUTF(env, str);
return jstr;
}
hello.c完整代码如下:
[cpp] view
plaincopy
#include <stdio.h>
#include <jni.h>
#include "com_lyz_hdk_helloworld_MainActivity.h"
JNIEXPORT jstring JNICALL Java_com_lyz_hdk_helloworld_MainActivity_helloFromC(JNIEnv *env , jobject obj){
char *str = "hello from c";
jstring jstr = (**env).NewStringUTF(env, str);
return jstr;
}
4)在jni目录下创建Android.mk
这个文件是Android实现JNI所必须的文件,而且文件名称固定为Android.mk不能更改。这个文件里的内容我们可以到ndk的docs目录下找到ANDROID-MK.html文件,打开这个文件,找到以下代码片段,拷贝到Android.mk文件中,注意要每一行不要有空格。
[plain] view
plaincopy
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := hello-jni
LOCAL_SRC_FILES := hello-jni.c
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
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := hello
LOCAL_SRC_FILES := hello.c
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
//加载静态代码块
static{
System.loadLibrary("hello");
}
在按钮的点击事件中调动本地方法,同时将结果Toast出来。
具体代码如下:
[java] view
plaincopy
public void click(View v){
Toast.makeText(this, "c代码的内容是:"+helloFromC(), Toast.LENGTH_SHORT).show();
}
MainActivity整体代码如下:
[java] view
plaincopy
package com.lyz.hdk.helloworld;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.widget.Toast;
/**
* 主程入口
* @author liuyazhuang
*
*/
public class MainActivity extends Activity {
public native String helloFromC();
//加载静态代码块
static{
System.loadLibrary("hello");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
public void click(View v){
Toast.makeText(this, "c代码的内容是:"+helloFromC(), Toast.LENGTH_SHORT).show();
}
}
大家可以到链接http://download.csdn.net/detail/l1028386804/8987847下载完整的Android JNI示例源代码。
本实例中,为了方面,我把一些文字直接写在了布局文件中和相关的类中,大家在真实的项目中要把这些文字写在string.xml文件中,在外部引用这些资源,切记,这是作为一个Android程序员最基本的开发常识和规范,我在这里只是为了方便直接写在了类和布局文件中。
http://blog.csdn.net/l1028386804/article/details/47405683
这里,我将用一个小例子的形式来帮助大家初探JNI的用法,首先,大家要先搭建好NDK环境,请大家先阅读《Android之——NDK环境搭建》一文。
一、实现
这个小例子实现的功能就是,通过Android中的java代码来调用C代码实现java代码与C代码之间的交互。
1、布局文件
我们首先在布局文件activity_main.xml中,添加一个按钮控件,并给按钮控件设置一个点击事件,具体代码如下:[html] view
plaincopy
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="click"
android:text="调用C代码" />
</RelativeLayout>
2、完善类MainActivity
1)定义本地方法要实现JNI方法的调用,首先要在MainActivity中定义一个本地方法,java中本地方法是以native关键字定义的。
具体代码如下:
[java] view
plaincopy
public native String helloFromC()
2)用javah命令生成,h头文件
用javah命令生成,h头文件,前提是要配置好java环境变量,这里我就不说怎么配置环境变量了,相信稍微了解java的同学都知道。我们通过cmd命令行进入到MainActivity包所在的目录。
如下图:
然后输入命令
[java] view
plaincopy
javah -encoding UTF-8 包名.类名
其中,-encoding UTF-8是指定生成的.h头文件的编码为UTF-8,包名是类所在的包,类名就是包含本地方法的类名,类名不带有.java后缀。
如下图:
此时,在当前目录下会生成一个.h头文件。
如下图:
3)实现C代码
com_lyz_hdk_helloworld_MainActivity.h中生成的代码如下:
[cpp] view
plaincopy
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_lyz_hdk_helloworld_MainActivity */
#ifndef _Included_com_lyz_hdk_helloworld_MainActivity
#define _Included_com_lyz_hdk_helloworld_MainActivity
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_lyz_hdk_helloworld_MainActivity
* Method: helloFromC
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_lyz_hdk_helloworld_MainActivity_helloFromC
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
在Android项目的根目录新建JNI目录,将com_lyz_hdk_helloworld_MainActivity.h文件拷贝到jni目录下,然后新建hello.c文件,引入所需要的库,
如下所示:
[cpp] view
plaincopy
#include <stdio.h>
#include <jni.h>
#include "com_lyz_hdk_helloworld_MainActivity.h"
在hello.c中实现Java_com_lyz_hdk_helloworld_MainActivity_helloFromC方法,返回相应的字符串
具体代码如下:
[cpp] view
plaincopy
JNIEXPORT jstring JNICALL Java_com_lyz_hdk_helloworld_MainActivity_helloFromC(JNIEnv *env , jobject obj){
char *str = "hello from c";
jstring jstr = (**env).NewStringUTF(env, str);
return jstr;
}
hello.c完整代码如下:
[cpp] view
plaincopy
#include <stdio.h>
#include <jni.h>
#include "com_lyz_hdk_helloworld_MainActivity.h"
JNIEXPORT jstring JNICALL Java_com_lyz_hdk_helloworld_MainActivity_helloFromC(JNIEnv *env , jobject obj){
char *str = "hello from c";
jstring jstr = (**env).NewStringUTF(env, str);
return jstr;
}
4)在jni目录下创建Android.mk
这个文件是Android实现JNI所必须的文件,而且文件名称固定为Android.mk不能更改。这个文件里的内容我们可以到ndk的docs目录下找到ANDROID-MK.html文件,打开这个文件,找到以下代码片段,拷贝到Android.mk文件中,注意要每一行不要有空格。
[plain] view
plaincopy
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := hello-jni
LOCAL_SRC_FILES := hello-jni.c
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
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := hello
LOCAL_SRC_FILES := hello.c
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
//加载静态代码块
static{
System.loadLibrary("hello");
}
在按钮的点击事件中调动本地方法,同时将结果Toast出来。
具体代码如下:
[java] view
plaincopy
public void click(View v){
Toast.makeText(this, "c代码的内容是:"+helloFromC(), Toast.LENGTH_SHORT).show();
}
MainActivity整体代码如下:
[java] view
plaincopy
package com.lyz.hdk.helloworld;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.widget.Toast;
/**
* 主程入口
* @author liuyazhuang
*
*/
public class MainActivity extends Activity {
public native String helloFromC();
//加载静态代码块
static{
System.loadLibrary("hello");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
public void click(View v){
Toast.makeText(this, "c代码的内容是:"+helloFromC(), Toast.LENGTH_SHORT).show();
}
}
二、运行效果
三、温馨提示:
大家可以到链接http://download.csdn.net/detail/l1028386804/8987847下载完整的Android JNI示例源代码。本实例中,为了方面,我把一些文字直接写在了布局文件中和相关的类中,大家在真实的项目中要把这些文字写在string.xml文件中,在外部引用这些资源,切记,这是作为一个Android程序员最基本的开发常识和规范,我在这里只是为了方便直接写在了类和布局文件中。
相关文章推荐
- 【Xamarin开发 Android 系列 8】 创建一个Json读取数据应用(上)
- Android Api Demos登顶之路(三十一)Alarm Controller
- Android 获取assets的绝对路径(转载)
- Android之——NDK环境搭建
- Android Zxing框架扫描解决扫描框大小,图片压缩问题
- Fragment实现Tabhost效果(未完)
- Android Context 是什么?
- Android编码规范
- 三、晓凡调试-Android开发版之应用调试
- Android View事件分发与传递
- Android ViewGroup.setDescendantFocusability函数
- Android四大组件之acticity整理
- Android ViewTreeObserver简介
- Android 之 下拉框(Spinner)的使用
- Android环境
- Android调用Camera API 拍照
- Android实战技巧之三十三:android.hardware.camera2使用指南
- Android之用PopupWindow实现弹出listview形式菜单
- Android登录拦截器实现方式(一)
- Android入门第一篇