blob: f93dbfd90b59d0abdf237122b317ecaf1cff2c51 [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include "android/wrap/wml_bridge.h"
#include "android/base/string/string_utils.h"
#include "android/utils/params_utils.h"
#include "base/android/jni/android_jni.h"
#include "base/android/jni_type.h"
#include "base/android/log_utils.h"
#include "core/manager/weex_core_manager.h"
static intptr_t jDoubleValueMethodId = 0;
static jint InitAppFramework(JNIEnv* env, jobject jcaller, jstring jinstanceid,
jstring jframwork, jobjectArray jargs) {
WeexCore::WMLBridge::Instance()->Reset(env, jcaller);
ScopedJStringUTF8 id(env, jinstanceid);
ScopedJStringUTF8 framework(env, jframwork);
int length = jargs == NULL ? 0 : env->GetArrayLength(jargs);
std::vector<INIT_FRAMEWORK_PARAMS*> params;
for (int i = 0; i < length; i++) {
auto jArg = std::unique_ptr<WXJSObject>(
new WXJSObject(env, env->GetObjectArrayElement(jargs, i)));
jint jTypeInt = jArg->GetType(env);
auto jDataObj = jArg->GetData(env);
auto jKeyStr = jArg->GetKey(env);
if (jTypeInt == 1) {
jclass jDoubleClazz = env->FindClass("java/lang/Double");
jmethodID method_id = nullptr;
if (jDoubleValueMethodId != 0) {
method_id = reinterpret_cast<jmethodID>(jDoubleValueMethodId);
} else {
method_id = base::android::GetMethod(
env, jDoubleClazz,
base::android::INSTANCE_METHOD,
"doubleValue",
"()D",
&jDoubleValueMethodId);
}
jdouble jDoubleObj = env->CallDoubleMethod(jDataObj.Get(), method_id);
const auto size = sizeof(jDoubleObj) + 1;
char * charData = (char *) malloc(size);
if(charData == nullptr){
continue;
}
memset(charData, 0, size);
snprintf(charData, size, "%f", jDoubleObj);
ScopedJStringUTF8 jni_key(env, jKeyStr.Get());
params.push_back(genInitFrameworkParams(jni_key.getChars(), charData));
free(charData);
} else if (jTypeInt == 2) {
jstring jDataStr = (jstring)jDataObj.Get();
ScopedJStringUTF8 jni_key(env, jKeyStr.Get());
ScopedJStringUTF8 jni_data(env, jDataStr);
params.push_back(
genInitFrameworkParams(jni_key.getChars(), jni_data.getChars()));
} else if (jTypeInt == 3) {
jstring jDataStr = (jstring)jDataObj.Get();
ScopedJStringUTF8 jni_key(env, jKeyStr.Get());
ScopedJStringUTF8 jni_data(env, jDataStr);
params.push_back(
genInitFrameworkParams(jni_key.getChars(), jni_data.getChars()));
}
}
auto result =
WeexCoreManager::Instance()
->getPlatformBridge()
->core_side()
->InitAppFramework(id.getChars(), framework.getChars(), params);
freeParams(params);
return result;
}
static jint DestoryAppContext(JNIEnv* env, jobject jcaller,
jstring jinstanceid) {
ScopedJStringUTF8 id(env, jinstanceid);
return WeexCoreManager::Instance()
->getPlatformBridge()
->core_side()
->DestroyAppContext(id.getChars());
}
static jint CreateAppContext(JNIEnv* env, jobject jcaller, jstring jinstanceid,
jstring jbundle, jobject jargs) {
ScopedJStringUTF8 id(env, jinstanceid);
ScopedJStringUTF8 bundle(env, jbundle);
return WeexCoreManager::Instance()
->getPlatformBridge()
->core_side()
->CreateAppContext(id.getChars(), bundle.getChars());
}
static jbyteArray ExecJsOnAppWithResult(JNIEnv* env, jobject jcaller,
jstring jinstanceid, jstring jbundle,
jobject jargs) {
ScopedJStringUTF8 id(env, jinstanceid);
ScopedJStringUTF8 bundle(env, jbundle);
auto ret = WeexCoreManager::Instance()
->getPlatformBridge()
->core_side()
->ExecJSOnAppWithResult(id.getChars(), bundle.getChars());
if (ret.get() != nullptr && ret->data.get() != nullptr) {
jbyteArray array = env->NewByteArray(ret->length);
env->SetByteArrayRegion(array, 0, ret->length,
reinterpret_cast<const jbyte*>(ret->data.get()));
return array;
}
return nullptr;
}
static jint ExecJsOnApp(JNIEnv* env, jobject jcaller, jstring jinstanceid,
jstring jfunction, jobjectArray jargs) {
// return WeexProxy::execJsOnApp(env, jcaller, jinstanceid, jfunction,
// jargs);
ScopedJStringUTF8 id(env, jinstanceid);
ScopedJStringUTF8 function(env, jfunction);
int length = 0;
if (jargs != NULL) {
length = env->GetArrayLength(jargs);
}
std::vector<VALUE_WITH_TYPE*> params;
for (int i = 0; i < length; i++) {
auto jArg = std::unique_ptr<WXJSObject>(
new WXJSObject(env, env->GetObjectArrayElement(jargs, i)));
jint jTypeInt = jArg->GetType(env);
auto jDataObj = jArg->GetData(env);
VALUE_WITH_TYPE* param = nullptr;
param = getValueWithTypePtr();
if (jTypeInt == 1) {
jdouble jDoubleObj =
base::android::JNIType::DoubleValue(env, jDataObj.Get());
param->type = ParamsType::DOUBLE;
param->value.doubleValue = jDoubleObj;
} else if (jTypeInt == 2) {
jstring jDataStr = (jstring)jDataObj.Get();
param->type = ParamsType::STRING;
param->value.string = jstring2WeexString(env, jDataStr);
} else if (jTypeInt == 3) {
jstring jDataStr = (jstring)jDataObj.Get();
param->type = ParamsType::JSONSTRING;
param->value.string = jstring2WeexString(env, jDataStr);
} else {
param->type = ParamsType::JSUNDEFINED;
}
params.push_back(param);
}
return WeexCoreManager::Instance()
->getPlatformBridge()
->core_side()
->CallJSOnAppContext(id.getChars(), function.getChars(), params);
}
namespace WeexCore {
WMLBridge* WMLBridge::g_instance = nullptr;
const char kWMLBridgeClassPath[] = "com/taobao/windmill/bundle/bridge/WeexBridge";
jclass g_WMLBridge_clazz = nullptr;
static JNINativeMethod gWMMethods[] = {
{"nativeInitAppFramework",
"(Ljava/lang/String;Ljava/lang/String;[Lcom/taobao/weex/bridge/"
"WXJSObject;)I",
(void*)InitAppFramework},
{"nativeCreateAppContext",
"(Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;)I",
(void*)CreateAppContext},
{"nativeExecJsOnApp",
"(Ljava/lang/String;Ljava/lang/String;"
"[Lcom/taobao/weex/bridge/WXJSObject;)I",
(void*)ExecJsOnApp},
{"nativeExecJsOnAppWithResult",
"(Ljava/lang/String;Ljava/lang/String;"
"Ljava/util/Map;)[B",
(void*)ExecJsOnAppWithResult},
{"nativeDestoryAppContext", "(Ljava/lang/String;)I", (void*)DestoryAppContext},
};
static int registerWMLBridgeNativeMethods(JNIEnv* env, JNINativeMethod* methods,
int numMethods) {
if (g_WMLBridge_clazz == NULL) {
LOGE("registerWMLBridgeNativeMethods failed to find bridge class.");
return JNI_FALSE;
}
if ((env)->RegisterNatives(g_WMLBridge_clazz, methods, numMethods) < 0) {
LOGE(
"registerWMLBridgeNativeMethods failed to register native methods for "
"bridge class.");
return JNI_FALSE;
}
return JNI_TRUE;
}
static intptr_t g_WMLBridge_dispatchMessage = 0;
static void Java_WMLBridge_dispatchMessage(JNIEnv* env, jobject obj,
jstring clientID, jstring vmID,
jbyteArray data, jstring callback) {
jmethodID method_id = base::android::GetMethod(
env, g_WMLBridge_clazz, base::android::INSTANCE_METHOD, "dispatchMessage",
"(Ljava/lang/String;Ljava/lang/String;[BLjava/lang/String;)V",
&g_WMLBridge_dispatchMessage);
env->CallVoidMethod(obj, method_id, clientID, vmID, data, callback);
base::android::CheckException(env);
}
static intptr_t g_WMLBridge_dispatchMessageSync = 0;
static base::android::ScopedLocalJavaRef<jbyteArray>
Java_WMLBridge_dispatchMessageSync(JNIEnv* env, jobject obj, jstring clientID,
jstring vmID, jbyteArray data) {
jmethodID method_id = base::android::GetMethod(
env, g_WMLBridge_clazz, base::android::INSTANCE_METHOD,
"dispatchMessageSync", "(Ljava/lang/String;Ljava/lang/String;[B)[B",
&g_WMLBridge_dispatchMessageSync);
auto result = env->CallObjectMethod(obj, method_id, clientID, vmID, data);
base::android::CheckException(env);
return base::android::ScopedLocalJavaRef<jbyteArray>(
env, static_cast<jbyteArray>(result));
}
static intptr_t g_WMLBridge_postMessage = 0;
static void Java_WMLBridge_postMessage(JNIEnv* env, jobject obj, jstring vmID,
jbyteArray data) {
jmethodID method_id = base::android::GetMethod(
env, g_WMLBridge_clazz, base::android::INSTANCE_METHOD, "postMessage",
"(Ljava/lang/String;[B)V", &g_WMLBridge_postMessage);
env->CallVoidMethod(obj, method_id, vmID, data);
base::android::CheckException(env);
}
bool WMLBridge::RegisterJNIUtils(JNIEnv* env) {
jclass temp_class = env->FindClass(kWMLBridgeClassPath);
// use to check WMLBridge has already on env
if (env->ExceptionOccurred()) {
LOGE("failed find class WMBridge");
env->ExceptionDescribe();
env->ExceptionClear();
return false;
} else if (temp_class != nullptr) {
g_WMLBridge_clazz = (jclass)env->NewGlobalRef(temp_class);
env->DeleteLocalRef(temp_class);
LOGE("success find class WMBridge");
registerWMLBridgeNativeMethods(env, gWMMethods,
sizeof(gWMMethods) / sizeof(gWMMethods[0]));
return true;
}
return false;
}
void WMLBridge::PostMessage(JNIEnv* env, const char* vm_id, const char* data, int dataLength) {
if (jni_object() != NULL) {
auto jni_str = base::android::ScopedLocalJavaRef<jstring>(
env, env->NewStringUTF(vm_id));
auto jni_array = base::android::ScopedLocalJavaRef<jbyteArray>(
env, newJByteArray(env, data, dataLength));
Java_WMLBridge_postMessage(env, jni_object(), jni_str.Get(),
jni_array.Get());
}
}
void WMLBridge::DispatchMessage(JNIEnv *env, const char *client_id,
const char *data, int dataLength, const char *callback, const char* vm_id) {
if (jni_object() != NULL) {
auto jni_client_id = base::android::ScopedLocalJavaRef<jstring>(
env, newJString(env, client_id));
auto jni_array = base::android::ScopedLocalJavaRef<jbyteArray>(
env, newJByteArray(env, data, dataLength));
auto jni_callback = base::android::ScopedLocalJavaRef<jstring>(
env, newJString(env, callback));
auto jni_vm_id = base::android::ScopedLocalJavaRef<jstring>(env, newJString(env, vm_id));
Java_WMLBridge_dispatchMessage(env, jni_object(), jni_client_id.Get(),
jni_vm_id.Get(), jni_array.Get(),
jni_callback.Get());
}
}
base::android::ScopedLocalJavaRef<jbyteArray> WMLBridge::DispatchMessageSync(
JNIEnv* env, const char* client_id, const char* data, int dataLength,
const char* vm_id) {
if (jni_object() != NULL) {
auto jni_client_id = base::android::ScopedLocalJavaRef<jstring>(
env, newJString(env, client_id));
auto jni_array = base::android::ScopedLocalJavaRef<jbyteArray>(
env, newJByteArray(env, data, dataLength));
auto jni_vm_id =
base::android::ScopedLocalJavaRef<jstring>(env, newJString(env, vm_id));
return Java_WMLBridge_dispatchMessageSync(env, jni_object(),
jni_client_id.Get(),
jni_vm_id.Get(), jni_array.Get());
}
return base::android::ScopedLocalJavaRef<jbyteArray>();
}
} // namespace WeexCore