android jni開發中c++ 呼叫java 方法
阿新 • • 發佈:2018-11-12
最近幾天搞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陌生的時候, 每走一步你就罵,這是什麼鬼啊,要當賊就不要怕捱打,呵呵噠!!