Android使用JNI生成.so文件并调用(使用传统生成.h的方法)
JNI就是Java-Native-Interface的缩写,它提供了若干API实现了Java和其他语言的通信(在Android中主要是C/C++)
Android调用jni在Android studio2.2版本前后是一个分水岭,之前提供的API在Android studio3.0之后被删除了,我们先回顾一下之前是怎么调用的:
- 首先写一个java类,这个方法名有可能报红,不要担心,当我们最后使用.so调用这个方法的就正常了。
- 然后用命令行生出来一个jni文件夹,首先我们要配置好jdk和ndk的环境,将当前位置指向我们的项目路径,但是我们需要明白的是:这一步生成.h的头文件是通过命令行编译.class文件形成的,当第一步完成后build->make Project重构代码,让项目中的代码生成java文件对应的class文件,找到这个文件对应的路径,在命令窗口,使用命令行生成对应的.h文件
- 这一步做完之后我们能看到,在项目根目录生成一个jni文件夹,但是这个位置我们是不能用的,那么应该怎么做呢,我们需要在main目录下新建一个jni文件夹,可以这样去生成这个文件夹 当生成jni这个文件夹后,将项目根目录下的jni文件夹中生成的.h文件复制到main目录下的jni文件夹中,这个时候我们只是声明了c或者cpp的方法,接下来继续创建一个.c文件,这一段c代码和上一步生成的.h头文件要绑定联系起来就是#include ".h文件带后缀全部复制过来",然后再JNICALL 调用的后边方法名称要和.h 头文件的方法名完全相同,不然会找不到我们在第一步声明的方法,这个是c的写法,如果我们习惯使用cpp(也就是c++语言),return env->NewsStringUTF((char *)"hello,jni!!")
- 方法我们现在实现了,那么应该如何调用,首先引入动态库:
package test.test;import android.support.v7.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.libName需要和build.gradle ndk节点下面的名字一样 static { //这个名字需要和build.gradle ndk节点中一致 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 = (TextView) 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();}
native-lib,就是我们要生成的.so文件名,这样在stringFromJNI()方法中获取到的String类型的数据就是.so文件中对应的函数传输的数据。
5、现在是最重要的一步,应该怎么生成.so文件呢?
- 在根目录gradle.properties下面加上:Android.useDeprecatedNdk=true这个意思就是允许使用低版本的NDK
- 在model下面的build.gradle中加上ndk节点具体位置如下图:Android{}中,defaultConfig括号下面建立ndk文件夹
注意:moduleName这里的名字要跟引入动态库的名字一样,按理说有这两步我们就可以了,实际上是不行的,我们先看看log
在这里当时我郁闷了好久,自己写的代码和别人的完全一样,步骤和配置也都是正确的,用有道翻译了半天才发现,这是因为AS在3.0以后推荐我们使用CMake来集成使用JNI-NDK开发,那么完全使用CMake开发模式后续再学习,这里引申出一个问题,假如接手一个老项目,AndroidAPI还手动调高了,系统强制使用CMake的开发方式,那么我们应该怎么办?
1、先通过SDKManager下载:CMake和LLD
2、在build.gradle的defaultConfig节点下加入:
android { compileSdkVersion 26 defaultConfig { applicationId "test.test" minSdkVersion 15 targetSdkVersion 26 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" externalNativeBuild { cmake { cppFlags "" } } }}
3、在build.gradle的android节点下加入: // 配置CMakeLists.txt路径 externalNativeBuild { cmake { path "CMakeLists.txt" // 设置所要编写的c源码位置,以及编译后so文件的名字 } }
如图所示:
4、添加CMakeLists.txt文件到build.gradle文件的统计目录下,具体内容如下:
# 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.#CMakeLists.txtcmake_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. # 设置so文件名称. testJNI # Sets the library as a shared library. SHARED # 设置这个so文件为共享. # Provides a relative path to your source file(s). # 配置这个so文件的位置. src/main/jni/testjni.c) # 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. # 制定目标库. testJNI # Links the target library to the log library # included in the NDK. ${log-lib} )
注意:这里需要更改的就是写了注释的这几句,第一处和第三处都是讲其更改为so文件的名字,第二处代表或者说位置指向了(我们在jni文件夹中声明了一个.c类型的文件用来实现.h声明的c函数)当前这个.c文件的位置。
补一句:突然记起来 这个.so文件是怎么产生的,我们跑一遍程序,运行一下今天写的代码,.so文件就会在下列对应的位置生成出来
到这里我们就配置完所有事项了:.so文件我们去哪里找呢?如图下这个位置
可以看到我们已经成功生成so文件。调用的时候可以使用JNIUtils的实例来获取 nativie修饰的方法
更多相关文章
- Android需要大量内存时自己设置堆大小
- Android中滑屏初探 ---- scrollTo 以及 scrollBy方法使用说明
- 【干货】测试Android应用安全性
- Android(安卓)下用 Pull 解析和生成 XML
- android UI进阶之style和theme的使用
- 使用谷歌提供的支持库(Android)
- 箭头函数的基础使用
- NPM 和webpack 的基础使用
- Python list sort方法的具体使用