1. 程式人生 > >Android JNI之靜態註冊(android studio)

Android JNI之靜態註冊(android studio)

起源

說到JNI,起初是滿臉頭痛。公司業務,呵呵,opengl,當初是java來寫的,後邊說是c++效率高,對此,我笑一笑從容。任務到手,沒辦法,就是幹。什麼某狗,什麼36啊,什麼某毒,嗖嗖嗖,嘿嘿,一個Hello JNI告訴我這個JNI還是很友好的。描述一下當時我所接受的第一個JNI程式。

一。建立JNI Floder, 將c++程式碼放入其中,然後檢視標頭檔案

這個地方要注意,是要生成JNI Floder型別的資料夾,如果隨便建立一個資料夾叫jni,那麼不好意思,我大as是不認識的。一個溫馨的提示,讓人愛得沉醉。

make.exe: *** No rule to make target .  Stop.

jni目錄程式碼展示圖
標頭檔案程式碼展示圖

二。根據c++標頭檔案編寫java端介面,並使用javah命令生成jni標頭檔案

這個呢,沒什麼好說的。java要跟c++進行交流,需要一個橋樑,橋的這頭是java,那頭是c++,中間的是jni,你不搞點事情是不行的。就這樣,普通話出現了,你懂我懂大家懂,才能展開深入交流,嘿嘿嘿。迴歸正題,看程式碼,看命令:

package net.mapout.jni;

/**
 * Created by Tower on 2017/5/25.
 * java jni 介面申明
 */
public class JNILoader {
    static {
        /**
         * JniDemo 為build的so檔名
         */
System.loadLibrary("JniDemo"); } public static native String sayHello(); }
開啟Terminal,進入/app/src/main/java目錄下
D:\Study_Code\JniDemo>   cd app/src/main/java

執行javah命令,生成標頭檔案net_mapout_jni_JNILoader.h到jni目錄下
D:\Study_Code\JniDemo\app\src\main\java>  javah -d ../jni net.mapout.jni.JNILoader

三。實現jni標頭檔案net_mapout_jni_JNILoader.h,並呼叫別人家寫的c++程式碼。

這個實現檔案可以瞎命名,但必須是.c/.c++為字尾,實現檔案嘛,嗯?嗯。

#include "net_mapout_jni_JNILoader.h"
#include "hello.h"
#include <string>

/**
 * std::string 轉  jstring
 */
jstring str2jstring(JNIEnv* env, std::string str)
{
    const char* pStr = str.c_str();
    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);
}

/**
 * 實現標頭檔案
 */
JNIEXPORT jstring JNICALL Java_net_mapout_jni_JNILoader_sayHello
  (JNIEnv *env, jclass jclass){
    return str2jstring( env, sayHello() );
}

專案檔案結構圖

四。到此,準備工作已經完成。等等,還有配置。配置嘛,一般一般。

首先,在專案的gradle.properties中配置一句:

android.useDeprecatedNdk=true

看字面意思,過時,沒錯,就是過時了,為啥還要配置呢,怪我咯。時代在進步,從當年的時代在召喚到如今的…今天天氣不錯,涼風有幸,秋月無邊,雖然我不是玉樹臨風…在打怪升級的路上,免不了有新的boss出現,cmake的火爆,這只是個意外,美麗的意外,這個暫且不提。有了首先,當然還需要然後撐腰。在當前 module 下的 build.gradle 中加入使用ndk,配置如下:

android {
    defaultConfig {
        ndk {
            moduleName "JniDemo"
            abiFilters "armeabi", "armeabi-v7a", "x86"  //輸出指定三種abi體系結構下的so庫。可有可無。
            cFlags "-std=c++11" //c++版本
            stl "gnustl_static" //支援 stl 標準庫
        }
    }
}

ndk,最後,還需要設定ndk環境。這個就是一個F4,千萬別手殘多按了一個ALT(如果一起按了,那麼恭喜你,再接再厲,下次更精彩),進入專案配置介面SDK Location->Android NDK location,設定NDK目錄即可。當然也可以通過手動在專案的 local.properties 中新增,舉慄如下:

ndk.dir=E\:\\adt-bundle-windows-x86_64-20140321\\android-ndk-r10

激動。想一下,還有什麼需要配置?搞事情。忘了就忘了吧,忘一忘,十年笑。

五。收工。

biu biu biu,build apk,見證奇蹟的時刻到了,這一刻屬於你們,也屬於我。缺陷不能不提,比如說jni標頭檔案名稱超長。當初java,c++,c三分天下,誰也不服誰。網際網路的格局,瞬息萬變。合作,隨之而來。java要跟c/c++交流,無縫對接,請了一個臭皮匠過來,趕時間。然後這位臭皮匠,囉裡囉唆、老生常談的做法。一個有效的交流,嗨,我來自xx省xx市,祖籍xx。說完這些,恭喜你,接下來,你可以聊天了。吐槽,歸吐槽。技術,總是在革新。這種方式,稱之為靜態註冊。那麼,相反呢。