Android-NDK學(xué)習(xí)(2)

寫在前面

本文需要一些CMakeJNI的基礎(chǔ)知識叼丑,對于CMake的使用推薦Android官網(wǎng)的NDK入門。CMake是Android Studio 2.2以上新增的支持原生編程的工具负拟,CMake是一個跨平臺的編譯工具,可以用簡單的語句描述所有平臺的編譯過程歹河。恩掩浙,暫時先記一下吧花吟,本文現(xiàn)處于自嗨狀態(tài),不適合作為各位將之作為NDK的學(xué)習(xí)資料厨姚。

環(huán)境配置

在創(chuàng)建項目時勾選include c++衅澈,在項目創(chuàng)建完畢,文件目錄如下:

目錄結(jié)構(gòu)

可以看到谬墙,可以看到app目錄下有一個CMakeLists.txt今布,我在這個txt里加了一些注釋

# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html

# Sets the minimum version of CMake required to build the native library.

cmake_minimum_required(VERSION 3.4.1)

# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.
# 增加cpp動態(tài)共享庫
add_library( # Sets the name of the library.
             hello

             # Sets the library as a shared library.
             SHARED

             # Provides a relative path to your source file(s).
             src/main/cpp/hello.cpp )

# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.

find_library( # Sets the name of the path variable.
              log-lib

              # Specifies the name of the NDK library that
              # you want CMake to locate.
              log )

# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.

# 生成鏈接動態(tài)庫
target_link_libraries( # Specifies the target library.
                       hello

                       # Links the target library to the log library
                       # included in the NDK.
                       ${log-lib} )

如果你有多個cpp動態(tài)共享庫,可以再添加一個add_library拭抬。在app的build.gradle中也有相關(guān)的配置:

    externalNativeBuild {
        cmake {
            path "CMakeLists.txt"
        }
    }

關(guān)于CMake更詳細(xì)的配置參見:https://developer.android.com/ndk/guides/cmake.html?hl=zh-cn

可以看到我的CMake文件中添加的動態(tài)庫為hello部默,這里在Java文件中創(chuàng)建一個JNI入口類,叫做JNIEntry:

package com.xiasuhuei321.forjni.entry;

import android.util.Log;

/**
 * Created by xiasuhuei321 on 2017/8/26.
 * author:luo
 * e-mail:xiasuhuei321@163.com
 */

public class JNIEntry {
    static {
        System.loadLibrary("hello");
    }

    // 實例域
    public String TAG1 = "JNIEntry_INSTANCE";
    // 靜態(tài)域
    public static final String TAG2 = "JNIEntry_STATIC";
    public static final String TAG = "JNIEntry";

    public static void testStaticMethod(){
        Log.e(TAG,"靜態(tài)測試方法被調(diào)用了");
    }

    private void testInstanceMethod(){
        Log.e(TAG,"實例測試方法被調(diào)用了");
    }

    /**
     * 從C++獲取字符串
     *
     * @return 字符串
     */
    public static native String stringFromJNI();

    /**
     * 將大寫字符串轉(zhuǎn)成小寫
     *
     * @return 小寫字符串
     */
    public static native String toLowCase(String str);

    public static native void changeArray(int[] array);

    public static native void accessField(Object obj);

    public static native void accessMethod(Object obj);
}

hello.cpp完整代碼

這里再記一下c++源碼造虎,方便以后自己查閱
cpp源碼:hello.cpp

//
// Created by xiasuhuei321 on 2017/8/25.
//

#include <jni.h>
#include <android/log.h>
#include <string>


extern "C"
{
JNIEXPORT jstring JNICALL
Java_com_xiasuhuei321_forjni_entry_JNIEntry_stringFromJNI(JNIEnv *env, jobject instance) {
    // 用c字符串創(chuàng)建Java字符串
    __android_log_print(ANDROID_LOG_DEBUG, "jni", "Hello World");
    // 在內(nèi)存溢出的情況下傅蹂,返回NULL
    return env->NewStringUTF("Hello World");
}

JNIEXPORT jstring JNICALL
Java_com_xiasuhuei321_forjni_entry_JNIEntry_toLowCase(JNIEnv *env, jclass type, jstring str_) {
    // 為了在原生代碼中使用Java字符串,需要先將Java字符串轉(zhuǎn)換成C字符串
    // 這個函數(shù)可以將Unicode格式的Java字符串轉(zhuǎn)換成C字符串
    // 第二個參數(shù)指定了是指向堆內(nèi)原有對象還是拷貝一份新的對象
    // 這種獲取的字符串只讀
    const char *str = env->GetStringUTFChars(str_, JNI_FALSE);
    // 獲取字符串長度
    jint length = env->GetStringLength(str_);
    char strs[length];

    // 這里必須要這么復(fù)制算凿,自己手動改會有一個特殊字符(猜測是結(jié)尾的符號)份蝴,
    // 在生成UTF字符串的時候會報錯
    strcpy(strs, str);
    for (int i = 0; i < length; i++) {
        char c = str[i];
        if (c >= 'A' && c <= 'Z') {
            strs[i] = (char) (c + 32);
        } else {
            strs[i] = c;
        }
    }

    __android_log_print(ANDROID_LOG_DEBUG, "jni", "%s", strs);
    // 釋放JNI函數(shù)返回的C字符串
    env->ReleaseStringUTFChars(str_, str);

    return env->NewStringUTF(strs);
}

JNIEXPORT void JNICALL
Java_com_xiasuhuei321_forjni_entry_JNIEntry_changeArray(JNIEnv *env, jclass type,
                                                        jintArray array_) {
    // 將Java數(shù)組復(fù)制到C數(shù)組中
//    env->GetIntArrayRegion()
    // 從C數(shù)組向Java數(shù)組提交所做的修改
//    env->SetIntArrayRegion()
    // 獲取指向數(shù)組元素的直接指針
    jint *value = env->GetIntArrayElements(array_, NULL);
    jint length = env->GetArrayLength(array_);
    // 這里對每個元素做+1操作
    for (int i = 0; i < length; i++) {
        value[i] += 1;
    }
    env->ReleaseIntArrayElements(array_, value, 0);
}

JNIEXPORT void JNICALL
Java_com_xiasuhuei321_forjni_entry_JNIEntry_accessField(JNIEnv *env, jclass type,
                                                        jobject instance) {
    jclass clazz = env->GetObjectClass(instance);
    // JNI提供了用域ID訪問兩類域的方法,可以通過給定實例的class對象獲取域ID
    // 用GetObjectClass函數(shù)可以獲得class對象
    // 獲取id
    jfieldID instanceFieldId = env->GetFieldID(clazz, "TAG1", "Ljava/lang/String;");
    // 獲取屬性值
    jstring jstr_value = (jstring) env->GetObjectField(instance, instanceFieldId);
    const char *ch_value = env->GetStringUTFChars(jstr_value, NULL);

    __android_log_print(ANDROID_LOG_DEBUG, "jni", "%s", ch_value);

    // 獲取id
    jfieldID staticFieldId = env->GetStaticFieldID(clazz, "TAG2", "Ljava/lang/String;");
    // 獲取屬性值
    jstring static_value = (jstring) env->GetStaticObjectField(clazz, staticFieldId);
    const char *st_value = env->GetStringUTFChars(static_value, NULL);
    __android_log_print(ANDROID_LOG_DEBUG, "jni", "%s", st_value);

}

JNIEXPORT void JNICALL
Java_com_xiasuhuei321_forjni_entry_JNIEntry_accessMethod(JNIEnv *env, jclass type,
                                                         jobject obj) {
    // 獲取class對象
    jclass clazz = env->GetObjectClass(obj);
    // 獲取方法id
    jmethodID i_id = env->GetMethodID(clazz, "testInstanceMethod", "()V");
    jmethodID s_id = env->GetStaticMethodID(clazz, "testStaticMethod", "()V");

    // 調(diào)用實例方法
    env->CallVoidMethod(obj, i_id);
    // 調(diào)用靜態(tài)方法
    env->CallStaticVoidMethod(clazz,s_id);
}
}

湊個字?jǐn)?shù)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末氓轰,一起剝皮案震驚了整個濱河市婚夫,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌戒努,老刑警劉巖请敦,帶你破解...
    沈念sama閱讀 217,542評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件镐躲,死亡現(xiàn)場離奇詭異储玫,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)萤皂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評論 3 394
  • 文/潘曉璐 我一進(jìn)店門撒穷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人裆熙,你說我怎么就攤上這事端礼。” “怎么了入录?”我有些...
    開封第一講書人閱讀 163,912評論 0 354
  • 文/不壞的土叔 我叫張陵蛤奥,是天一觀的道長。 經(jīng)常有香客問我僚稿,道長凡桥,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,449評論 1 293
  • 正文 為了忘掉前任蚀同,我火速辦了婚禮缅刽,結(jié)果婚禮上啊掏,老公的妹妹穿的比我還像新娘。我一直安慰自己衰猛,他們只是感情好迟蜜,可當(dāng)我...
    茶點故事閱讀 67,500評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著啡省,像睡著了一般娜睛。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上卦睹,一...
    開封第一講書人閱讀 51,370評論 1 302
  • 那天微姊,我揣著相機(jī)與錄音,去河邊找鬼分预。 笑死兢交,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的笼痹。 我是一名探鬼主播配喳,決...
    沈念sama閱讀 40,193評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼凳干!你這毒婦竟也來了晴裹?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,074評論 0 276
  • 序言:老撾萬榮一對情侶失蹤救赐,失蹤者是張志新(化名)和其女友劉穎涧团,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體经磅,經(jīng)...
    沈念sama閱讀 45,505評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡泌绣,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,722評論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了预厌。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片阿迈。...
    茶點故事閱讀 39,841評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖轧叽,靈堂內(nèi)的尸體忽然破棺而出苗沧,到底是詐尸還是另有隱情,我是刑警寧澤炭晒,帶...
    沈念sama閱讀 35,569評論 5 345
  • 正文 年R本政府宣布待逞,位于F島的核電站,受9級特大地震影響网严,放射性物質(zhì)發(fā)生泄漏识樱。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,168評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望牺荠。 院中可真熱鬧翁巍,春花似錦、人聲如沸休雌。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽杈曲。三九已至驰凛,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間担扑,已是汗流浹背恰响。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留涌献,地道東北人胚宦。 一個月前我還...
    沈念sama閱讀 47,962評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像燕垃,于是被迫代替她去往敵國和親枢劝。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,781評論 2 354

推薦閱讀更多精彩內(nèi)容