1.ndk的版本
2.ndk是否成功
3.ndk在Android里面的配置
Android NDK 是在SDK前面又加上了原生二字,即Native Development Kit,因此又被Google称为NDK。
1、什么是JNI?
JNI全称 Java Native Interface , java本地化接口 ,它提供了若干的API实现了Java和其他语言的通信(主要是C&C++)。它允许Java代码和其他语言写的代码进行交互,简单的说,一种在Java虚拟机控制下执行代码的标准机制。
NDK包括了:
1、从C / C++生成原生代码库所需要的工具和build files。
2、将一致的原生库嵌入可以在Android设备上部署的应用程序包文件(application packages files ,即.apk文 件)中。
3、支持所有未来Android平台的一系列原生系统头文件和库
为何要用到NDK?
概括来说主要分为以下几种情况:
1. 代码的保护,由于apk的java层代码很容易被反编译,而C/C++库反汇难度较大(安全)。
2. 在NDK中调用第三方C/C++库,因为大部分的开源库都是用C/C++代码编写的。
3. 便于移植,用C/C++写的库可以方便在其他的嵌入式平台上再次使用。
2、JNI的优缺点
优点:
可以使用本地的代码,为java与C语言之间建立了一个桥梁
缺点:
1>、程序不再跨平台。要想跨平台,必须在不同的系统环境下重新编译本地语言部分。
2>、程序不再是绝对安全的,本地代码的不当使用可能导致整个程序崩溃。一个通用规则是,你应该让本地方法集中在少数几个类当中。这样就降低了JAVA和C之间的耦合性。
总结
NDK帮助将C/C++库打包成动态库.so,JNI是C/C++动态库能被调用的桥梁接口
JNI是java接口,用于Java与C/C++之间的交互,作为两者的桥梁
NDK是Android工具开发包,帮助快速开发C/C++动态库,相当于JDK开发java程序一样,同时能帮打包生成.so库
————————————————
3、JNI的使用场景
当你开始着手准备一个使用JNI的项目时,请确认是否还有替代方案。应用程序使用JNI会带来一些副作用。下面给出几个方案,可以避免使用JNI的时候,达到与本地代码进行交互的效果:
1、JAVA程序和本地程序使用TCP/IP或者IPC进行交互。
2、当用JAVA程序连接本地数据库时,使用JDBC提供的API。
3、JAVA程序可以使用分布式对象技术,如JAVA IDL API。
这些方案的共同点是,JAVA和C处于不同的线程,或者不同的机器上。这样,当本地程序崩溃时,不会影响到JAVA程序。
下面这些场合中,同一进程内JNI的使用无法避免:
1、程序当中用到了JAVA API不提供的特殊系统环境才会有的特征。而跨进程操作又不现实。
2、你可能想访问一些己有的本地库,但又不想付出跨进程调用时的代价,如效率,内存,数据传递方面。
3、JAVA程序当中的一部分代码对效率要求非常高,如算法计算,图形渲染等。
总之,只有当你必须在同一进程中调用本地代码时,再使用JNI。
studio下的NDK操作流程:
NDK开发思路:1、下载NDK
2、创建一个native方法,
3、通过javah生成头文件,
4、改cpp类的代码,
5、编辑c语言 ,
6、,添加application.mk文件,
7、运行
按照上述的思路开始一步一步执行
studio配置环境:
Android Studio 2.2 又重新加入了jni的支持,并且使用的是CMake,所以现在写jni不需要配置mk文件了。
eclipse找那个的 所以就不像以前那样还要安装什么cygwin。
SDK、JDK、NDK的区别
SDK软件开发工具包;英语全称:Software Development Kit
JDKJava语言的软件开发工具包;英语全称:Java Development Kit
NDK原生软件开发工具包;英语全称:Native Development Kit;被Google称为NDK
由此可见,其实不管什么XDK,都可以叫SDK,可能为了有很好的区分,便有了JDK、NDK,所以我们有的时候常说的SDK并不是特指安卓开发工具包,
而只是我们都是同行,交流的时候都知道指的是什么,其实你们会发现,我们常常接三方平台的时候,那些工具包也是叫SDK,但可能我们在交流的时候就会加个前缀,比如:微信分享SDK、支付宝SDK、xxSDK。
在项目配置中 , 关联NDK之后就会ok
《一》下载NDK
NDK的下载地址:
https://developer.android.com/ndk/index.html#Revisions
《二》配置NDK
local.properties里面可以找到SDK和NDK的路径
如果出现如下错误: NDK integration is deprecated in the current plugin. gradle.properties中添加如下配置
使用AndroidStudio开发前我们也要做点额外工作,我们需要在项目根目录下local.properties中添加编译NDK的路径:ndk.dir=/Users/liangqi/android-ndk
不要急,还没有完,ndk环境搭建还有最后一步,在gradle.properties的文件末尾加上android.useDeprecatedNdk=true这段代码,文字看不懂吧直接上图:
<三> java代码调用C的工具类,cmake不需要,自动生成
然后如下图所示重新Make Project一下工程:生成Class文件
System.loadLibrary(huazict"); 里面不用加.so也可以了
//javah -d jni -classpath E:\NdkDemo\app\build\intermediates\classes\debug ndkdemo.peng.cx.com.myapplication.JNIUtils
public class JNIUtils {
static {
System.loadLibrary("huazict");
}
public native StringgetString();
}
<四>如何生成.h文件
在studio打开Terminal命令行工具,打开步骤是View->Tool Windows->Terminal (或直接按Alt+F12),如下图所示:
输入命令:javah -d jni -classpath 自己编译后的class文件的绝对路径
.h文件生成的目录是更加你的javah指令。
javah -d jni -classpath E:\NdkTest\app\build\intermediates\classes\debug ndkdemo.peng.cx.com.myapplication.JniDemo(注意debug后的空格)
找到类所在的路径:
输入指令之后就自动生成了.h的文件.
把生成的jni目录拷贝到程序的根目录:
<五> 拷贝JNI在正确的目录下 我们在工程中创建一个文件夹jni,此目录与工程中的java目录同级,并把生成的*.h文件放置到jni文件夹中。
<六>写C语言文件
现在我们来写一个test的C文件huazict.c同.h文件一样放到jni文件夹下,代码如下:
C包含里面的头文件.h文件,就是上面生成的.h文件
#include"ndkdemo_peng_cx_com_myapplication_JNIUtils.h"
JNIEXPORT jstring JNICALL Java_ndkdemo_peng_cx_com_myapplication_JNIUtils_getString
(JNIEnv *env, jobject obj) {
return (*env)->NewStringUTF(env, "这是我测试的jni");
}
最后在构建文件中的默认配置中加上:
ndk {
moduleName "huazict" //生成的so名字
abiFilters"armeabi","armeabi-v7a","x86" //输出指定三种abi体系结构下的so库。
}
<七>编译生成SO库
Android Studio的菜单build > Rebuild Project clean 一下,然后rebuild一下,就会生成.so文件,在build/intermediates.ndk下
不是eclipse还要配置android.mk这么文件吗?android studio不用,
你还真猜对了,不过不是说不用就代表他没有,只不过这个配置过程不过你来做,你要做的就是配置上图的代码。那android.mk
<八>建立一个jniLib目录,把so库拷贝进来
运行程序,可以看到效果
public class MainActivityextends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView tv = (TextView) findViewById(R.id.sample_text);
tv.setText(new JNIUtils().getString());
}
}
总结一下流程:
编写静态方法(用java声明)-->编译生成class文件--->编译生成h文件---->编写C文件(用C/C++实现)
---->配置NDK---->配置so库---->在Activity调用(Java调用C/C++)。
自己总结的流程:
1.下载NDK
2.配置NDK
3.写JAVA类调用C
4.把JAVA生成Class
5.生成.h文件
6.写C语言
7.配置so库并编译so库
java文件如何编译生成Class文件,先到了.java的目录羡慕,然后用命令 javac 类名 javac JNIUtils.java
javah -jni com.example.binbin.testjni.myJNI
生成头文件;Javah ndktest.peng.cx.com.myapplication.JNIUtils
得到函数的签名:快速的方法
方式二:
创建NDK项目(方式二)
第一步 , 创建支持C++的项目
在创建项目的时候 , 勾选了C++ support , 项目创建完成之后 , 会自动帮我们生成一个
好用,写.h文件,相同的效果(自己的博客链接)
http://www.2cto.com/kf/201607/526887.html
http://www.cnblogs.com/wzben/p/5733571.html
NDK调用完美,高级版本,最新采用cpp
studio2.2版本
http://blog.csdn.net/dagaozi/article/details/52784635
http://www.jianshu.com/p/f1b8b97d2ef8(cMake)
http://blog.csdn.net/qq_35064774/article/details/52955242?locationNum=4&fps=1
JNI调用
http://www.jianshu.com/p/aba734d5b5cd
Jni系列教程
http://www.jianshu.com/p/68bca86a84ce
jni步骤开发:
https://www.jianshu.com/p/58a551c0c09f
https://blog.csdn.net/qq_21556263/article/details/84144396
1.注意路径
2.生成多个so的版本,在gradle里面配置
3.修改生成的路径
4.rebuild和运行的区别
5.修改了生成路径报重复的问题
Debug和Release模式 && 静态和动态编译
1.Release和Debug的区别
Release版称为发行版,Debug版称为调试版。
Debug中可以单步执行、跟踪等功能,但生成的可执行文件比较大,代码运行速度较慢。Release版运行速度较快,可执行文件较小,但在其编译条件下无法执行调试功能。
Release的exe文件链接的是标准的MFC DLL(Use MFC in a shared or static dll)。这些DLL在安装Windows的时候已经配置,所以这些程序能够在没有安装Visual C++的机器上运行。而Debug版本的exe链接了调试版本的MFC DLL文件,在没有安装Visual C++的机器上不能运行,因为缺相应的DLL,除非选择use static dll when link。
Debug 和 Release 并没有本质的区别,他们只是VC预定义提供的两组编译选项的集合,编译器只是按照预定的选项行动。如果我们愿意,我们完全可以把Debug和Release的行为完全颠倒过来。当然也可以提供其他的模式,例如自己定义一组编译选项,然后命名为MY_ABC等。习惯上,我们仍然更愿意使用VC已经定义好的名称。
Debug版本包括调试信息,所以要比Release版本大很多(可能大数百K至数M)。至于是否需要DLL支持,主要看你采用的编译选项。如果是基于ATL的,则Debug和Release版本对DLL的要求差不多。如果采用的编译选项为使用MFC动态库,则需要MFC42D.DLL等库支持,而Release版本需要MFC42.DLL支持。Release不对源代码进行调试,不考虑MFC的诊断宏,使用的是MFC Release库,编译时对应用程序的速度进行优化,而Debug则正好相反,它允许对源代码进行调试,可以定义和使用MFC的 诊断宏,采用MFC Debug库,对速度没有优化。
既然Debug和Release仅仅是编译选项的不同,那么为什么要区分Debug和Release版本呢?
Debug和Release,在我看来主要是针对其面向的目标不同的而进行区分的。Debug通常称为调试版本,通过一系列编译选项的配合,编译的结果通常包含调试信息,而且不做任何优化,以为开发人员提供强大的应用程序调试能力。而Release通常称为发布版本,是为用户使用的,一般客户不允许在发布版本上进行调试。所以不保存调试信息,同时,它往往进行了各种优化,以期达到代码最小和速度最优。为用户的使用提供便利。
NDK和CMake 的下载和安装
local.properties文件, 在里面添加:
//后面改成自己下载后解压的路径名ndk.dir=C\:\\Users\\Lulu\\AppData\\Local\\Android\\android-ndk-r13
CMake:一个跨平台的编译构建工具,替代 Android.mk
LLDB:一个高效的 C/C++ 的调试工具
NDK:即我们需要下载的工具,会生成到 SDK 根目录下的 ndk-bundle 目录下
1. JNI 是什么
JNI 是 Java Native Interface 的缩写,即 Java 的本地接口。
2. NDK 是什么
NDK 是 Native Development Kit 的缩写,是 Android 的工具开发包。
作用是快速开发 C/C++ 的动态库,并自动将动态库与应用一起打包到 apk。
NDK 是属于 Android 的,与 Java 无直接关系。
————————————————
NDK两种开发模式
ndk-build 形式; Android Studio 2.2之前的模式
CMake 形式: CLion C/C++编辑器; AS2.2之后整合了CLion代码, AS就支持了CMake形式的NDK开发
第一种方式:CMake 形式:
1.直接建立项目,include C++
2.项目配置NDK
ndk.dir=/Users/mac/Library/Android/sdk/ndk-bundle
sdk.dir=/Users/mac/Library/Android/sdk
3.cMakeList:定义cmakeListd的路径
externalNativeBuild {
cmake {
path"CMakeLists.txt"
}
}
cmake的版本:如果版本不对,会有问题。
4.点击Link C++ Project with Gradle
右击jni目录,选择Link C++ Project with Gradle标签
5.修改生成so库都类型
externalNativeBuild {
cmake {
cppFlags ""
abiFilters "armeabi-v7a"
}
}
添加java方法,studio自动提示,会写好方法名。
都是自动生成文件
注意:类名和方法名不要乱改,否则会找不到。
CMakeLists.txt文件解析:
# 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)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/jniLibs/${ANDROID_ABI})
# 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.
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)
# 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.
target_link_libraries( # Specifies the target library.
native-lib
# Links the target library to the log library
# included in the NDK.
${log-lib})
来源:https://www.jianshu.com/p/65013d2b14fa
1.cmake_minimum_required(VERSION 3.4.1)
用来声明编译本地库文件时需要的Cmake最小版本,在AndroidStudio构建版本时会自动生成;
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY
{ANDROID_ABI})
将libxx.so生成到jniLibs文件夹下
2.add_library()
native-lib : 编译本地本地lib生成的库文件的名称
SHARED : (生成的库种类)SHARED表示编译生成的是动态链接库
src/main/cpp/native-lib.cpp : 表示编译文件的相对路径,这里可以是一个文件的路径也可以是多个文件的路径
3.find_library()
这个的作用是声明编译本地库的时候,需要用的到一些依赖库.
log-lib 是这个库的别名,方便我们以后引用
log 是我们调试的时候打印log的一个库
4.target_link_libraries()
target_link_libraries( # Specifies the target library.
native-lib
# Links the target library to the log library
# included in the NDK.
${log-lib})
目的是用来关联我们本地的库跟第三方的库.这里就是把native-lib库和log库关联起来.
重要的方法:
cmkelist。里面打印日志:
set(var hello)
message($var )
头文件用<>,比如:#include
#include "people/people.h"
如果要用<>,在cmake里面,把people文件夹路径定义: include _directory(people/)
cmake主要是:
修改native-lib.cpp
这时候我们修改下native-lib.cpp,native-lib.cpp内容如下:
Cmake错误查找:
CMake Error at CMakeLists.txt:40 (target_link_libraries):
Cannot specify link libraries for target "mobilenetssdncnn" which is not
built by this project.
修改so的名字:要2个地方都要改
add_library(tongueorSDK SHARED mobilenetssdncnn_jni.cpp)
target_link_libraries(tongueorSDK
ncnn
glslang SPIRV OGLCompiler OSDependent
android
z
log
jnigraphics
vulkan
)
# sources directories
aux_source_directory(./src SRCS_src)
aux_source_directory(./src/models SRCS_models)
aux_source_directory(./src/tongue SRCS_tongue)
# .h search directory
include_directories(src src/models src/tongue)
include_directories(3rdparty/ncnn/include)
include_directories(3rdparty/opencv340/include)
link_directories(${CMAKE_SOURCE_DIR}/3rdparty/ncnn/lib/${ANDROID_ABI})
link_directories(${CMAKE_SOURCE_DIR}/3rdparty/opencv340/lib/${ANDROID_ABI})
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -mfpu=neon ")
FIND_PACKAGE(OpenMP REQUIRED)
if(OpenMP_CXX_FOUND OR OPENMP_FOUND)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}")
endif()
# main libdriverbehavior.so
add_library(tongueorSDK SHARED ${SRCS_src} ${SRCS_models} ${SRCS_tongue})
#target_link_libraries(tongue ncnn yuv opencv_java3 jnigraphics dl log)
target_link_libraries(tongueorSDK ncnn opencv_java3 jnigraphics dl log)
target_link_libraries:里面所有用到或者生成的so库
依赖的第三方so库
link_directories(${CMAKE_SOURCE_DIR}/3rdparty/ncnn/lib/${ANDROID_ABI})
link_directories(${CMAKE_SOURCE_DIR}/3rdparty/opencv340/lib/${ANDROID_ABI})
依赖的.h.cpp文件目录
include_directories(src src/models src/tongue)
include_directories(3rdparty/ncnn/include)
include_directories(3rdparty/opencv340/include)
6.为什么代码没有跳转,无法关联?解决c语言调试问题
Android Studio JNI代码突然无法跳转
AndroidStudio3.2 + gradle 4.6 下突然无法是用 ctrl + 左键 跳转代码。选中代码点击时出现 “Cannot find declaration to go to” 提示. 经过了换 SDK 后比对发现,如果JNI 代码出现这个问题,一般就是 CMake 版本不对。我换成3.6.xxx就好用了。3.10.xxx不知道为何跳转不了代码。
打开 SDK manager, 在 SDK tools 中,选中右下角的 show package details ,可以查看 cmake 版本。如果是 3.10.xxx ,取消选中,换成下面的 3.6.xxx, Apply 后自动下载安装。完成后应该就可以了。
cmake的版本有关系;安装,卸载,安装试试,版本切换下
7.so库,如何断点?
安装C++调试器LLDB插件:
每次断点的时候,要等LLDB准备完成才开始断点。
android cmake生成的mk文件在哪
NDK开发新增cpp文件,cpp目录下看不到 报This file is not part of the project. Pelase include it in the appropriate
Java注册C++回调接口
默认是通过源代码,及时生成的so库
如何把so库放lib里面配置调用呢?
把build自动生成so的代码屏蔽掉。
//去生成so库类型的配置
// externalNativeBuild {
// cmake {
// cppFlags ""
// abiFilters "armeabi-v7a"
// }
// }
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'),'proguard-rules.pro'
}
}
// externalNativeBuild {
// cmake {
// path "CMakeLists.txt"
// }
// }
//会引用libs里面的
sourceSets {
main {
jniLibs.srcDirs = ['libs']
}
}
}
build下面就不会生成cmake这个目录。