NDK开发教程
Java世界 <-> JNI层 <-> Native世界
JNI : Java Native Interface,通常翻译为JAVA本地接口
NDK即Naive Development Kit
- NDK是一系列工具的集合
- NDK提供了工具链,帮助开发者快速开发以及调试C(或C++)的动态库
- NDK提供了一份稳定、功能有限的API库
- 不同于linux的glibc,Android采用的是 Google Bionic Libc,大部分api是一致的
- 一些重要逻辑、算法可以采用C/C++、甚至是汇编的形式通过NDK的工具链最终编译生成动态库,最后通过JNI完成和Dalvik/ART虚拟机环境中的Java代码的交互
- 使用NDK开发的so不再具有跨平台特性、需要编译提供不同平台支持ABI:Application Binary Interface
ABI | 支持的指令集 | 备注 |
---|---|---|
armeabi-v7a | armeabi | 与ARMv5/v6设备不兼容 |
Thumb-2 | ||
VFPv3-D16 | ||
armeabi-v8a | AArch64 | |
x86 | x86(IA-32) | 不支持MOVBE或SSE4 |
MMX | ||
SSE/2/3 | ||
SSSE3 | ||
x86_64 | x86-64 | |
MMX | ||
SSE/2/3 | ||
SSSE3 | ||
SSE4.1、4.2 | ||
POPCNT |
NDK 支持的架构详细信息可以在如下网页中查看
https://developer.android.google.cn/ndk/guides/abis?hl=zh_cn
如何创建一个NDK程序
File -> New -> New Project -> Native C++ , 就可以创建一个NDK程序
看一下默认创建的文件
MainActivity.java
package com.showme.ndk01;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
// Used to load the 'native-lib' library on application startup.
static {
System.loadLibrary("native-lib");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Example of a call to a native method
TextView tv = findViewById(R.id.sample_text);
tv.setText(stringFromJNI());
}
/**
* A native method that is implemented by the 'native-lib' native library,
* which is packaged with this application.
*/
public native String stringFromJNI();
}
app/src/main/cpp/native-lib.cpp
#include <jni.h>
#include <string>
extern "C" JNIEXPORT jstring JNICALL
Java_com_showme_ndk01_MainActivity_stringFromJNI(
JNIEnv* env,
jobject /* this */) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
JNI函数特征一览
extern “C” : 由于C++支持重载,C++l类中的函数会有name mangling,后面会详细介绍为什么这里必须要有extern “C”
jni函数的参数问题(参数至少是两个):JNIEnv* 和jobject(非静态函数) 以及JNIEnv *和jclass(静态函数) 从第三个参数开始,才是java层传递的自己的参数
JNICALL : 空宏,只是确定一个规则,可以被删除
JNIEXPORT:__ attribute __((visibility(“default”))),代表当前函数符号需要导出,与之对应为hidden隐藏符号信息
android studio默认生成的函数名很长,如Java_com_example_jni_1enc_jni_String_StringFromJNI,以下划线分割
public native String stringFromJNI();
public static native String StringStatic();
extern "C" JNIEXPORT jstring JNICALL
Java_com_showme_myapplication_MainActivity_stringFromJNI(
JNIEnv* env,
jobject /* this */) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
extern "C" JNIEXPORT jstring JNICALL
Java_com_showme_myapplication_MainActivity_StringStatic(
JNIEnv* env,
jclass ) {
std::string hello = "StringStatic Hello from C++";
return env->NewStringUTF(hello.c_str());
}
JNI可以使用C和CPP开发(extern “C”)
使用C语言编写程序,并在cpp中使用
testc.c
#include "testc.h"
int add_c(int a,int b){
return a+b;
}
testc.h
#ifndef ABC_TESTC_H
#define ABC_TESTC_H
#include<stdio.h>
int add_c(int a,int b);
#endif ABC_TESTC_H
在cpp中使用testc.c中的函数,需要以extern "C"的方式引入头文件
extern "C" {
#include "testc.h"
}
需要将testc.c添加到CMakeList.txt文件中
add_library( # Sets the name of the library.
native-lib
# Sets the library as a shared library.
SHARED
testc.c
# Provides a relative path to your source file(s).
native-lib.cpp )
JNI开发-日志
#include <android/log.h>
__android_log_print(int prio, const char* tag, const char* fmt, ...);
JNI当中的基本数据类型
Java类型 | 本地类型(Native Type) | 描述 |
---|---|---|
boolean | jboolean | C/C++无符号8位整形 (unsigned char) |
byte | jbyte | C/C++带符号8位整形(char) |
char | jchar | C/C++无符号16位整形(unsigned short) |
short | jshort | C/C++带符号16位整形(short) |
int | jint | C/C++带符号32位整形(int) |
long | jlong | C/C++带符号64位整形(long) |
float | jfloat | C/C++32位浮点型(float) |
double | jdouble | C/C++64位浮点型(double) |
public native int IntFromJNI(int a);
extern "C" JNIEXPORT jint JNICALL
Java_com_showme_myapplication_MainActivity_IntFromJNI( JNIEnv* env, jobject /* this */, jint a) {
returnu a + 1;
}