android jni调用流程 2019-08 jni-ndk

这篇博客详细介绍了Android JNI调用的流程,包括编写JNI工具类、使用javac -h生成JNI头文件、编写Android.mk、修改build.gradle文件以及编写cpp文件。在过程中,提到了在Android.mk中配置头文件引用和解决iostream及namespace std的解析问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、写jni工具类:

2、生成jni头文件:

在最新的jdk中,javah指令被移除,使用javac -h 指令代替,两者存在差异,javac -h指令包括两个步骤:javac生成x x x.class文件和javah生成jni头文件。javac操作的对象是java源文件,如上图中,java文件全称为:JniUtil.java,则在terminal中通过命令行找到JniUtil.java,通过命令:javac -h jni JniUtil.java  生成jni头文件; 命令中第三个参数为生成的文件夹名。执行成功之后可以在执行命令的根目录下找到一个jni文件夹,其中存在JniUtil.h头文件。

 

3、编写Android.mk

Android.mk文件主要用于静/动态库生成,文件内容如下:

LOCAL_PATH := $(call my-dir) //每个Android.mk文件必须以定义开始。它用于在开发tree中查找源文件。宏my-dir则由Build System 提供。返回包含Android.mk目录路径。

include $(CLEAR_VARS) //CLEAR_VARS变量由Build System提供。并指向一个指定的GNU Makefile,由它负责清理很多LOCAL_xxx。例如LOCAL_MODULE,LOCAL_SRC_FILES,LOCAL_STATIC_LIBRARIES等等。但不是清理LOCAL_PATH。这个清理是必须的,因为所有的编译控制文件由同一个GNU Make解析和执行,其变量是全局的。所以清理后才能便面相互影响。

LOCAL_MODULE    := jni-utils //LOCAL_MODULE模块必须定义,以表示Android.mk中的每一个模块。名字必须唯一且不包含空格。Build System 会自动添加适当的前缀和后缀。例如,demo,要生成动态库,则生成libdemo.so。但请注意:如果模块名字被定义为libabd,则生成libabc.so。不再添加前缀。

LOCAL_SRC_FILES := jniutil_JniUtil.cpp //这行代码表示将要打包的C/C++源码。不必列出头文件,build System 会自动帮我们找出依赖文件。缺省的C++ 源码的扩展名为.cpp。

include $(BUILD_SHARED_LIBRARY)  //BUILD_SHARED_LIBRARY是Build System提供的一个变量,指向一个GUN Makefile Script。它负责收集自从上次调用include $(CLEAR_VARS)后的所有

//LOCAL_xxxxinx。并决定编译什么类型
//BUILD_STATIC_LIBRARY:编译为静态库
//BUILD_SHARED_LIBRARY:编译为动态库
//BUILD_EXECUTABLE:编译为Native C 可执行程序
//BUILD_PREBUILT:该模块已经预先编译

LOCAL_SRC_FILES对应的参数是后续cpp文件的文件名,即jni源文件,不需要写头文件,只需要写cpp/c文件名称即可,因为在环境配置好之前,android studio中编写c/cpp文件如同在txt中编写一样,不太友好,所以把cpp文件的编写留在最后。

 4、修改app中的build.gradle文件:

在defaultConfig块中添加ndk块:

ndk{
    moduleName "jni-utils"
}

在android代码块中添加externalNativeBuild 和 sourceSets.main块:

externalNativeBuild {
    ndkBuild{
        path 'src/main/java/jniuitl/jni/Android.mk'
    }
}
sourceSets.main{
    jni.srcDirs = []
}

demo的build.gradle文件如下:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 27
    defaultConfig {
        applicationId "realsee.androidresearch"
        minSdkVersion 16
        targetSdkVersion 27
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        ndk{
            moduleName "jni-utils"
        }
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    externalNativeBuild {
        ndkBuild{
            path 'src/main/java/jniuitl/jni/Android.mk'
        }
    }
    sourceSets.main{
        jni.srcDirs = []
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:27.1.1'
    implementation 'com.android.support.constraint:constraint-layout:1.1.3'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}

5、makeProject并编写cpp文件

执行makeProject,在jni文件夹中创建.cpp文件,引入对应头文件,即可进行代码编写,demo的cpp文件如下:


#include "jniuitl_JniUtil.h"
JNIEXPORT jstring JNICALL Java_jniuitl_JniUtil_getStart
        (JNIEnv *env, jclass){
    return env->NewStringUTF("let's start here");
}

.h文件如下:

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

#ifndef _Included_jniuitl_JniUtil
#define _Included_jniuitl_JniUtil
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     jniuitl_JniUtil
 * Method:    getStart
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_jniuitl_JniUtil_getStart
  (JNIEnv *, jclass);

#ifdef __cplusplus
}
#endif
#endif

ending.

--------------------------------------------补充------------------------------------------------

如果在ndk中无法解析iostream 和namespace std,在android.mk中添加如下两句话:

LOCAL_C_INCLUDES := $(NDK_ROOT)/sources/cxx-stl/stlport/stlport
LOCAL_LDLIBS := $(NDK_ROOT)/sources/cxx-stl/stlport/libs/armeabi/libstlport_static.a

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值