概念
原生开发工具包(英语:native development kit,简称NDK)是一种基于原生程序接口的软件开发工具。通过此工具开发的程序直接以本地语言运行,而非虚拟机。因此只有java等基于虚拟机运行的语言的程序才会有原生开发工具包。
NDK帮助开发者快速地开发C(或C++)的动态库,自动将so和java应用一起打包到Apk
NDK提供工具以便JNI调用C/C++,而且提供了交叉编译器(交叉编译是在一个平台上生成另一个平台上的可执行代码。同一个体系结构可以运行不同的操作系统;同样,同一个操作系统也可以在不同的体系结构上运行。)可以修改.mk文件生成特定CPU平台的动态库。
NDK和JNI的关系
简单说就是JNI负责Java与C/C++进行互相操作,NDK提供工具方便在Android平台使用JNI。
通过实例了解NDK的用法
环境要求
1.Android studio3.X(老版本操作不太一样)
2.AS里安装安卓虚拟机
3.jdk配置
正式开始
1.建立一个空的安卓工程

2.安装NDK
选择File->project Structure->SDK Location->Android NDK location
两种安装方式
1.官网下载,在这里填写路径
2.没安装的情况下这里会有一个蓝色的download点击自动安装最新版本
这里安装完local.properties里会自动加上路径
手动在gradle.properties里面加上:
android.useDeprecatedNdk=true
(新版本好像不用加,不过建议加一下,最多警告一下弃用)
3.新建jni类,依次点击app–>src–>main–>java–>com.example.myapplication新建一个java类
(创建出来是.class结尾的我这里是已经ndk-build后的)
代码如下:
package com.example.myapplication;
public class JNITest {
JNITest(){
System.loadLibrary("JniLib");
}//加载动态链接库,名字要与后面建的一致
public native String getString();
//这个方法后面在C里面实现
}
4.在main下建一个jni文件夹来放.h头文件

5.建立头文件
alt+f12进入终端,直接是你的工程目录cd app/src/main
javac 命令生成.h头文件的格式为:
javac -encoding utf8 -h 目标文件夹 源文件夹
以我的为例
javac -encoding utf8 -h .\jni .\java\com\example\example\JNITest.java
然后就会发现生成了头文件
文件内容如下:(这个是自动生成的不用改)
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_example_myapplication_JNITest */
#ifndef _Included_com_example_myapplication_JNITest
#define _Included_com_example_myapplication_JNITest
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_example_myapplication_JNITest
* Method: getString
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_example_myapplication_JNITest_getString
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
6.在jni目录下新建:Android.mk、Application.mk
Android.mk
LOCAL_PATH := $(call my-dir) #不用修改
include $(CLEAR_VARS) #不用修改
LOCAL_MODULE := JniLib #动态库名称和上面的一样
LOCAL_SRC_FILES =: JniLib.cpp #Cpp文件,里面就是我们写的Cpp代码
include $(BUILD_SHARED_LIBRARY) #生成.so动态库
Application.mk
APP_MODULES := JniLib
APP_ABI := all
7.编写JniLib.cpp
在jni文件夹里建c++文件JniLib.cpp(和上面名字一样)
这里基本是头文件里的加个参数就能用了包名按自己的改用"下划线_"连接
#include <jni.h>
#include<com_example_myapplication_JNITest.h>
#include<stdio.h>
#include<iostream>
extern "C" JNIEXPORT jstring JNICALL Java_com_example_myapplication_JNITest_getString
(JNIEnv * env, jobject clazz){
return env->NewStringUTF("C++ Hello World");
}
8、将java文件链接到C++文件:
右键java文件夹–》Link C++…->选择ndk-build,Project Path是Android.mk的地址
9.添加ndk节点、sourceSets节点、task ndkBuild节点:
进入app文件夹下的build.gradle文件:
apply plugin: 'com.android.application'
android {
compileSdkVersion 29
buildToolsVersion "29.0.3"
defaultConfig {
applicationId "com.example.myapplication"
minSdkVersion 21
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
ndk{
moduleName "JniLib"
abiFilters "armeabi-v7a", "x86" //输出指定的三种abi体系下的so库"armeabi",只加载armabi架构(目录下)的so库,如果是别的架构,就会找不到
}
sourceSets{ //不配的话都会有一个默认值 可以指定哪些源文件(或文件夹下的源文件)要被编译,哪些源文件要被排除
main{
jni.srcDirs = [] //禁用as自动生成mk
//jniLibs.srcDirs=["src/main/libs" ] //so包就去src/main/libs目录下找
}
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
task ndkBuild(type:Exec,description:'Compile JNI source via NDK'){
commandLine "D:\\androidsdk\\ndk-bundle\\ndk-build.cmd",//配置ndk的路径
'NDK_PROJECT_PATH=build/intermediates/ndk',//ndk默认的生成so的文件
'NDK_LIBS_OUT=src/main/libs',//配置的我们想要生成的so文件所在的位置
'APP_BUILD_SCRIPT=src/main/jni/Android.mk',//指定项目以这个mk的方式
'NDK_APPLOCATION_MK=src/main/jni/Application.mk'//指定项目以这个mk的方式
}
externalNativeBuild {
ndkBuild {
path file('src/main/jni/Android.mk')
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
}
10.生成动态库
在工具里配置ndk-build
program是配ndk-build.cmd的地址在上面安装的ndk-build里面
Working directory是你的工程目录
选中JNITest类右键->External Tools->ndk-build,生成so文件:
11.mainActivity和布局文件
package com.example.myapplication;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
Button button;
TextView ndk;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button = findViewById(R.id.button);
ndk = findViewById(R.id.ndk);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
ndk.setText("结果:"+ new JNITest().getString());
//tv.setText("结果:");
}
});
}
}
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/ndk"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="---调用之前---"
android:textSize="@android:dimen/app_icon_size"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="调用JNI"
tools:layout_editor_absoluteX="30dp"
tools:layout_editor_absoluteY="30dp"
tools:ignore="MissingConstraints"/>
</androidx.constraintlayout.widget.ConstraintLayout>
12.运行结果
点击调用之前
点击调用
作者:韦天钰
原文链接:https://blog.csdn.net/qq_43425012/article/details/106728040