1. 【干货】火爆全网的《超全NDK精品教程》JNI 3分钟学会写NDK第一个Demo

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这个目录。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,529评论 5 475
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,015评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,409评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,385评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,387评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,466评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,880评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,528评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,727评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,528评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,602评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,302评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,873评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,890评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,132评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,777评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,310评论 2 342

推荐阅读更多精彩内容