Android jni本地编程入门

在某些情况下,java编程已经不能满足我们的需要,比如一个复杂的算法处理,这时候就需要用到jni技术;

  • jni : java native interface

  • jni
    其实就是java和c/cpp之间进行通信的一个接口规范,java可以调用c/cpp里面的函数,同样,c/cpp也可以调用java类的方法;

jni开发工具ndk的安装:
在最新的ndk版本中,安装ndk很简单,只需要装ndk的路径配置到系统环境变量中即可;
在编译的时候,进入工程根目录;执行命令
 ndk-build
 
即可完成编译;

一、cpp与java

>>1.java文件:TextOutput.java


package com.jnitest;

import android.util.Log;

public class TextOutput {
private native String init();
static {
System.loadLibrary("text");
}

public String getString() {
return init();
}

public void sayHello() {
Log.e("tag", "void sayHello");
}

public String sayHello_() {
Log.e("tag", "string sayHello_");
return "return string sayHello_";
}

public static void sayHello__() {
Log.e("tag", "static sayHello__");
}
}

在该类中定义了一个本地方法init[native init],方法实现由接下来的cpp函数来实现;以及定义了其它几个方法,由cpp文件来调用;

>>2.cpp文件:test.cpp


#include <jni.h>
#include <android/log.h>
#include <string.h>

#ifndef _Included_com_jnitest_TextOutput
#define _Included_com_jnitest_TextOutput
#ifdef __cplusplus
extern "C" {
#endif
JNIEXPORT jstring JNICALL Java_com_jnitest_TextOutput_init(JNIEnv *, jobject);
#ifdef __cplusplus
}
JNIEXPORT jstring JNICALL Java_com_jnitest_TextOutput_init(JNIEnv * env,
jobject obj) {
jmethodID mid; // 方法标识id
jclass cls = env->GetObjectClass(obj); // 类的对象实例
mid = env->GetMethodID(cls, "sayHello", "()V");
env->CallVoidMethod(obj, mid);

jmethodID mid1;
mid1 = env->GetMethodID(cls, "sayHello_", "()Ljava/lang/String;");// @1
jstring s1 = (jstring) env->CallObjectMethod(obj, mid1); // @2

jmethodID mid2;
mid2 = env->GetStaticMethodID(cls, "sayHello__", "()V");
env->CallStaticVoidMethod(cls, mid2);

return s1;
}
#endif
#endif

先来看在cpp中定义的函数名:Java_com_jnitest_TextOutput_init
其实不难看出,java文件与cpp文件中函数名的配对定义方式为Java
+ 包名 + java类名 + 方法/函数名,中间用_分隔;其中两个参数分别是:

  • env:当前该线程的内容,包含线程里面全部内容;

  • obj:当前类的实例,指.java文件的内容(在该例子中即是TextOutput类);

@1:获取MethodId,该方法需要三个参数,分别jclass类的对象实例,函数名,函数签名;其中函数签名由两部分构成(参数+函数返回值); 
查看签名可以通过先进入到java文件生成的class文件目录,执行命令:javap -s -p ClassName

生成如上图所示的函数签名;

@2:执行该方法,在上面的例子中,将执行sayHello_方法

运行程序:


TextOutput to = new TextOutput();
Log.e("tag", "" + to.getString());

二.c与java
在Activity中有一个int字段,通过callback赋值


package com.example.hellojni;

import android.app.Activity;
import android.util.Log;
import android.widget.TextView;
import android.os.Bundle;

public class HelloJni extends Activity {
private static int si;

private static void callback() {
si = 123;
}

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TextView tv = new TextView(this);
tv.setText(stringFromJNI());
setContentView(tv);
Log.e("tag", "si=" + si);
}

public native String stringFromJNI();

static {
System.loadLibrary("hello-jni");
}
}

hello-jni.c


#include <string.h>
#include <jni.h>

/*
* */
jstring Java_com_example_hellojni_HelloJni_stringFromJNI(JNIEnv* env,
jobject thiz) //env:当前该线程的内容,包含线程全部的东西;thiz:当前类的实例,指.java文件的内容
{
jint si;
jfieldID fid; // 一个字段,实际上对应java类里面的一个字段或属性;
jclass cls = (*env)->GetObjectClass(env, thiz); // 类的对象实例
jmethodID mid = (*env)->GetStaticMethodID(env, cls, "callback", "()V"); // 一个方法的id
//(I)V (I)I
if (mid == NULL) {
return (*env)->NewStringUTF(env, "mid=null");
}
(*env)->CallStaticVoidMethod(env, cls, mid); //调用callback方法
fid = (*env)->GetStaticFieldID(env, cls, "si", "I"); //取出si字段
if (fid == NULL) {
return (*env)->NewStringUTF(env, "fid=null");
}
si = (*env)->GetStaticIntField(env, cls, fid); //取出字段对应的值(fid字段对应的值)

return (*env)->NewStringUTF(env, "init success");
}

运行上面的Activity,即可实现对si的赋值

3.加入链接库

在程序开发过程中,会频繁的用到调试,方式有很多种,下面要讲的这一种是通过log打印信息来打印程序运行时的一些状态数值;

修改Android.mk文件,添加一句代码


include $(CLEAR_VARS)
LOCAL_LDLIBS += -llog //LDLIBS:连接libs,后面跟的参数为需要链接的libs,-llog表示Android中的Log库;
include $(BUILD_SHARED_LIBRARY)

加入了log库之后

即可以在c文件中调用log打印输出信息:


__android_log_print(ANDROID_LOG_ERROR, "hello", "livingstone");
__android_log_print(ANDROID_LOG_DEBUG, "hello", "livingstone %d" ,23);

Android jni本地编程入门

时间: 2024-08-14 23:50:51

Android jni本地编程入门的相关文章

一天掌握Android JNI本地编程 快速入门

一.JNI(Java Native Interface)  1.什么是JNI:               JNI(Java Native Interface):java本地开发接口 JNI是一个协议,这个协议用来沟通java代码和外部的本地代码(c/c++) 外部的c/c++代码也可以调用java代码  2.为什么使用JNI: 效率上 C/C++是本地语言,比java更高效 代码移植,如果之前用C语言开发过模块,可以复用已经存在的c代码 java反编译比C语言容易,一般加密算法都是用C语言编写

超全Android JNI&NDK编程总结

由于网上关于JNI/NDK相关的知识点介绍的比较零散而且不具备参照性,所以写了这篇JNI/NDK学习笔记,便于作为随时查阅的工具类型的文章,本文主要的介绍了在平时项目中常用的命令.JNI数据类型.签名等,便于查阅相关资料.文末相关参考资料比较适合刚接触或者不熟悉Android NDK开发的朋友参阅. 常用命令 javac 编译java源文件生成.class文件 由于JNI对应的头文件由javah工具根据对应的.class文件生成,所以在进行JNI编程之前,写好Java代码后需要先编译,在使用ja

Android JNI配置及入门

JNI是一种可以在Java中调用C/C++代码的技术,也就是说可以在Android上使用C/C++来开发.但是并不能用纯C/C++来开发Android应用,因为这些C/C++代码要通过Java定义的接口来调用. 我试验Android上的JNI时使用的是NDK-R10,不需要Cygin,使用版本较低的NDK时请另寻教程. NDK的安装与ADT中如何配置NDK 可以到Android Developer官网上去下载最新的NDK工具包,下载下来之后解压到随便一个好找的目录,比如我们解压到了C:\,这样N

Android jni/ndk编程二:jni数据类型转换(primitive,String,array)

一.数据类型映射概述 从我们开始jni编程起,就不可能避开函数的参数与返回值的问题.java语言的数据类型和c/c++有很多不同的地方,所以我们必须考虑当在java层调用c/c++函数时,怎么正确的把java的参数传给c/c++函数,怎么正确的从c/c++函数获取正确的函数返回值:反之,当我们在c/c++中使用java的方法或属性时,如何确保数据类型能正确的在java和c/c++之间转换. 回顾我们上一篇文章中的那个c函数: #include <stdio.h> #include <jn

Android JNI 本地开发接口

前言 JNI java native interface java 本地开发接口 JNI理解 JNI 简单的理解就是一个桥梁或者适配器,是C/C++语言和JAVA语言进行进行沟通的桥梁和中间件,相当于android开发中ListView和GridView的Adapter适配器,将数据和界面显示的view进行连接起来的桥梁.也可以理解为协议(接口),即C/C++与java语言相互沟通(传参,调用)的协议,在实际开发中也是通过本地开发接口(native interface)来实现相互沟通.

Android jni/ndk编程五:jni异常处理

在Java的编程中,我们经常会遇到各种的异常,也会处理各种的异常.处理异常在java中非常简单,我们通常会使用try-catch-finally来处理,也可以使用throw简单抛出一个异常.那么在jni编程的时候我们又是如何处理异常的呢? 异常处理流程 jni规范已经给我们做好了所有需要做的事情.回想一下处理异常的过程: 我们首先要在有可能产生异常的地方检测异常 处理异常 是的,我觉得异常的处理就是可以简单的总结为两步,在异常处理中我们通常会打印栈信息等.在jni编程中,异常处理的思路应该也与之

Android jni/ndk编程三:native访问java

一.访问静态字段 Java层的field和method,不管它是public,还是package.private和protected,从 JNI都可以访问到,Java面向语言的封装性不见了. 静态字段和非静态的字段访问方式不同,jni规范提供了一系列带static标示的访问静态字段的函数: jobject (*GetStaticObjectField)(JNIEnv*, jclass, jfieldID); jboolean (*GetStaticBooleanField)(JNIEnv*, j

Android jni/ndk编程四:jni引用类型

一.JNI引用类型 JNI支持三种类型的 opaque reference:local references, global references,和weak global references,下面我们将逐一探讨. local references 大部分JNI 函数都会创建LocalRef,如NewObject创建一个实例,并返回一个指向该实例的LocalRef.LocalRef只在本线程的 native method中有效. 一但native method返回,LocalRef 将被释放.

Android JNI 调用 C/C++

Android JNI 调用 C/C++ 接口 Android 使用 NDK 原生支持调用 c/c++ 接口的代码,只需要在程序中按照 android jni 规范编程就可以直接使用. C 语言版本 JNI 调用 c 语言相对简单,命名一个 jni 函数,系统会自动注册到 Java 虚拟机,然后 Java 代码里面可以直接调用: Native 代码: #include <jni.h> int add(int x, int y) { return x + y; } jint Java_com_e