文档章节

Android Native jni 编程入门

x
 xchsp
发布于 2015/03/07 09:39
字数 1053
阅读 7
收藏 0

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

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

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

 

下面就通过一个例子一步一步的来初步学习jni

一、HelloWorld

新建一个工程,你甚至不需要其它额外的设置,然后在工程中添加一个jni目录,然后就可以开始了;

1.新建一个java类HelloWorld.java

复制代码

package com.jni;public class HelloWorld {    static {
        System.loadLibrary("helloworld");
    }    public native String helloworld();
}

复制代码

在HelloWorld中,定义了一个方法helloworld(),只不过这个方法被申明成了native的,并没有具体的实现,具体功能我们在接下来的cpp文件中实现;

2.在jni目录下添加一个helloworld.cpp

复制代码

#include <jni.h>#include <android/log.h>#include <string.h>#ifndef _Included_com_jni_HelloWorld // 1#define _Included_com_jni_HelloWorld#ifdef __cplusplus // 2extern "C" {#endif // 2JNIEXPORT jstring JNICALL Java_com_jni_HelloWorld_helloworld(JNIEnv *, jobject);
#ifdef __cplusplus // 3}#endif // 3#endif // 1JNIEXPORT jstring JNICALL Java_com_jni_HelloWorld_helloworld(JNIEnv * env,
        jobject obj) {    return env->NewStringUTF("helloworld");
}

复制代码

从上面这个cpp文件中可以很明白的看出,它有一个方法,具体包括方法申明和方法实现两个部分;但是相信大家也都看出来了,方法的命令很怪异,怎么这么长的方法名?

我们在这里先思考一个问题,java类中的方法是如何调用c++中的方法的呢?要解决这个问题,就得先来看这个长长的方法名;

其实这是jni的一个规范之一,用于映射java方法和c/c++中的方法对应;

再来看在cpp中定义的函数名:Java_com_jni_HelloWorld_helloworld

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

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

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

这里的helloworld方法,其实就只是返回了一个单词"helloworld";

3.在jni目录下添加一个Android.mk文件

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE    := helloworld
LOCAL_SRC_FILES := helloworld.cpp
include $(BUILD_SHARED_LIBRARY)

4.在命令行下进入工程目录执行 ndk-build 命令,然后运行程序,调用HelloWorld实例的helloworld方法就可以得到它的返回字符串了;

 

二、jni调用Java类的方法(1)

通过上面的helloworld练手之后,我们来看一下jni调用java类里面的方法的实现;

1.新建设一个MethodCall.java文件如下

复制代码

public class MethodCall {    final String tag = "MethodCall";    static {
        System.loadLibrary("methodcall");
    }    public native String jniCallMethod1();    public native String jniCallMethod2();    public native String jniCallStaticMethod();    public void javaMethod1() {
        Log.e(tag, "javaMethod1");
    }    public String javaMethod2() {
        Log.e(tag, "javaMethod2");        return "javaMethod2";
    }    public static void javaStaticMethod(String input) {
        Log.e("MethodCall", "" + input);
    }
}

复制代码

该类有6个方法,其中有3个是java类的方法,另外3个是native方法,3个native方法分别去调用3个java方法;

2.添加三个native方法具体实现 methodcall.cpp

复制代码

#include <jni.h>#include <android/log.h>#include <string.h>#ifndef _Included_com_jni_MethodCall#define _Included_com_jni_MethodCall#ifdef __cplusplusextern "C" {#endifJNIEXPORT jstring JNICALL Java_com_jni_MethodCall_jniCallMethod1(JNIEnv *,
        jobject);
JNIEXPORT jstring JNICALL Java_com_jni_MethodCall_jniCallMethod2(JNIEnv *,
        jobject);
JNIEXPORT jstring JNICALL Java_com_jni_MethodCall_jniCallStaticMethod(JNIEnv *,
        jobject);
#ifdef __cplusplus
}#endif#endifJNIEXPORT jstring JNICALL Java_com_jni_MethodCall_jniCallMethod1(JNIEnv * env,
        jobject obj) {
    jmethodID mid; // 方法标识id
    jclass cls = env->GetObjectClass(obj); // 类的对象实例
    mid = env->GetMethodID(cls, "javaMethod1", "()V");
    env->CallVoidMethod(obj, mid);    return env->NewStringUTF("jniCallMethod1");
}

JNIEXPORT jstring JNICALL Java_com_jni_MethodCall_jniCallMethod2(JNIEnv * env,
        jobject obj) {
    jmethodID mid; // 方法标识id
    jclass cls = env->GetObjectClass(obj); // 类的对象实例
    mid = env->GetMethodID(cls, "javaMethod2", "()Ljava/lang/String;");
    jstring js = (jstring) env->CallObjectMethod(obj, mid);    return js;
}

JNIEXPORT jstring JNICALL Java_com_jni_MethodCall_jniCallStaticMethod(
        JNIEnv * env, jobject obj) {
    jmethodID mid; // 方法标识id
    jclass cls = env->GetObjectClass(obj); // 类的对象实例
    mid = env->GetStaticMethodID(cls, "javaStaticMethod",            "(Ljava/lang/String;)V");
    jstring input = env->NewStringUTF("jniCallStaticMethod->>javaStaticMethod");
    env->CallStaticVoidMethod(cls, mid, input);    return env->NewStringUTF("jniCallStaticMethod");
}

复制代码

该cpp文件中有3个方法(我这里把方法名都写得很明白直观,相信不需要注释都知道是调用的哪一个java方法)


本文转载自:

共有 人打赏支持
x
粉丝 0
博文 56
码字总数 129407
作品 0
沈阳
私信 提问
Android: NDK编程入门笔记

为何要用到NDK? 概括来说主要分为以下几种情况: 1. 代码的保护,由于apk的java层代码很容易被反编译,而C/C++库反汇难度较大。 2. 在NDK中调用第三方C/C++库,因为大部分的开源库都是用C/C...

xubohui
2012/08/20
0
0
Android: NDK编程入门笔记

为何要用到NDK? 概括来说主要分为以下几种情况: 1. 代码的保护,由于apk的java层代码很容易被反编译,而C/C++库反汇难度较大。 2. 在NDK中调用第三方C/C++库,因为大部分的开源库都是用C/C...

JORDANSG
2012/08/14
0
0
Android: NDK编程入门笔记

为何要用到NDK? 概括来说主要分为以下几种情况: 1. 代码的保护,由于apk的java层代码很容易被反编译,而C/C++库反汇难度较大。 2. 在NDK中调用第三方C/C++库,因为大部分的开源库都是用C/C...

gongweixin
2013/04/23
0
3
Android Studio进行NDK编程

近期,转战Android Studio。通过Android Studio进行简单的NDK Demo实现。无奈才疏学浅,资料有限。一直处于碰壁状态。找了好多资料,思量良久。终见实验效果,现分享给大家。通过Java对C语言...

wolfbigbig
2016/03/02
1K
4
Android NDK Hello

Android应用程序访问android的根文件系统中的文件时,由于应用程序的权限限制,无法访问这些文件,怎么办? 这时就要用到NDK编程了,既用C/C++代码实现访问系统文件,并将其生成本地库,供a...

长平狐
2013/01/06
130
0

没有更多内容

加载失败,请刷新页面

加载更多

我的Linux系统九阴真经

我的Linux系统九阴真经 在今天,互联网的迅猛发展,科技技术也日新月异,各种编程技术也如雨后春笋一样,冒出尖来了。各种创业公司也百花齐放百家争鸣,特别是针对服务行业,新型互联网服务行...

linuxCool
53分钟前
15
0
Python程序员需要知道的30个技巧

1 直接交换两个数字位置 1x, y = 10, 202print(x, y)3x, y = y, x4print(x, y)5#1 (10, 20)6#2 (20, 10) 2 比较运算符的链接 1n = 102result = 1 < n < 203print(result)4# True5result = 1 ......

糖宝lsh
53分钟前
10
0
[LintCode] Linked List Cycle(带环链表)

描述 给定一个链表,判断它是否有环。 样例 给出 -21->10->4->5, tail connects to node index 1,返回 true。 这里解释下,题目的意思,在英文原题中,tail connects to node index 1 表示的...

honeymose
今天
10
0
Android :报错Your project path contains non-ASCII characters.

报错内容如下 Your project path contains non-ASCII characters. This will most likely cause the build to fail on Windows. Please move your project to a different directory. See ht......

lanyu96
今天
7
0
Nginx平滑添加模块

Nginx已经编译安装并运行了一段时间, 然后某一天, 发现需要用到某个模块但当初没有编译, 这个时候怎么办呢? 卸载重新安装肯定可以的, 如果Nginx版本没有变更的话, 则有一个相对平滑的方法来添...

老菜鸟0217
今天
11
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部