上文我們已經介紹了如何配置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文件,修改如下:
利用上篇創建的ndk -build命令工具生成庫
使用庫
- 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"
}
}*/
否則報錯:
gradle修改如下圖
- 3.然后在Activity中測試調用,在TextView上顯示我們通過C++代碼實現的方法getPackname獲取app的包名了。