1. 程式人生 > >android jni開發中c++ 呼叫java 方法

android jni開發中c++ 呼叫java 方法

    最近幾天搞fbreader 電子書的二次開發,其中需要 c++ 呼叫 java方法解密電子書,所以l老虎吃天,硬著頭皮看c++程式碼。

 具體的思路如下,其實也就這幾步:

     1. jni 中用到 java反射的方法 找到java類,  找類的物件  ,找到方法。,

     2. 如果 是靜態的方法都不用找物件, 直接找到類, 找靜態方法。

     是你一定感覺很簡單,我也這麼覺的,可是具體做的時候就會遇到些不可描述的弱智問題,呵呵!!

直接上程式碼:

1.1


     if (stream.isNull() || !stream->open()) {
         return false;
     }

     std::size_t length;
     int allLength = 0;
     do {
         length = stream->read(myParserBuffer, BUFFER_SIZE);
         allLength += length;
     } while ((length == BUFFER_SIZE) && !myInterrupted);//每次讀取一個xhtml

     char *all = (char *) malloc(allLength);
     stream->seek(0, true);
     stream->read(all, allLength);

     std::string result = decode(all, allLength);

   c++ 的語法,不懂的還得熟悉 一下, stream->read()   代表指標 呼叫read方法 (*stream).read(),malloc 代表分配記憶體地址,std:: string  就是固定的名稱空間的一些寫法,基本語言都相似,知識細節不同,我是目標導向, 看懂基本的意思就行啦,其它的以後有機會再看。

問題就在這:std::string result = decode(all, allLength); 自己定義一個呼叫java解密的方法decode , 可是怎麼也不知怎麼配置.h 檔案和 方法實現,後來網上偶然看到 使用 alt+enter 鍵,自動在.h 生成定義的標頭檔案 ,在.cpp 生成方法的實現,IDE還真是先進啊,如下所示:.h 檔案中
private:
	bool myInterrupted;
	ZLXMLReaderInternal *myInternalReader;
	char *myParserBuffer;
	std::vector<shared_ptr<nsMap> > myNamespaces;
	std::string myErrorMessage;

friend class ZLXMLReaderInternal;
friend class ZLXMLReaderHandler;
	
std::string  decode(const char *all, int length); .h 中就是這句

  .cpp 中是這樣子的: 方法的的實現 ,具體呼叫java方法的過程就得您老自己寫。

std::string ZLXMLReader::decode(const char *all, int length) {
   
    return string();
}

1.2  開始呼叫java方法了 ,進入高潮了。

    首先定義一個java方法,要不調個毛啊: 

package org.geometerplus.zlibrary.core.xml;

public class DecodeXml {

    public String decode(String html) {
        Log.i("dddd", "decode:java1方法 ");
        return  "<defghijk>";
    }

    public static String decodeXml() {
        Log.i("dddd", "decode:java2靜態方法");
        return  "<defghijk>";
    }
}

其次就是前面說的反射的大招 :

std::string ZLXMLReader::decode(const char *all, int length) {
    //1.呼叫java方法;獲得env指標,類似與java中上下文
    JNIEnv *env = AndroidUtil::getEnv();
    if (env == NULL) {
        return 0;
    }
     // 2. 找到類 ,後面是包名
    jclass cls = env->FindClass("org/geometerplus/zlibrary/core/xml/DecodeXml");
    if (cls == 0) {
        return 0;
    }
    // 3.找到方法id, 括號裡面官名叫方法簽名,其實就是傳參型別和 返回型別,我這個是字串
    jmethodID mid;
    mid = env->GetMethodID(cls, "decode", "(Ljava/lang/String;)Ljava/lang/String;");
    // 4.到方法肯定要物件調, 下面就是預設構造方法的物件,也可以自己過載構造方法; 靜態方法當然不要物件
    jobject j_object = env->AllocObject(cls);
    const char *str = "fkdfdk";
    if (mid == 0) {
        return 0;
    }
    const char *name = "World";
    jstring arg = env->NewStringUTF(name);
    // 5. 這句就是直搗黃龍的黃龍,調一般方法
    jstring result = (jstring) env->CallObjectMethod(j_object, mid, arg);
//    __android_log_print(ANDROID_LOG_INFO, "dddd", "2GetTime Begin", result);
    str = env->GetStringUTFChars(result, 0);
//    env->ReleaseStringUTFChars(result, 0);
    return str;
}

   經過以上這幾步,既可以在java 中看到列印的日誌了。看起來簡單啊,但是當你對c陌生的時候, 每走一步你就罵,這是什麼鬼啊,要當賊就不要怕捱打,呵呵噠!!