Android NDK开发 - Cmake环境调用.so文件

关于.so库

Android开发者使用的.so文件一般会有两种,一种是符合JNI标准的,就是方法以Java_包名_类名_方法名,Java可以调用;另一种是非JNI标准的,这种只能我们自己写JNI使用C/C++调用.so的库。

JNI标准.so库

生成libnative-lib.so文件的Java代码JNIUtils.java,包名为com.example.test

package com.example.test;

public class JNIUtils {
    /**
     * A native method that is implemented by the 'native-lib' native library,
     * which is packaged with this application.
     */
    public static native String stringFromJNI();

    // Used to load the 'native-lib' library on application startup.
    static {
        System.loadLibrary("native-lib");
    }
}

在要引用libnative-lib.so的module的/src/main/java下创建目录com.example.test,并在该目录下创建文件JNIUtils.java,这里stringFromJNI()方法会报红,但不必创建对应的native-lib.cpp。

package com.example.test;

public class JNIUtils {
    static {
        System.loadLibrary("native-lib");
    }

   //方法要对应
    public static native String stringFromJNI();
}

在/src/main下创建目录jniLibs,并将libnative-lib.so文件添加到这里,

《Android NDK开发 - Cmake环境调用.so文件》

libnative-lib.so

在Java代码中就可以直接调用方法

import static com.example.test.JNIUtils.stringFromJNI;

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        TextView textView = (TextView) findViewById(R.id.textview);
        textView.setText(stringFromJNI());
    }
}

非JNI标准.so库

参考这篇,有源码的
如果使用非JNI标准的.so库,最好要有相应的.h头文件

配置.so文件存放位置,听说放在/app/libs比在/app/src/main/jniLibs好build.gradle

  sourceSets.main {
        jniLibs.srcDirs = ['libs']
        jni.srcDirs = []
    }

《Android NDK开发 - Cmake环境调用.so文件》

.png

首先配置CMakeLists.txt文件,这里主要讲解下配置。先看下已经配置好的库文件:

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

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 )

#定位到.so文件目录
set(distribution_DIR ${CMAKE_SOURCE_DIR}/../../../../libs)

add_library( xxx-01
             SHARED
             IMPORTED )
set_target_properties( xxx-01
                       PROPERTIES IMPORTED_LOCATION
                       ../../../../libs/${ANDROID_ABI}/libxxx-01.so )

add_library( xxx-02
             SHARED
             IMPORTED )
set_target_properties( xxx-02
                       PROPERTIES IMPORTED_LOCATION
                       ../../../../libs/${ANDROID_ABI}/libxxx-02.so )

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11")

add_library( native-lib
             SHARED
             src/main/cpp/native-lib.cpp )

include_directories(libs/include)

target_link_libraries( native-lib xxx-01 xxx-02
                       ${log-lib} )

cmake_minimum_required(VERSION 3.4.1):表示cmake的最低版本是3.4.1。add_library():添加库,分为两种,一种是需要编译为库的代码,比如native-lib;一种是已经编译好的库文件,比如xxx-01,xxx-02。

这里用到的需要生成的.so文件

add_library( native-lib
             SHARED
             src/main/cpp/native-lib.cpp )

最后的参数是源码的路径,如果有更多的源码就接下去写上。

add_library( xxx-01
             SHARED
             IMPORTED )

这里xxx-01表示库的名称,SHARED表示是共享库,一般是.so文件;还有STATIC,一般是.a文件。IMPORTED表示引用的不是生成的。set_target_properties:对于已经编译好的so文件需要引入,所以需要设置。

set_target_properties( xxx-01
                       PROPERTIES IMPORTED_LOCATION
                       ../../../../libs/${ANDROID_ABI}/libxxx-01.so )

这里xxx-01是名字,然后是PROPERTIES IMPORTED_LOCATION加上库的路径。include_directories:一般外面引入的库文件需要头文件,所以可以通过这个来引入:

include_directories(libs/include)

target_link_libraries:链接,把需要的so文件链接起来,这里native-lib需要链接ffmpeg的库文件。

最后看下和java,res同级的cpp目录下有native-lib.cpp文件,系统自动生成的。首先是native-lib.cpp内容:

#include <jni.h>
#include <string>

extern "C"
jstring
Java_com_example_MainActivity_stringFromJNI(
        JNIEnv *env, jobject) {
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}

这里有一个函数Java_com_example_MainActivity_stringFromJNI,命名方式也可以知道,Java开头,com_example为包名,MainActivity是调用的java类,最后stringFromJNI是方法名。然后返回了hello from c++字符。看下java的代码:

 // Example of a call to a native method
 TextView tv = (TextView) findViewById(R.id.sample_text);
 tv.setText(avformatinfo());
/**
  * A native method that is implemented by the 'native-lib' native library,
  * which is packaged with this application.
 */
  public native String stringFromJNI();
  // Used to load the 'native-lib' library on application startup.
    static {
        loadLibrary("native-lib");
    }

那么接下去就是第三方.so库的使用了。

根据需求修改jni部分的代码,也就是native-lib.cpp的代码,在这里调用第三方.so库中的C/C++方法,完成需要实现的功能。以上就是简单的讲解调用.so库。

    原文作者:Android源码分析
    原文地址: https://juejin.im/entry/5952276c5188250d725a2b56
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞