她定义了同等效Java接抱C/C++的点子。它是为了有利于java调用C、C++等本地代码锁封装的一律叠接口。

3.4 绑定头文件路径

绑定头文件1

绑定头文件2

绑定头文件3

绑定头文件4

绑定头文件5

1)提高代码的安全性。由于so库反编译比较不方便,因此NDK提高了Android程序的安全性

1. 新建一个日常的Android项目

简单,略。

JNI调用java方法的流程是先行经过类名找到类似,然后重新冲章程名找到方法的id,最后就得调用这个法了。

3. 装NDK插件与绑定NDK路径

针对Eclipse
IDE:放到eclipse安装目录下之plugins目录就对了,然后挨家挨户点击Window–>Preference–>Android–>NDK
进行NDK路径的绑定

绑定步骤1

绑定步骤2

JNI笔记-搭建开发环境

No2:

3.3 复制标头文件内容及jni.cpp,并删除标头文件(com_example_hello_jni_Jni.h)

jni-未绑定.png

3)实现Android项目受到所声明的native方法

先期出只概念

JNI,洋名全称是Java Native
Interface,翻译过来就Java本地接口。我们且了解所谓接口就是一律仿照规范,可以就此来定义接入方式。那么JNI定义了啊衔接方式吗?答案是:它定义了同等学Java接抱C/C++的方。

我们理解C/C++语言编译后底文件是得一直当本土系统受运行的,而Java文件编译后生成的凡许节码文件,需要依赖Java虚拟机(JVM)来运转,显然在效率上C/C++更高效;另一方面,我们明白字节码文件是可以生爱反编译的,存在不安全性;再者,硬件相关的驱动、许多出名的音视频解码库也是C/C++编写的。Java程序想如果实施高性能的代码、想使大安全性要用调用系统让和重用曾经有的音视频解码库,那么就是只好采取JNI了。

关押下自己那儿简陋的笔记:

JNI笔记-概念

Java JNI–Java Native
Interface(java本地接口),它是为好java调用C、C++等地方代码锁封装的平等重叠接口。

1. 下载NDK

What ? NDK是呀不良?别着急嘛,这就是说。NDK洋名全称是Native Development
Kit,就是Google给我们开发者提供的同一效好地展开JNI开发之家伙集,可以到官网下载,也得以据此自己备好的资源(里面还含了适用于eclipse开发条件之NDK插件,这个当ADT-Bundle中凡合二为一的)。

JNI开发流程:首先需要在java中声称native方法,接着用C或C++实现native方法,然后就是得编译运行了

7. run时而看望

运作结果

Java果真通过JNI技术调用了C代码,而C真的回到问候让Java了,nice!!!


最终不妨看我当年底笔记(仅供参考,估计只有自身好看得掌握,捂脸走。。。)

JNI笔记- Hello JNI

假如是调用java中的莫静态方法,那么得组织出类的目标后才能够调用它。

3.2 生成Jni.java的标头文件

复制工程的src目录的职,当前吧:D:\Android\jni\Hello-JNI\src
CMD进入

C:\Users\Lshare>cd /d D:\Android\jni\Hello-JNI\src
D:\Android\jni\Hello-JNI\src>

复制Jni.java的整个径名,当前为:com.example.hello_jni.Jni
javah生成标头文件

D:\Android\jni\Hello-JNI\src>javah com.example.hello_jni.Jni

刷一下工程,可以看来

标头文件

No8:

3.1 创建Java源文件–Jni.java
package com.example.hello_jni;
public class Jni {
    //静态加载我们即将生成的so库
    static{
        System.loadLibrary("jni");
    }
    //代理函数,具体实现在C
    public native String getMsgFromC();
}

3)实现JNI方法

原理

粗粗的历程是这般的:

  1. 咱将C/C++源程序编译打包成动态库(dll或so,具体看运行的条件),存放于我们先后的lib目录下;
  2. 当java程序中我们调用带native修饰的代办方,它的兑现以C/C++程序中,系统会调用动态库中相应的落实方式,如果需要的话,还会见回处理结果。

JNI笔记-原理

javac com/ryg/JniTest.java
javah com.ryg.JniTest

Hello JNI

假使上面的手续顺利,下面我们即将正式跟JNI打个招呼了。Hello
JNI项目源码:下载

第一,在工程的主目录下创建一个子目录,名称随意,这里选择jni作为子目录的称呼,然后拿前经过javah生成的条文件com_ryg_JniTest.h复制到jni目录下,接着创建test.cpp和test.c两独文件。

4.完函数体

#include <jni.h>
/**
 * env:包含了jni.h提供了许多便捷的函数,查看头文件源码发现
 * #if defined(__cplusplus)
 * typedef _JNIEnv JNIEnv;
 * typedef _JavaVM JavaVM;
 * #else
 * typedef const struct JNINativeInterface* JNIEnv;
 * typedef const struct JNIInvokeInterface* JavaVM;
 * thiz:包含对应的代理函数的java类的对象
 */
#ifndef _Included_com_example_hello_jni_Jni
#define _Included_com_example_hello_jni_Jni
#ifdef __cplusplus
extern "C" {
#endif
JNIEXPORT jstring JNICALL Java_com_example_hello_1jni_Jni_getMsgFromC
  (JNIEnv * env, jobject thiz){
    //当为cpp文件时用“env->”,为c文件时用“(*env)->”
    // 该函数用于将“C-String”转换为jstring
    return env->NewStringUTF("Hello JNI!");
}
#ifdef __cplusplus
}
#endif
#endif

No4:

3. 创办两单照应的文件

一个凡Java源文件,代理动态库中艺术;另一个凡是C/C++源文件,是对准代理方的贯彻。
顶尖实践是:先创造Java代理文件,静态导入动态库并编辑好代理方,然后使用javah命令生成C语言的法门签名;复制方法签名到C/C++源文件被,补充参数誉为以及方法体就OK了。

4)编译so库并在Java中调用

6. 修改Android.mk和Application.mk适应需求

Android.mk的任务:描述来文件该怎么编译

#包含Android.mk自身的路径
LOCAL_PATH := $(call my-dir)
#清除LOCAL_XXX变量,除了LOCAL_PATH
include $(CLEAR_VARS)
#要生成的动态库名称,系统会自动加上“lib”前缀和“.so”后缀
LOCAL_MODULE    := jni
#要编译的C/C++文件
LOCAL_SRC_FILES := jni.cpp
#指向构建脚本,搜集定义的LOCAL_XXX变量信息,生成lib$(LOCAL_MODULE).so
include $(BUILD_SHARED_LIBRARY)

Application.mk的天职:描述哪一个动态库是项目用的
默认不要命成这个文件,我们要好在/jni目录下新建一个。一般情形下,我们应用有限个变量就足足了

#定义要生成的CPU架构的so文件,all代表所有
APP_ABI := all
#目标安卓版本,18表示api level,即Android 4.3
APP_PLATFORM := android-8

接下来以app/src/main中开创一个叫做也jniLibs的目,将变的so库复制到jniLibs目录中,然后经AndroidStudio编译运行即可。

JNI开发环境搭建

放任你这么一游说,原理似乎知道了数了,那本凡是无是欠开工了??别急,“工欲善其事,必先利其器”,让咱事先增建筑起出环境。

指令如下

5. 圆逻辑实现

//activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <Button
        android:onClick="sayHello"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="C快快请安" />
</RelativeLayout>

//MainActivity.java
public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
    public void sayHello(View view){
        String msg = new Jni().getMsgFromC();
        Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
    }
}

JNIEXPORT和JNICALL:它们要JNI中所定义之宏大,可以以jni.h这个腔文件中查找到

2. 加上本地动态库支持

右击Android项目–>Android Tools–>Add Native
Support…,然后输入动态库的名目(系统会自行抬高前缀”lib”和后缀”.so”,以jni为例)

累加本地动态库支持1

累加本地动态库支持2

成功后会见发觉,工程会转移至C/C++视图,并且项目中几近了有的文件/文件夹

大多了底公文

函数名格式遵循规则:Java_包名_类名_方法名

2. 解压NDK并查阅参考文档

以下载后底缩减包解压到自由分区,注意文件路径不能够包含中文和空白字符(比如空格、tab),否则会导致NDK不可用。注:可以经过查看参考文档和导入示例代码到工程上。

NDK目录

3)便于平台中间的移植。通过C、C++实现之动态库可以生有益地于其余平台及利用

C:gcc -shared -I/usr/lb/jvm/java-7-openjdk-amd64/include-fPIC test.c-o
libjni-test.so

public class MainActivity extends ActionBarActivity {

    private static final String TAG = "MainActivity";

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

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        TextView textView = (TextView)findViewById(R.id.msg);
        textView.setText(get());
        set("hello world from JniTestApp");
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    public static void methodCalledByJni(String msgFromJni) {
        Log.d(TAG, "methodCalledByJni, msg: " + msgFromJni);
    }

    public native String get();

    public native void set(String str);
}

NDK是Android所提供的一个器集,通过NDK可以于Android中愈发有益于之通过JNI来访问当地代码,比如C或者C++。

JNI方法是指Java中宣示的native方法

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_ryg_JniTest */

#ifndef _Included_com_ryg_JniTest
#define _Included_com_ryg_JniTest
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_ryg_JniTest
 * Method:    get
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_ryg_JniTest_get
  (JNIEnv *, jobject);

/*
 * Class:     com_ryg_JniTest
 * Method:    set
 * Signature: (Ljava/lang/String;)V
 */
JNIEXPORT void JNICALL Java_com_ryg_JniTest_set
  (JNIEnv *, jobject, jstring);

#ifdef __cplusplus
}
#endif
#endif

1)在Java中声明native方法

No7:

package com.ryg;

import java.lang.System;

public class JniTest {

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

    public static void main(String args[]) {
        JniTest jniTest = new JniTest();
        System.out.println(jniTest.get());
        jniTest.set("hello world");
    }

    public native String get();
    public native void set(String str);
}

NDK还提供了接力编译器,开发人员只待简单的修改mk文件就足以扭转特定CPU平台的动态库。

No6:

NDK开发流程

No1:

4)提高程序在某些特定情形下的行效率,但是连无克明了提升Android程序的性质

so库的编译这里用gcc,编译指令如下

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

#ifdef __cplusplus
extern "C" {
#endif

void callJavaMethod(JNIEnv *env, jobject thiz) {
    jclass clazz = env->FindClass("com/ryg/JniTestApp/MainActivity");
    if (clazz == NULL) {
        printf("find class MainActivity error!");
        return;
    }
    jmethodID id = env->GetStaticMethodID(clazz, "methodCalledByJni", "(Ljava/lang/String;)V");
    if (id == NULL) {
        printf("find method methodCalledByJni error!");
    }
    jstring msg = env->NewStringUTF("msg send by callJavaMethod in test.cpp.");
    env->CallStaticVoidMethod(clazz, id, msg);
}

jstring Java_com_ryg_JniTestApp_MainActivity_get(JNIEnv *env, jobject thiz) {
    printf("invoke get in c++\n");
    callJavaMethod(env, thiz);
    return env->NewStringUTF("Hello from JNI in libjni-test.so !");
}

void Java_com_ryg_JniTestApp_MainActivity_set(JNIEnv *env, jobject thiz, jstring string) {
    printf("invoke set from C++\n");
    char* str = (char*)env->GetStringUTFChars(string,NULL);
    printf("%s\n", str);
    env->ReleaseStringUTFChars(string, str);
}

#ifdef __cplusplus
}
#endif

//模块名称
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := jni-test
//需要参与编译的源文件
LOCAL_SRC_FILES := test.cpp

include $(BUILD_SHARED_LIBRARY)

//CPU的架构平台的类型
APP_ABI := armeabi

4)切换至jni目录的父目录,然后经过ndk-build命令编译产生so库

以Linux环境受到,JNI和NDK开发所用到的动态库的格式是以.so为后缀的公文,下面统一简称为so库。

#include "com_ryg_JniTest.h"
#include <stdio.h>

JNIEXPORT jstring JNICALL Java_com_ryg_JniTest_get(JNIEnv *env, jobject thiz) {
    printf("invoke get in c++\n");
    return env->NewStringUTF("Hello from JNI !");
}

JNIEXPORT void JNICALL Java_com_ryg_JniTest_set(JNIEnv *env, jobject thiz, jstring string) {
    printf("invoke set from C++\n");
    char* str = (char*)env->GetStringUTFChars(string,NULL);
    printf("%s\n", str);
    env->ReleaseStringUTFChars(string, str);
}

#include "com_ryg_JniTest.h"
#include <stdio.h>

JNIEXPORT jstring JNICALL Java_com_ryg_JniTest_get(JNIEnv *env, jobject thiz) {
    printf("invoke get from C\n");
    return (*env)->NewStringUTF(env, "Hello from JNI !");
}

JNIEXPORT void JNICALL Java_com_ryg_JniTest_set(JNIEnv *env, jobject thiz, jstring string) {
    printf("invoke set from C\n");
    char* str = (char*)(*env)->GetStringUTFChars(env,string,NULL);
    printf("%s\n", str);
    (*env)->ReleaseStringUTFChars(env, string, str);
}

出头文件如下所示

2)可以非常有利地动时曾有些C/C++开源库

C++:gcc -shared-I/usr/lib/jvm/java-7-openjdk-amd64/include-fPIC
test.cpp-o libjni-test.so

头颅有一个加载动态库的经过,其中jni-test是so库的标识,so库完整名称为libjni-test.so

接上篇《android开发方探索》读书笔记(十三)–综合技能

2)编译java源文件得到class文件,然后经javah命令导出JNI的条文件

JNIEnv*:表示一个针对JNI环境之指针,可以通过她来访问JNI提供的接口方法

No3:

简单单native方法get和set就是亟需以JNI中实现之道

No5:

可以参照我先的博客JNI,NDK

应用NDK有如下好处:

2)创建一个Android项目,并扬言所欲的native方法

jobject:表示Java对象吃的this

NDK会创建一个和jni目录平级的目录libs,libs下面存放的便是so库的目。

1)下载并部署NDK

于外部创建一个叫做吧jni的目,然后以jni目录下创造3单文件:test.cpp、Android.mk、Application.mk

相关文章