Android之——JNI初探

转载请注明出处:http://blog.csdn.net/l1028386804/article/details/47405683

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

一、实现

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

1、布局文件

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

<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关键字定义的。

具体代码如下:

public native String helloFromC()
2)用javah命令生成,h头文件

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

如下图:

然后输入命令

javah -encoding UTF-8 包名.类名

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

如下图:

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

如下图:

3)实现C代码

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

/* 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文件,引入所需要的库,

如下所示:

#include <stdio.h>
#include <jni.h>
#include "com_lyz_hdk_helloworld_MainActivity.h"

在hello.c中实现Java_com_lyz_hdk_helloworld_MainActivity_helloFromC方法,返回相应的字符串

具体代码如下:

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完整代码如下:

#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文件中,注意要每一行不要有空格。

   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所以我将上面的配置修改为以下代码:

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即可。

具体代码实现如下:

//加载静态代码块
static{
	System.loadLibrary("hello");
}

在按钮的点击事件中调动本地方法,同时将结果Toast出来。

具体代码如下:

public void click(View v){
	Toast.makeText(this, "c代码的内容是:"+helloFromC(), Toast.LENGTH_SHORT).show();
}

MainActivity整体代码如下:

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程序员最基本的开发常识和规范,我在这里只是为了方便直接写在了类和布局文件中。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-27 03:58:30

Android之——JNI初探的相关文章

【转】Android与JNI(二) -- 不错

原文网址:http://www.cnblogs.com/eddy-he/archive/2012/08/09/2629974.html 软件版本: ubuntu10.04 java version "1.6.0_30-ea" eclipse android-ndk-r5b 目录: 1. 简介 2. JNI 组件的入口函数 3. 使用 registerNativeMethods 方法 4. 测试 5. JNI 帮助方法 6. 参考资料 1. 简介 Android与JNI(一)已经简单介绍

Android通过JNI实现与C语言的串口通讯操作蓝牙硬件模块

一直想写一份技术文档,但因为自感能力有限而无从下笔,近期做了个关于Android平台下实现与C语言的通讯来操作蓝牙模块的项目,中间碰到了很多问题,也在网上查了很多资料,在完毕主要功能后.也有一些人在网上问我一些问题.这里写下这篇文档算是一个阶段性的总结. 假设反响好.兴许将会发上Android Stub与新版Android HAL的学习文档. 因为蓝牙模块是串口通讯机制.使用C语言来訪问,而Android的应用层採用Java.无法直接操作硬件.故使用JNI的技术实现主要功能.Android的JN

Android使用JNI(从java调用本地函数)

当编写一个混合有本地C代码和Java的应用程序时,需要使用Java本地接口(JNI)作为连接桥梁.JNI作为一个软件层和API,允许使用本地代码调用Java对象的方法,同时也允许在Java方法中调用本地函数. 在Java端,开发者所需要做的仅仅是在连接本地函数的方法之前加上native关键字.这样VM就会去寻找这个本地函数. 1.从Java调用本地函数 从Java调用本地函数时,需要在类中定义一个带有native关键字的特有方法,作为连接本地代码的桥梁.通过这个定义,尝试调用本地方法时JVM会找

I.MX6 android BatteryService jni hacking

/**************************************************************************** * I.MX6 android BatteryService jni hacking * 声明: * 本文主要是为了知道Android的获取的电源管理的数据的jni是从Linux系统的 * 什么位置获取的,获取的机制是什么. * * 2016-2-22 深圳 南山平山村 曾剑锋 ********************************

[Android] 图片JNI(C++\Java)高斯模糊 多线程

在我的博客中,曾经发布了一篇高斯模糊(堆栈模糊)的文章:在其中使用了国外的一个堆栈模糊来实现对图片的模糊处理:同时弄了一个JNI C++ 的版本. 这篇文章依然是堆栈模糊:可以说最原始的地方还是堆栈模糊部分:只不过是支持多线程的. 纳尼??感情是之前那个不支持多线程?Sorry,我说错了:两个都是支持多线程调用的.不过新讲的这个是能在内部采用多线程进行分段模糊. 原来的:[Android]-图片JNI(C++\Java)高斯模糊的实现与比较 开工吧 说明:其中代码大部分来源于网络,不过都是开源的

Android - Android调用JNI方法 及 代码

Android调用JNI方法 及 代码 本文地址: http://blog.csdn.net/caroline_wendy JNI: Java Native Interface, 实现Java和C/C++的互通. 在Android上使用JNI的方法. 时间:2014.9.3 环境: 必须使用标准Eclipse, 安装Android的环境, 才可以使用NDT插件. Eclipse Standard/SDK Version: Luna Release (4.4.0); Android: ADT-23

OpenCV4Android释疑: 透析Android以JNI调OpenCV的三种方式(让OpenCVManager永不困扰)

前文曾具体探讨了关于OpenCV的使用,原本以为天下已太平.但不断有人反应依旧配不好OpenCV4Android,不能得心应手的在Android上使用OpenCV.大量的精力都浪费在摸索配置上.尤其是OpenCVManager诞生之后.更让人无语.大家第一个反应就是怎样才干不安装OpenCVManager.由于要多安装这个东西对客户来说体验太不好了. 咱家昨夜研究至两点,今早七点起床.最终把头绪理清了. 以下咱家以之前做过的一个基于OpenCV2.3.1.android通过jni调用opencv

Android中JNI的使用

Android中JNI编程的那些事儿 首先说明,Android系统不允许一个纯粹使用C/C++的程序出现,它要求必须是通过Java代码嵌入Native C/C++——即通过JNI的方式来使用本地(Native)代码.因此JNI对Android底层开发人员非常重要. 如何将.so文件打包到.APK 让我们 先 从最简单的情况开始,假如已有一个JNI实现——libxxx.so文件,那么如何在APK中使用它呢? 在我最初写类似程序的时候,我会将libxxx.so文件push到/system/lib/目

Android(Java):jni源代码

public void onCreate(Bundle savedInstanceState)    {        super.onCreate(savedInstanceState);        Button btn = new Button(this);        btn.setText("测试ndk");        btn.setOnClickListener(new ButtonOnClickListener());        setContentView(