1. 搭建环境
环境变量:
sudo apt-get remove openjdk*
export JAVA_HOME=/opt/java/jdk1.8.0_211
export JRE_HOME=${JAVA_HOME}/jre
export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib
export NDK=/opt/java/android-ndk-r13b
export ANDROID_SDK=/opt/Sdk
export PATH=.:${JAVA_HOME}/bin:$PATH:$NDK:$ANDROID_SDK/platform-tools:$ANDROID_SDK/tools
-----------------------ndk13------------------------------------------------------------------------------------------------------------
export CC=/opt/java/android-ndk-r13b/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/arm-linux-androideabi-gcc
echo $CC #编译arm 下执行gcc
export CFCAGS="--sysroot=/opt/java/android-ndk-r13b/platforms/android-21/arch-arm"
#参数 指定编译头文件
$CC $CFCAGS -fPIC -shared -o libTest.so hello.c -I. # 生成 arm 平台下 的动态库libTest.so
$CC $CFCAGS -c hello.c -o hello.o
ar -crsv libStaticTest.a hello.o #生成静态库libStaticTest.a
------------------ndk 16-------------------------------------------------------------------------------------------------------------------
export CC=/opt/android-ndk-r16-beta1/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/arm-linux-androideabi-gcc
echo $CC #编译arm 下执行gcc
export CFCAGS="--sysroot=/opt/android-ndk-r16-beta1/platforms/android-21/arch-arm -isysroot /opt/android-ndk-r16-beta1/sysroot -isystem /opt/android-ndk-r16-beta1/sysroot/usr/include/arm-linux-androideabi"
#参数 指定编译头文件
$CC $CFCAGS -fPIC -shared -o libTestDynastic.so hello.c -I.
ndk 16 头文件单独放入了android-ndk-r16-beta1/sysroot 目录下
----------------------------------------------------------------------------------------
--sysroot=XX
使用xx作为这一次编译头文件与库的查找目录, 默认查找下面/usr/include usr/lib目录
--isysroot xx
头文件查找目录,覆盖--sysroot,查找XX/usr/include
-IXX
头文件查找目录
-LXX
指定库文件目录
-xx.so
指定需要链接的库名
优先级: -I > -isystem > sysroot
hello.c源文件:
#include <stdio.h>
#include <stdlib.h>
int test(){
printf("test test ");
return 1000000;
}
int test2(){
printf("test2 test2 ");
return 1;
}
void main(){
test();
test2();
}
2.1 新建android工程, Include C++ Support
2.2. 拷贝so 库静态库 放入到指定 编译环境目录 下 库名:libTest.so、libStaticTest.a
2.3. native-lib.cpp 中 调用 so库函数
Java :
/**
* A native method that is implemented by the 'native-lib' native library,
* which is packaged with this application.
*/
public native String stringFromJNI();
native-lib.cpp
#include <jni.h>
#include <string>
#include <android/log.h>
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, "JNI", __VA_ARGS__)
// c++ 中调用 c ,必须 要 extern "C"
extern "C" {
extern jint test(); // 1000000, static test
extern jint test2(); // 1, dynastic test
}
extern "C"
JNIEXPORT jstring
JNICALL
Java_dn_denganzhi_com_myapplication_MainActivity_stringFromJNI(
JNIEnv *env,
jobject /* this */) {
jint r= test();
LOGE(" test1---%d",r);
int r2= test2();
LOGE(" test2---%d",r2);
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
2.4. 修改 CMakeLists.txt指定编译的时候 链接 libTest.so 库 , 编译动态库,指定红色的即可
# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html# Sets the minimum version of CMake required to build the native library.
cmake_minimum_required(VERSION 3.4.1)
# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.
# 主文件 编译生成库名 动态库 路径
add_library( # Sets the name of the library.
native-lib# Sets the library as a shared library.
SHARED# Provides a relative path to your source file(s).
src/main/cpp/native-lib.cpp )# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.
# 连接log
find_library( # Sets the name of the path variable.
log-lib# Specifies the name of the NDK library that
# you want CMake to locate.
log )# 设置一个变量
# CMAKE_CXX_FLAGS c++的参数,会传递给编译器
# CMAKE_C_FLAGS c
# 编译的时候传递参数需要连接so
# 动态库生成可执行程序的时候链接:
# 3.gcc main.c -o main -I. -L. -lsy : 生成可执行程序
# -L 指定动态库的路径 libTestDynastic.so
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -L${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}")
# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.
# 表示以引入静态库的方式引入StaticTest
#add_library(StaticTest STATIC IMPORTED)
# 设置目标导入路径,这里是一行
#set_target_properties(StaticTest PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libStaticTest.a)# 使用message 输出 cmake 内置变量
message("ANDROID_ABI : ${ANDROID_ABI}")# 第一个参数目标so
# 编译native-lib 模块需要 StaticTest 模块
target_link_libraries( # Specifies the target library.
native-lib
# StaticTest # 静态库编译链接
TestDynastic #动态库编译链接,指定动态库名,去头lib去尾巴so
# Links the target library to the log library
# included in the NDK.
${log-lib} )
2.5. gradle配置 abiFilters生成架构库
apply plugin: 'com.android.application'
android {
compileSdkVersion 27
defaultConfig {
applicationId "dn.denganzhi.com.myapplication"
minSdkVersion 15
targetSdkVersion 27
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake {
cppFlags ""
abiFilters "armeabi-v7a"
}
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
}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'
}
2.6. 加载库, 调用native方法运行,输出结果
调用:
package dn.denganzhi.com.myapplication;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
// Used to load the 'native-lib' library on application startup.
static {
// System.loadLibrary("Test");
System.loadLibrary("native-lib");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void showMsg(View view){
stringFromJNI();
}
/**
* A native method that is implemented by the 'native-lib' native library,
* which is packaged with this application.
*/
public native String stringFromJNI();
}
输出结果:
静态库配置:
# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html# Sets the minimum version of CMake required to build the native library.
cmake_minimum_required(VERSION 3.4.1)
# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.
# 主文件 编译生成库名 动态库 路径
add_library( # Sets the name of the library.
native-lib# Sets the library as a shared library.
SHARED# Provides a relative path to your source file(s).
src/main/cpp/native-lib.cpp )# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.
# 连接log
find_library( # Sets the name of the path variable.
log-lib# Specifies the name of the NDK library that
# you want CMake to locate.
log )# 设置一个变量
# CMAKE_CXX_FLAGS c++的参数,会传递给编译器
# CMAKE_C_FLAGS c
# 编译的时候传递参数需要连接so
# 动态库生成可执行程序的时候链接:
# 3.gcc main.c -o main -I. -L. -lsy : 生成可执行程序
# -L 指定动态库的路径 libTestDynastic.so
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -L${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}")
# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.
# 表示以引入静态库的方式引入StaticTest
add_library(StaticTest STATIC IMPORTED)
# 设置目标导入路径,这里是一行
set_target_properties(StaticTest PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libStaticTest.a)# 使用message 输出 cmake 内置变量
message("ANDROID_ABI : ${ANDROID_ABI}")# 第一个参数目标so
# 编译native-lib 模块需要 StaticTest 模块
target_link_libraries( # Specifies the target library.
native-lib
StaticTest # 静态库编译链接
# TestDynastic #动态库编译链接,指定动态库名,去头lib去尾巴so
# Links the target library to the log library
# included in the NDK.
${log-lib} )
运行输出结果:
注意:
在4.4以上,如果load一个动态库,需要先将这个动态库的依赖的其他动态库load进来
6.0以下, System.loadLibrary 不会自动为我们加载依赖的动态库
6.0以上,System.loadLibrary 会自动为我们加载依赖动态库