安卓开发学习之初识ndk开发

背景

今天没事干,就开始学习ndk开发,实现了一下Android和C的函数方法互调,记录一下步骤


步骤

1、通过Android Studio的SDK Manager安装CMake、LLDB和NDK


2、新建工程,记得要勾选inclue C++ support,而后一路next,直到完成



3、而后,在工程目录下,随便哪个子目录里,右击新建一个C源文件,同时可以勾选生成同名的头文件



4、ok后,会在指定目录下生成my_ndk_util.c/.h文件,内容如下

头文件

#ifndef MYNDKDEMO_MY_NDK_UTIL_H
#define MYNDKDEMO_MY_NDK_UTIL_H

#endif //MYNDKDEMO_MY_NDK_UTIL_H

源文件

#include "my_ndk_util.h"


5、而后,在CMakeLists.txt文本文件里,在add_library()中添加我们的源文件的相对路径,如下

add_library( # Sets the name of the library.
             native-lib

             # Sets the library as a shared library.
             SHARED

             # Provides a relative path to your source file(s).
             src/main/jni/my_ndk_util.c) # 工程目录下的相对路径

其他的都不用改


6、同步之后,在源文件里添加一个函数,完整代码如下

#include "my_ndk_util.h"
#include "jni.h"
#include "string.h"
#include "android/log.h" // 调用Android打日志方法而用

const char* tag = "my_ndk_util";

JNIEXPORT jstring JNICALL Java_com_example_songzeceng_myndkdemo_MyNdkUtil_getAppKey(JNIEnv* env, jclass type, jstring str){
    char* content = "浔阳江头夜送客,枫叶荻花秋瑟瑟";
    char* string = (*env)->GetStringUTFChars(env, str, JNI_FALSE); // 根据jstring获取字符串
    string = strcat(string, content);

    __android_log_print(ANDROID_LOG_INFO, tag, string); // 打印日志,相当于Log.i(tag, string);


    return (*env)->NewStringUTF(env, content); // 根据content创建jstring
}

源文件里,头文件包含我就不说了,尤其要注意参数列表里前两个参数的位置是固定的,不能打乱,它们之后的参数都要显示写在对应的native函数的参数列表里,也是一一对应的

那么这个c函数对应的native函数在哪儿呢?看看函数名,函数名格式是Java_native函数所在类的包名_native函数所在类名_jni函数名,如包名有.分割,以_代之,所以我这个函数名就对应着com.example.songzeceng.myndkdemo包下的MyNdkUtil.java文件里的getAppKey()方法


7、在C函数对应的包名下创建MyNdkUtils类,先加载库,再定义native方法,代码如下

public class MyNdkUtil {
    private static final String LIB = "native-lib";
    static {
        System.loadLibrary(LIB);
    }

    public static native String getAppKey(String s); // 这个参数s,就是C函数里的jstring参数
}

这个lib名字,是在CMakeLists.txt文件的add_library里指定的,详情请翻阅上文第5步


8、在MainActivity里,调用方法,进行验证

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        String s = MyNdkUtil.getAppKey("白居易--");
        Log.i(TAG, s);
    }
}

由于在MyNdkUtil类加载的时候就加载了native库,所以不妨碍native函数的调用

效果如下:



踩的坑

1、报错cmake error: format string is not a string literal (potentially insecure) [-Werror,-Wformat-security]

这个由于我们是用CMake开发,不存在mk文件,所以只需要在CMakeLists.txt里加上这样一句话就可以

set(CMAKE_C_FLAGS "-Wno-error=format-security")


2、找不到asm/types.h文件,同样,在CMakeLists.txt文件里加上一句话

set(CMAKE_C_FLAGS "-isystem /Users/songzeceng/Library/Android/sdk/ndk-bundle/sysroot/usr/include/arm-linux-androideabi")

路径是自己ndk目录下的sysroot/usr/include/arm-linux-androideabi


另外,我这个是用的C文件,所以是CMAKE_C_FLAGS,如果用的是cpp文件,旧得是CMAKE_CXX_FLAGS


猜你喜欢

转载自blog.csdn.net/qq_37475168/article/details/80369527