1. 程式人生 > >Android Studio2.2.3使用C++生成so檔案

Android Studio2.2.3使用C++生成so檔案

  之前的時候寫過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!完成!