Android 中 C++ 调用 Java, 以及 Java 调用 C++的开发精要

C++ 调用 Java的原理本质

通过C++中jniEnv的几个关键API实现在C++ 中调用 Java的方法:

FindClass(), NewObject(), GetStaticMethodID(), 
GetMethodID(), CallStaticObjectMethod(), CallVoidMethod()

参考这篇文章写的很清晰:
http://www.cnblogs.com/luxiaofeng54/archive/2011/08/17/2142000.html

在C++中映射Java中的类、和方法, 以及创建对象

在Java中:

package com.duicky;
public class TestProvider {
 
public static String getTime() {
        LogUtils.printWithSystemOut( "Call From C Java Static Method"   );
        LogUtils.toastMessage(MainActivity.mContext, "Call From C Java Static Method"   );
        return String.valueOf(System.currentTimeMillis());
}
 
public void sayHello(String msg) {
        LogUtils.printWithSystemOut("Call From C Java Not Static Method :" + msg);
        LogUtils.toastMessage(MainActivity.mContext, "Call From C Java Not Static Method :" + msg);
}
 
}

对于这样一个Java层的类, 在C++中实现调用它的静态方法和普通方法需要定义其映射的类、对象, 和方法.

jclass TestProvider;
jobject mTestProvider;
jmethodID getTime;
jmethodID sayHello;

对这几个对象的赋值:

jclass TestProvider = (*jniEnv)->FindClass(jniEnv,"com/duicky/TestProvider");
TestProvider mTestProvider = (*jniEnv)->NewObject(jniEnv, TestProvider,construction_id);
jmethodID getTime = (*jniEnv)->GetStaticMethodID(jniEnv, TestProvider, "getTime","()Ljava/lang/String;"); //都是通过类找到方法
jmethodID sayHello = (*jniEnv)->GetMethodID(jniEnv, TestProvider, "sayHello","(Ljava/lang/String;)V"); //都是通过类找到方法
在C++中调用 Java中的 方法

静态:

//通过jclass类调用静态方法
(*jniEnv)->CallStaticObjectMethod(jniEnv, TestProvider, getTime);
非静态:
//通过jobject对象调用普通方法
(*jniEnv)->CallVoidMethod(jniEnv, mTestProvider, sayHello,jstrMSG);


Java 调用 C++ 的原理本质

Java类中写一个native关键字修饰的方法, 通过javah生成一个函数名,
命名规范是: 包名类名方法名. 在C++中对这个函数进行实现.
这样Java层调用这个native方法就进入到了C++中的实现中去了.
例如:

private native void nativeSaveWebArchieve(long nativeTabAndroid, String filename, ValueCallback<String> callback);
chromium 中是如何使用C++和Java之间的相互调用的

chromium为方便JNI的开发, 写了一个关键脚本: jni_generator.py,
在编译前扫描所有的java文件, 对java文件中有@CalledByNative注解的方法和native关键字修饰的方法,
在out/release/gen/目录下生成和java文件对应的.h文件,
命名规则是: 类名_jni.h, 例如: Tab.java对应Tab_jni.h, TraceEvent.java对应TraceEvent_jni.h

以Tab.java为例:

public class Tab {
    //内核获得用户输入的url
    @CalledByNative
    public String getUrl() {
        String url = getWebContents() != null && !getWebContents().isDestroyed() ? getWebContents().getUrl() : "";
        if (getContentViewCore() != null || getNativePage() != null || !TextUtils.isEmpty(url)) {
            mUrl = url;
        }

        return mUrl != null ? mUrl : "";
    }

    //保存网页的API
    private native void nativeSaveWebArchieve(long nativeTabAndroid, String filename, ValueCallback<String> callback);
}

对应着Tab_jni.h中的内容:

//生成一个方法对调用Java中的方法进行封装
//本质还是: 通过JNIEnv找到method id, 然后通过CallObjectMethod() 进行调用.
static base::android::ScopedJavaLocalRef<jstring> Java_Tab_getUrl(JNIEnv* env,
    jobject obj) {
  /* Must call RegisterNativesImpl()  */
  CHECK_CLAZZ(env, obj,
      Tab_clazz(env), NULL);
  jmethodID method_id =
      base::android::MethodID::LazyGet<
      base::android::MethodID::TYPE_INSTANCE>(
      env, Tab_clazz(env),
      "getUrl",

"("
")"
"Ljava/lang/String;",
      &g_Tab_getUrl);

  jstring ret =
      static_cast<jstring>(env->CallObjectMethod(obj, //***这里实现的真正调用java中的方法***
          method_id));
  jni_generator::CheckException(env);
  return base::android::ScopedJavaLocalRef<jstring>(env, ret);
}

对java中的native方法进行实现,
方法名必须按照: 包名类名方法名, 符合签名规范.

void Java_org_chromium_chrome_browser_Tab_nativeSaveWebArchieve(JNIEnv* env,
    jobject jcaller,
    jlong nativeTabAndroid,
    jstring filename,
    jobject callback) {
  TabAndroid* native = reinterpret_cast<TabAndroid*>(nativeTabAndroid);
  CHECK_NATIVE_PTR(env, jcaller, native, "SaveWebArchieve");
  return native->SaveWebArchieve(env, jcaller, filename, callback);
}

在tab_android.cc中 #include "jni/Tab_jni.h"

#include "jni/Tab_jni.h"
GURL TabAndroid::GetURL() const {
  JNIEnv* env = base::android::AttachCurrentThread();
  return GURL(base::android::ConvertJavaStringToUTF8(
      Java_Tab_getUrl(env, weak_java_tab_.get(env).obj())));
}


void TabAndroid::SaveWebArchieve(JNIEnv *env, jobject obj, jstring path, jobject callback) {
    ScopedJavaGlobalRef<jobject>* j_callback = new ScopedJavaGlobalRef<jobject>();
    j_callback->Reset(env, callback);
    base::FilePath target_path(ConvertJavaStringToUTF8(env, path));
    web_contents()->GenerateMHTML(
      target_path,
      base::Bind(&GenerateMHTMLCallback, base::Owned(j_callback), target_path));
}

----DONE------

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容