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------

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容