最近几天搞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 > 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 "";
}
public static String decodeXml() {
Log.i("dddd", "decode:java2静态方法");
return "";
}
}
其次就是前面说的反射的大招 :
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陌生的时候, 每走一步你就骂,这是什么鬼啊,要当贼就不要怕挨打,呵呵哒!!