Android Studio2.2.3使用C++生成so檔案
阿新 • • 發佈:2019-02-11
之前的時候寫過Android Studio2.2.3之前的so庫檔案,之前的版本的so庫檔案的編寫詳見,之前寫過的文章:
http://blog.csdn.net/wb175208/article/details/52577167
當再次使用的時候,發現很多問題,之前使用已經不能成功了。原來是Android Studio升級後能很好的相容C++,包括語法檢測、自動生成函式的標頭檔案等多種功能。自己在嘗試包括在網上查詢資料後,包使用方法寫出來,以備之後使用。
1.建立一個工程,注意一定要勾選上這個Include C++ Support
2.一路點選 【next】點選到最後的時候,採用預設就好了:
3.點選【finish】之後,會報錯:NDK not configured
4.右鍵點選工程名稱:open moudule setting
5.把我們提前下載好的NDK,配置上去就可以了,點選【OK】
6.裡面已經為我們生成了一個Demo,可以直接執行看看結果,裡面有cpp,僅供參考:
還可以找到我們生成的so檔案
7.但是呢,很多時候我們是不用demo的,我們需要自己手寫自己的.h和.cpp檔案。那我們就修改一下原來的檔案。首先修改生成的so的名稱和連結使用的名稱:把原來的native-lib改為TestCpp
8.新建一個本地類檔案TestCpp.java,並且引用我們新建的so庫,紅色報錯也不要著急
點選Ctrl+E,選擇第一個AS會自動幫我們生成實現
9.下面我們就直接測試一下看看是不是我們想要的結果。so檔案我們需要release版本的。PS:(Debug版本和release版本,做個C++的都知道。debug版本是除錯的使用的,裡面包含很多的除錯資訊,檔案體積也是比較大;release版本釋出的時候使用的,會自動的去除掉裡面的除錯資訊,檔案體積比較小)。通過Gradle projects生成release版本:
然後在這個位置就可以找到我們的release版本的so檔案
10.新建一個module來測試我們生成的so檔案,然後把我們需要的so檔案和TestCpp拷貝測試module中:
注意:TestCpp包名路徑名必須和原來的保持一致
還需要新增這部分內容:
11.檢視效果:
這樣就已經到達我們需要的效果了。
12.但是C++是需要.h檔案和.cpp檔案配合之後的,如果我要新增新的c++類怎麼辦呢?
那我們就新增一個C++類:
Test.h
//
// Created by aaa on 2017/4/12.
//
#ifndef LATINIME_TEST_H
#define LATINIME_TEST_H
#include <string>
using namespace std;
class MyTest {
public:
int testAdd(int a, int b);
std::string get_str();
};
#endif //LATINIME_TEST_H
Test.cpp
//
// Created by aaa on 2017/4/12.
//
#include "Test.h"
std::string MyTest::get_str() {
return "asdsgfdshgf";
}
int MyTest::testAdd(int a, int b) {
return a + b;
}
新增一個native-lib.h檔案
//
// Created by aaa on 2017/4/12.
//
#ifndef LATINIME_NATIVE_LIB_H
#define LATINIME_NATIVE_LIB_H
#include <jni.h>
#include <string>
#include "Test.h"
#ifdef __cplusplus
extern "C" {
#endif
extern MyTest gTest;
JNIEXPORT jstring JNICALL
Java_com_ime_aaa_testcplus_TestCpp_testGetString(JNIEnv *env, jclass type, jstring str_);
JNIEXPORT jint JNICALL
Java_com_ime_aaa_testcplus_TestCpp_testAdd(JNIEnv *env, jclass type, jint a, jint b);
#ifdef __cplusplus
}
#endif
#endif //LATINIME_NATIVE_LIB_H
native-lib.cpp
#include "native-lib.h"
//定義一個全域性變數
MyTest gTest;
/**
* C字串轉java字串
*/
jstring strToJstring(JNIEnv *env, const char *pStr) {
int strLen = strlen(pStr);
jclass jstrObj = env->FindClass("java/lang/String");
jmethodID methodId = env->GetMethodID(jstrObj, "<init>", "([BLjava/lang/String;)V");
jbyteArray byteArray = env->NewByteArray(strLen);
jstring encode = env->NewStringUTF("utf-8");
env->SetByteArrayRegion(byteArray, 0, strLen, (jbyte *) pStr);
return (jstring) env->NewObject(jstrObj, methodId, byteArray, encode);
}
/**
* jstring -> UTF-8
*/
char *jstringToUTF8(JNIEnv *env, jstring jstr) {
char *rtn = NULL;
jclass clsstring = env->FindClass("java/lang/String");
jstring strencode = env->NewStringUTF("utf-8");
jmethodID mid = env->GetMethodID(clsstring, "getBytes",
"(Ljava/lang/String;)[B");
jbyteArray barr = (jbyteArray) env->CallObjectMethod(jstr, mid, strencode);
jsize alen = env->GetArrayLength(barr);
jbyte *ba = env->GetByteArrayElements(barr, JNI_FALSE);
if (alen > 0) {
rtn = (char *) malloc(alen + 1);
memcpy(rtn, ba, alen);
rtn[alen] = 0;
}
env->ReleaseByteArrayElements(barr, ba, 0);
return rtn;
}
JNIEXPORT jstring JNICALL
Java_com_ime_aaa_testcplus_TestCpp_testGetString(JNIEnv *env, jclass type, jstring str_) {
char *ch = jstringToUTF8(env, str_);
return env->NewStringUTF(ch);
}
JNIEXPORT jint JNICALL
Java_com_ime_aaa_testcplus_TestCpp_testAdd(JNIEnv *env, jclass type, jint a, jint b) {
return gTest.testAdd(a, b);
}
並且修改CMakeLists.txt檔案,把我們需要編譯的檔案新增進去
13.重新編譯so庫檔案,拷貝到測試的module中,並且修改TestCpp.java檔案
OK!完成!