美文网首页
外行搞应用-Android Studio 调用C程序

外行搞应用-Android Studio 调用C程序

作者: 21世纪不靠谱艺术表演家 | 来源:发表于2019-04-29 22:38 被阅读0次

    去年同事给了个图像解码的.so库,让搞进app里,研究了一下搞定了。没有及时总结。最近又给了个sm2验签的源码搞到app里,发现之前学会的东西已经完全忘了,所以这次赶紧记下来。


    环境

    用Android Studio开发的话需要先装LLDB,CMake,NDK这三个SDK Tools。


    新建Java类

    新建一个Java类,写下面的代码。这里是引入lib_sum这个库,声明了一个本地方法sum。

    package com.example.ndkdemo;
    
    public class JniSum {
        static {
            System.loadLibrary("lib_sum");
        }
        public static native int sum(int a,int b);
    }
    

    C代码

    新建C代码目录,我建到了app/src/main/jni/里。在目录先新建一个空的sum.c文件。


    在Terminal中先cd到JniSum 类的目录里,然后用javah -jni com.example.ndkdemo.JniSum生成一个头文件,并把头文件剪切到C代码目录里。这相当于自动生成了本地方法sum对应的jni接口的C原型。如果不使用javah,直接自己写也是可以的。

    /* DO NOT EDIT THIS FILE - it is machine generated */
    #include <jni.h>
    /* Header for class com_example_ndkdemo_JniSum */
    
    #ifndef _Included_com_example_ndkdemo_JniSum
    #define _Included_com_example_ndkdemo_JniSum
    #ifdef __cplusplus
    extern "C" {
    #endif
    /*
     * Class:     com_example_ndkdemo_JniSum
     * Method:    sum
     * Signature: (II)I
     */
    JNIEXPORT jint JNICALL Java_com_example_ndkdemo_JniSum_sum
      (JNIEnv *, jclass, jint, jint);
    
    #ifdef __cplusplus
    }
    #endif
    #endif
    
    

    接下来根据这个原型来写C函数,这里测试代码很简单,直接输出两个输入之和。要搞数组之类比较复杂的操作时需要研究一下jni接口的使用方法。

    #include "com_example_ndkdemo_JniSum.h"
    JNIEXPORT jint JNICALL Java_com_example_ndkdemo_JniSum_sum (JNIEnv * env, jclass obj, jint a, jint b){
        return a+b;
      }
    

    CMakeLists

    CMakeLists的功能相当于Makefile。
    新建CMakeLists.txt文件,随便放哪,我这里放到了工程根目录下。



    然后加入以下内容。

    • .so库名,最终编译产生的.so库就是这个名字
    • 源文件目录,这个目录是源文件和CMakeLists的相对路径,多文件的话就都写进来
    • 别忘了修改target_link_libraries中的.so库名
    # 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)
    
    # 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.
                 lib_sum #.so库名 可自定义
    
                 # Sets the library as a shared library.
                 SHARED
    
                 # Provides a relative path to your source file(s).
                 app/src/main/jni/sum.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.
                           lib_sum #.so库名 可自定义
                           # Links the target library to the log library
                           # included in the NDK.
                           ${log-lib} )
    
    • c程序需要调用.so的话就再写一个add_library():
     add_library(mysum SHARED IMPORTED)
      set_target_properties(mysum PROPERTIES IMPORTED_LOCATION
                          ${CMAKE_SOURCE_DIR}/app/src/main/jniLibs/${ANDROID_ABI}/libmysum.so)
    

    这个mysum是我之前编译好的一个不带jni接口的.so库,add_library中说明要导入这个库, set_target_properties中有这个库的路径。别忘了最后target_link_libraries中把这个库link上。这样就可以直接在c文件中调用了。
    建议所有的.so库都放到app/src/main/jniLibs/中,这个是默认路径,用起来比较方便。

    编译

    编译时先右键app,点击Link C++ Project with Gradle,然后选择CMakelists的路径。这样就根据CMakeLists的内容自动在gradle中添加了配置。
    build.gradle中自动加入以下内容:

        buildTypes {
            release {
                minifyEnabled false
                proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
            }
        }
        externalNativeBuild {
            cmake {
                path file('../CMakeLists.txt')
            }
        }
    

    最后在MainActivity随便写个代码测试一下:

    public class MainActivity extends AppCompatActivity {
        private TextView txv;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            txv = findViewById(R.id.txv);
            int a = JniSum.sum(1,2);
            txv.setText(a+"");
    
        }
    }
    

    在虚拟机上试一下,工作正常。


    相关文章

      网友评论

          本文标题:外行搞应用-Android Studio 调用C程序

          本文链接:https://www.haomeiwen.com/subject/fecpnqtx.html