上文我们已经介绍了如何配置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 <jni.h>
/* 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的包名了。
网友评论