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

2019-04-29  本文已影响0人  21世纪不靠谱艺术表演家

去年同事给了个图像解码的.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文件,随便放哪,我这里放到了工程根目录下。



然后加入以下内容。

# 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} )
 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+"");

    }
}

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


上一篇下一篇

猜你喜欢

热点阅读