Android NDK开发-简单Demo(二)

上文我们已经介绍了如何配置android studio环境来开发NDK,本篇实战开发,写一个简单的Demo。

  • MainActivity.java
public class MainActivity extends AppCompatActivity {

    // 用于在应用程序启动时加载“native-lib”库。
    static {
        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());
    }
    //使用C/C++实现
    public native String stringFromJNI();
}

使用上篇介绍的javah -jni命令工具可以生成头com_example_lynnlee_ndkdemo_MainActivity.h文件

  • com_example_lynnlee_ndkdemo_MainActivity.h
/* DO NOT EDIT THIS FILE - it is machine generated */
#include 
/* Header for class com_example_lynnlee_ndkdemo_MainActivity */

#ifndef _Included_com_example_lynnlee_ndkdemo_MainActivity
#define _Included_com_example_lynnlee_ndkdemo_MainActivity
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_example_lynnlee_ndkdemo_MainActivity
 * Method:    stringFromJNI
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_example_lynnlee_ndkdemo_MainActivity_stringFromJNI
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

函数名Java_com_example_lynnlee_ndkdemo_MainActivity_stringFromJNI组成:类名_方法名组成。参数JNIEnv *和jobject必须有,JNIEnv之jvm指针,jobject指调用该函数的java类引用。

在jni目录下新建jnitest.c文件,刚才com_example_lynnlee_ndkdemo_MainActivity.h名字太长,改为jnitest.h。

//
// Created by LynnLee on 2018/8/5.
//
#include "jnitest.h"

JNIEXPORT jstring JNICALL Java_com_example_lynnlee_ndkdemo_MainActivity_stringFromJNI(JNIEnv *env, jobject obj)
{
    return (*env)->NewStringUTF(env, "LynnLee");
}

函数实现就返回了一个"LynnLee"字符串

在jni目录下新建Android.mk文件,Android.mk文件是Android 的makefile文件

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := native-lib
LOCAL_SRC_FILES := jnitest.c
include $(BUILD_SHARED_LIBRARY)
  • LOCAL_PATH := $(call my-dir)

宏函数’my-dir’由编译系统提供,返回当前包含Android.mk文件的目录路径

  • include $(CLEAR_VARS)

CLEAR_VARS由编译系统提供,清除除LOCAL_PATH以外的其它LOCAL_XXX变量

  • LOCAL_MODULE :=native-lib

编译的目标对象,LOCAL_MODULE变量必须定义,以标识你在Android.mk文件中描述的每个模块。名称必须是唯一的,而且不包含任何空格。
注意:编译系统会自动产生合适的前缀和后缀,换句话说,一个被命名为native-lib的共享库模块,将会生成'libnative-lib.so'文件。

  • LOCAL_SRC_FILES :=hello-jni.c
    LOCAL_SRC_FILES变量必须包含将要编译打包进模块中的C/C++源代码文件。这里不需要列出头文件和包含文件,因为编译系统将会自动为你找出依赖型的文件,仅仅列出直接传递给编译器的源代码文件就好。

include $(BUILD_SHARED_LIBRARY)

指定编译出的库类型1.BUILD_SHARED_LIBRARY:动态库;2.BUILD_STATIC_LIBRARY:静态库;3.BUILD_EXECUTEABLE指:可执行文件

Application.mk

APP_ABI := all

APP_ABI有四种类型(默认armeabi),armeabi、armeabi-v7a、x86、mips,设置时以空格隔开,all表示所有。

生成库

需要修改app/CMakeLists.txt文件,修改如下:

 

CMakeLists.txt.png

利用上篇创建的ndk -build命令工具生成库

 

so库.png

使用库

  • 1.在main/libs目录下生成的so文件(名字为lib+我们指定的库名)复制到app/libs目录下,并且在gradle添加加载so库的设置,如下代码:
sourceSets {
        main {
            jniLibs.srcDirs = ['libs']
        }
    }
  • 2.删除main目录下jni、libs、obj三个文件夹。修改gradle文件,注释掉如下代码:
/*externalNativeBuild {
        cmake {
            path "CMakeLists.txt"
        }
    }*/

否则报错:

 

错误.png

gradle修改如下图

 

gradle.png

  • 3.然后在Activity中测试调用,在TextView上显示我们通过C++代码实现的方法getPackname获取app的包名了。

运行效果.png

git代码路径:https://github.com/lynnleescz/NDKdemo

你可能感兴趣的:(NDK)