JNI开发(基于AS高低版本说明)

更新了Android Studio版本之后,在按照之前的方式搭建JNI的开发环境,发现不断的报错,通过查看日志发现,android.useDeprecatedNdk不再支持了让,使用CMake or ndk-build。本文介绍了在低版本和高版本上分别怎么实现,以及总结在搭建过程中遇到的错误和解决办法。

Android Studio 2.2版本以下

1.首先通过SDKManager-SDK Tools下载NDK插件

2.在local.properties文件里面配置NDK路径:

一种方式是在该文件中直接填写NDK的路径

另一种方式是在SDK Location里面配置:在项目上右键->选择open Moulde Settings

3.在在gradle.properties文件中追加下面代码:
android.useDeprecatedNdk=true
4.使用native关键字编写JNI接口
public class JNIUtils {
    public static native String getStringFromC();
}

编写之后,make project,在工程目build\intermediates\classes\debug\自己的包名下就可以看到编译后的class文件JNIUtils.class如下图所示:

5.使用javah命令生成.h头文件

5.1 打开Terminal,然后在命令行中先进入到工程的build\intermediates\classes\debug目录下(cd 直接拖拽debug目录即可)
5.2 输入命令:javah 包名.类名
“`
javah com.bysj.myapplication.JNIUtils

在debug目录下就会生成对应的头文件(.h文件)
![](https://upload-images.jianshu.io/upload_images/1797490-7e0d526371cf522d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

####6. 实现上述头文件里面的方法
6.1 在main目录下新建jni文件夹
![](https://upload-images.jianshu.io/upload_images/1797490-512c5b4a8cd42089.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
6.2 将上述的头文件复制进来,文件名可以随意该,但是内容不能改。
6.3 新建一个c或者c++源文件实现头文件中的方法,并在源文件中引入头文件(此处我自己建立的是C++的文件)

include “com_bysj_jniapplication_JNIUtils.h” //头文件的名字要对应

JNIEXPORT jstring JNICALL Java_com_bysj_jniapplication_JNIUtils_getStringFromC
(JNIEnv *env, jclass) {
return env -> NewStringUTF(“Hello from C++”);
}

####7. 添加NDK配置
7.1 开发app内build.gradle,在android/defaultConfig下面添加ndk配置

android {
。。。。。。
defaultConfig {
。。。。。。
ndk {
moduleName “JNISample” //生成so库的名字
}
}
buildTypes {
。。。。。。
}
}

7.2 加载so库,在JNIUtils类中添加以下的代码:

public class JNIUtils {
static {
System.loadLibrary(“JNISample”);//名字要与build.gradle中配置的一致
}
public native static String getStringFromC();
}

最后编译运行,可以看到结果:
![](https://upload-images.jianshu.io/upload_images/1797490-292b912b646b07b9.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

###以上是在AS2.2版本以下这样做会成功,但是在2.2以后在编译的时候会报以下的错误:

![](https://upload-images.jianshu.io/upload_images/1797490-c4b77caefc905b7b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

我们仔细看下Log,大概意思就是说:
1.  android.useDeprecatedNdk不再支持了
2.  让使用CMake or ndk-build
3.  然后还有链接
考虑使用CMake或ndk构建集成。要了解更多信息,请访问:
[https://d.android.com/r/studio-ui/add-native-code.html#ndkCompile](https://d.android.com/r/studio-ui/add-native-code.html#ndkCompile)
首先,您可以使用Android的ndk构建脚本示例插件为您生成:
/Users/apple/Desktop/AndroidJNITest/app/build/intermediates/ndk/debug/Android.mk
或者,你可以使用实验插件:
[https://developer.android.com/r/tools/experimental-plugin.html](https://developer.android.com/r/tools/experimental-plugin.html)
继续使用已弃用的NDK编译60天,设置在gradle.properties
android.deprecatedNdkCompileLease = 1523416167903(这个测试不起作用)
经过各种查资料,发现原来在gradle3.0以上以前这种方法不再支持

###所以在AS2.2版本以后进行NDK开发要使用CMake,下面演示以下具体的实现方法(你会发现很简单,省去类很多的事)
##Android Studio 2.2版本以上
####1. 先通过SDKManager下载:CMake和LLDB
![](https://upload-images.jianshu.io/upload_images/1797490-dfd243342993575d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

####2.在新建项目的时候勾选 Include C++ Support
![](https://upload-images.jianshu.io/upload_images/1797490-2f08d885b0618894.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

接下来的步骤跟创建普通项目一样。

2.1 配置C++支持功能(Customize C++ Support)在Customize C++ Support界面默认即可。
![](https://upload-images.jianshu.io/upload_images/1797490-306fa9628efaf7d0.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

* #####C++ Standard
指定编译库的环境,其中Toolchain Default使用的是默认的CMake环境;C++ 11也就是C++环境。两种环境都可以编库,至于区别,后续会跟进,当前博文使用的是CMake环境。

* #####Exceptions Support
如果选中复选框,则表示当前项目支持C++异常处理,如果支持,在项目Module级别的build.gradle文件中会增加一个标识 -fexceptions到cppFlags属性中,并且在so库构建时,gradle会把该属性值传递给CMake进行构建。

* #####Runtime Type Information Support
同理,选中复选框,项目支持RTTI,属性cppFlags增加标识-frtti

点击完成,Android Studio会自动把JIN开发的环境搭建好,可以直接运行,比起低版本的是不是省很多事啊!

勾选了 Include C++ Support以后,会自动在build.gradle中添加以下配置

android {
compileSdkVersion 27
defaultConfig {
。。。。。。。。
externalNativeBuild {
cmake {
cppFlags “”
}
}
}
externalNativeBuild {
cmake {
path “CMakeLists.txt” //该文件用于配置JNI项目属性
}
}
}


####3.CMakeLists.txt文件说明
CMakeLists.txt文件用于配置JNI项目属性,主要用于声明CMake使用版本、so库名称、C/CPP文件路径等信息,下面是该文件内容:

Sets the minimum version of CMake required to build the native

library. You should either keep the default value or only pass a

value of 3.4.0 or lower.

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 it for you.

Gradle automatically packages shared libraries with your APK.

add_library( # Sets the name of the library.
# 设置so文件名称
native-lib

         # Sets the library as a shared library.
         SHARED

         # Provides a relative path to your source file(s).
         # Associated headers in the same location as their source
         # 设置这个so文件为共享.
         # file are automatically included.
         src/main/cpp/native-lib.cpp )

Searches for a specified prebuilt library and stores the path as a

variable. Because system libraries are included 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 )

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} )

“`

  • cmake_minimum_required(VERSION 3.4.1)
    CMake最小版本使用的是3.4.1。

    • add_library()
      配置so库信息(为当前当前脚本文件添加库)

    • native-lib
      这个是声明引用so库的名称,在项目中,如果需要使用这个so文件,引用的名称就是这个。值得注意的是,实际上生成的so文件名称是libnative-lib。当Run项目或者build项目是,在Module级别的build文件下的intermediates\transforms\mergeJniLibs\debug\folders\2000\1f\main下会生成相应的so库文件。* SHARED
      这个参数表示共享so库文件,也就是在Run项目或者build项目时会在目录intermediates\transforms\mergeJniLibs\debug\folders\2000\1f\main下生成so库文。此外,so库文件都会在打包到*.apk里面,可以通过选择菜单栏的Build->Analyze Apk…查看apk中是否存在so库文件,一般它会存放在lib目录下。

    • src/main/cpp/native-lib.cpp
      构建so库的源文件。

STATIC:静态库,是目标文件的归档文件,在链接其它目标的时候使用。
SHARED:动态库,会被动态链接,在运行时被加载。
MODULE:模块库,是不会被链接到其它目标中的插件,但是可能会在运行时使用dlopen-系列的函数动态链接。
更详细的解释请参考这篇文章:C++静态库与动态库

下面的配置实际上与自定义的JNI项目(自定义的so库)没有太大关系。

  • find_library()
    这个方法与我们要创建的so库无关而是使用NDK的Apis或者库,默认情况下Android平台集成了很多NDK库文件,所以这些文件是没有必要打包到apk里面去的。直接声明想要使用的库名称即可(猜测:貌似是在Sytem/libs目录下)。在这里不需要指定库的路径,因为这个路径已经是CMake路径搜索的一部分。如示例中使用的是log相关的so库。

  • log-lib
    这个指定的是在NDK库中每个类型的库会存放一个特定的位置,而log库存放在log-lib中

  • log
    指定使用log库

  • target_link_libraries()
    如果你本地的库(native-lib)想要调用log库的方法,那么就需要配置这个属性,意思是把NDK库关联到本地库。

  • native-lib
    要被关联的库名称

  • loglib l o g − l i b 要 关 联 的 库 名 称 , 要 用 大 括 号 包 裹 , 前 面 还 要 有 符号去引用。

实际上,我们可以自己创建CMakeLists.txt文件,而且路径不受限制,只要在build.gradle中配置externalNativeBuild.cmake.path来指定该文件路径即可。

说明

AS2.2版本以后不会再创建jin文件夹,而创建的是cpp文件夹

总结

Android Studio2.2以上版本进行JNI开发,只需要在新建项目的时候勾选 Include C++ Support选项,AS会自动帮我们搭建好JNI开发环境,我们只需要改成我们需要的文件名即可。相比低版本的各种配置,是简单方便了很多。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值