利用IDEA進行JNI開發:使用NDK生成Linux平臺下的so檔案

柴月和岐月發表於2017-09-16

 

使用NDK生成Linux平臺下的so檔案和使用MinGW生成Windows平臺下的dll檔案前半部分是一樣的,都是用javah生成標頭檔案,再根據標頭檔案編寫.c(C檔案)或者.cpp檔案(C++檔案),最後利用這個檔案生成各自的庫

先下載好自己平臺下的NDK檔案,下載地址:NDK 下載

 

流程如下:

1.編寫包含native方法的類

2.將此類使用javah生成對應的標頭檔案(推薦下里面我總結的內容:IDEA開發,Jni中javah使用方式的探索

3.利用此標頭檔案編寫.c或者.cpp檔案:這一步很簡單

這是隨便寫的一個native方法生成的.h標頭檔案

 

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class test_ndkdemo_MainActivity */

#ifndef _Included_test_ndkdemo_MainActivity
#define _Included_test_ndkdemo_MainActivity
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     test_ndkdemo_MainActivity
 * Method:    getStr
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_test_ndkdemo_MainActivity_getStr//看這裡看這裡看這裡,我寫的native在標頭檔案裡的表現形式
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

之後直接新建檔案命名為.c或者.cpp格式,然後#include"你生成的類名.h",實現你.h裡只是單單宣告的方法,比如這樣

 

 

#include"test_ndkdemo_MainActivity.h"//匯入你的標頭檔案
JNIEXPORT jstring JNICALL Java_test_ndkdemo_MainActivity_getStr//然後實現裡面的具體內容
  (JNIEnv *env, jobject obj){
    char buf[128]="test";
    return (*env)->NewStringUTF(env,buf);
  }

4.使用NDK:使用NDK你需要編寫一個Android.mk的檔案,有過Linux下使用gcc命令的看到mk應該會想到make和make file相關的內容,Android.mk的底層也是他們

 

編寫Android.mk的資料我推薦這個,Android.mk詳解

在編寫好之後我們就可以使用NDK工具了(其實是使用NDK路徑下的ndk-build.cmd檔案,有興趣的可以去找找,然後把編譯相關的檔案拷過來嘗試就在那個目錄下執行這個命令)

比如我的是

 

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := test
LOCAL_SRC_FILES := test_ndkdemo_MainActivity.c
include $(BUILD_SHARED_LIBRARY)

很簡單的- -。

 

不過請讀者老爺們注意幾點:你的.h,.c,.cpp和Android.mk得放一個資料夾下(不放也可以,你路徑在Android.mk裡多寫幾個字母也行);要是還要使用其他的庫的話記得在Android.mk新增進去

 

 

然後,我們就不跑到NDK安裝路徑下使用ndk-build.cmd命令了,我們使用前面介紹過的一鍵生成方式

 

之後隨便選你Android.mk所在目錄下隨便一個檔案執行此External Tools就行了。

 

剩餘幾點想說的

1.生成了兩個資料夾,不知道為什麼,有讀者知道的話請告知一下

。。。。。。。。。。。。。。。。。。。。。。。。。。。。

2018.1.8

後面研究SO檔案的時候,竟然偶然得知了這個答案

使用ndk生成的so檔案時會經過strip這樣一個操作,strip會將so裡動態連結庫末尾的.symtab和.strtab這兩個section去掉。

可以在\obj\local下找到未經過strip的.so檔案。

。。。。。。。。。。。。。。。。。。。。。。。。。。。。

2.Gradle在java的同級目錄中定義了一個jniLibs的變數用於存放jni的庫,記得以前的做法是把jni的庫都放在lib目錄下,然後宣告jniLibs的值

android{     
02.   sourceSets {  
03.        main {  
04.            jniLibs.srcDirs = ['libs']  
05.        }  
06.}  

現在很簡單了,新建和java同級的目錄命名為jniLibs,放入jni的庫就能在編譯時加入了

 

3.關於ndk-build.cmd:

 

相關文章