blob: 94a3ac66abf0beb11cf341116cbd66dc799f7dd8 [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 "weexcore_impl_android.h"
#include <android/jsengine/multiprocess/WeexProxy.h>
#include <android/base/jni/android_jni.h>
#include <android/jniprebuild/jniheader/WXBridge_jni.h>
#include <android/base/string/string_utils.h>
#include <core/render/manager/render_manager.h>
#include <core/render/page/render_page.h>
#include <core/render/node/render_object.h>
#include <core/config/core_environment.h>
#include <map>
#include <core/manager/weex_core_manager.h>
using namespace WeexCore;
jclass jBridgeClazz;
jclass jWXJSObject;
jclass jWXLogUtils;
jclass jMapClazz;
jclass jSetClazz;
jmethodID jMapConstructorMethodId = nullptr;
jmethodID jMapPutMethodId = nullptr;
jmethodID jSetConstructorMethodId = nullptr;
jmethodID jSetAddMethodId = nullptr;
jclass jWMBridgeClazz = nullptr;
jmethodID jDoubleValueMethodId;
jobject jThis;
jobject jWMThis;
jlongArray jFirstScreenRenderTime = nullptr;
jlongArray jRenderFinishTime = nullptr;
std::map<std::string, jobject> componentTypeCache;
JStringCache refCache(2048);
static JavaVM *sVm = NULL;
JNIEnv *getJNIEnv() {
JNIEnv *env = NULL;
if ((sVm)->GetEnv((void **) &env, JNI_VERSION_1_4) != JNI_OK) {
return JNI_FALSE;
}
return env;
}
jstring getComponentTypeFromCache(const std::string type) {
std::map<std::string, jobject>::const_iterator iter = componentTypeCache.find(type);
if (iter != componentTypeCache.end()) {
return (jstring)(iter->second);
} else {
return nullptr;
}
}
jstring putComponentTypeToCache(const std::string type) {
JNIEnv *env = getJNIEnv();
jstring jType = env->NewStringUTF(type.c_str());
jobject jGlobalType = env->NewGlobalRef(jType);
componentTypeCache.insert(std::pair<std::string, jobject>(type, jGlobalType));
env->DeleteLocalRef(jType);
return (jstring) jGlobalType;
}
jstring getKeyFromCache(JNIEnv *env, const char *key) {
return refCache.GetString(env, key);
}
jfloatArray c2jFloatArray(JNIEnv *env, const float c_array[]) {
if (nullptr == c_array) {
return nullptr;
}
if (0 == c_array[0]
&& 0 == c_array[1]
&& 0 == c_array[2]
&& 0 == c_array[3]) {
// Default value;
return nullptr;
}
jfloatArray jArray = env->NewFloatArray(4);
env->SetFloatArrayRegion(jArray, 0, 4, c_array);
return jArray;
}
static jint InitFrameworkEnv(JNIEnv *env, jobject jcaller,
jstring framework,
jobject params,
jstring cacheDir,
jboolean pieSupport) {
jThis = env->NewGlobalRef(jcaller);
jclass tempClass = env->FindClass(
"com/taobao/weex/bridge/WXBridge");
jBridgeClazz = (jclass) env->NewGlobalRef(tempClass);
env->DeleteLocalRef(tempClass);
return WeexProxy::doInitFramework(env, jThis, framework, params, cacheDir, pieSupport);
}
static void BindMeasurementToRenderObject(JNIEnv* env, jobject jcaller,
jlong ptr){
RenderObject *render = convert_long_to_render_object(ptr);
if(render){
render->BindMeasureFunc();
}
}
static void OnInstanceClose(JNIEnv *env, jobject jcaller, jstring instanceId) {
WeexCoreManager::getInstance()->getPlatformBridge()->onInstanceClose(
env->GetStringUTFChars(instanceId, JNI_FALSE)
);
}
static void SetDefaultHeightAndWidthIntoRootDom(JNIEnv *env, jobject jcaller,
jstring instanceId, jfloat defaultWidth, jfloat defaultHeight,
jboolean isWidthWrapContent, jboolean isHeightWrapContent) {
WeexCoreManager::getInstance()->getPlatformBridge()->setDefaultHeightAndWidthIntoRootDom(
env->GetStringUTFChars(instanceId, JNI_FALSE),
defaultWidth,
defaultHeight,
isWidthWrapContent,
isHeightWrapContent
);
}
static void SetRenderContainerWrapContent(JNIEnv* env, jobject jcaller, jboolean wrap, jstring instanceId) {
const char *cInstanceId = env->GetStringUTFChars(instanceId, JNI_FALSE);
WeexCoreManager::getInstance()->getPlatformBridge()->setRenderContainerWrapContent(
cInstanceId,wrap
);
}
static jlongArray GetFirstScreenRenderTime(JNIEnv *env, jobject jcaller, jstring instanceId) {
jlongArray jTemp = env->NewLongArray(3);
RenderPage *page = RenderManager::GetInstance()->GetPage(jString2StrFast(env, instanceId));
if (page == nullptr) {
if (jFirstScreenRenderTime != nullptr) {
env->DeleteGlobalRef(jFirstScreenRenderTime);
jFirstScreenRenderTime = nullptr;
}
jFirstScreenRenderTime = static_cast<jlongArray>(env->NewGlobalRef(jTemp));
return jFirstScreenRenderTime;
}
std::vector<int64_t> temp = page->PrintFirstScreenLog();
jlong ret[3];
ret[0] = temp[0];
ret[1] = temp[1];
ret[2] = temp[2];
env->SetLongArrayRegion(jTemp, 0, 3, ret);
if (jFirstScreenRenderTime != nullptr) {
env->DeleteGlobalRef(jFirstScreenRenderTime);
jFirstScreenRenderTime = nullptr;
}
jFirstScreenRenderTime = static_cast<jlongArray>(env->NewGlobalRef(jTemp));
env->DeleteLocalRef(jTemp);
return jFirstScreenRenderTime;
}
static jlongArray GetRenderFinishTime(JNIEnv *env, jobject jcaller, jstring instanceId) {
jlongArray jTemp = env->NewLongArray(3);
RenderPage *page = RenderManager::GetInstance()->GetPage(jString2StrFast(env, instanceId));
if (page == nullptr) {
if (jRenderFinishTime != nullptr) {
env->DeleteGlobalRef(jRenderFinishTime);
jRenderFinishTime = nullptr;
}
jRenderFinishTime = static_cast<jlongArray>(env->NewGlobalRef(jTemp));
return jRenderFinishTime;
}
std::vector<int64_t> temp = page->PrintRenderSuccessLog();
jlong ret[3];
ret[0] = temp[0];
ret[1] = temp[1];
ret[2] = temp[2];
env->SetLongArrayRegion(jTemp, 0, 3, ret);
if (jRenderFinishTime != nullptr) {
env->DeleteGlobalRef(jRenderFinishTime);
jRenderFinishTime = nullptr;
}
jRenderFinishTime = static_cast<jlongArray>(env->NewGlobalRef(jTemp));
env->DeleteLocalRef(jTemp);
return jRenderFinishTime;
}
//Notice that this method is invoked from main thread.
static jboolean NotifyLayout(JNIEnv* env, jobject jcaller, jstring instanceId) {
bool ret = WeexCoreManager::getInstance()->getPlatformBridge()->notifyLayout(
env->GetStringUTFChars(instanceId, JNI_FALSE)
);
return ret ? JNI_TRUE : JNI_FALSE;
}
//Notice that this method is invoked from JS thread.
static void ForceLayout(JNIEnv *env, jobject jcaller, jstring instanceId) {
WeexCoreManager::getInstance()->getPlatformBridge()->forceLayout(
env->GetStringUTFChars(instanceId, JNI_FALSE)
);
}
static void SetStyleWidth(JNIEnv *env, jobject jcaller,
jstring instanceId, jstring ref, jfloat value) {
WeexCoreManager::getInstance()->getPlatformBridge()->setStyleWidth(
env->GetStringUTFChars(instanceId, JNI_FALSE),
env->GetStringUTFChars(ref, JNI_FALSE),
value
);
}
static void SetStyleHeight(JNIEnv *env, jobject jcaller,
jstring instanceId, jstring ref, jfloat value) {
WeexCoreManager::getInstance()->getPlatformBridge()->setStyleHeight(
env->GetStringUTFChars(instanceId, JNI_FALSE),
env->GetStringUTFChars(ref, JNI_FALSE),
value
);
}
static void SetMargin(JNIEnv *env, jobject jcaller,
jstring instanceId, jstring ref, jint edge, jfloat value) {
WeexCoreManager::getInstance()->getPlatformBridge()->setMargin(
env->GetStringUTFChars(instanceId, JNI_FALSE),
env->GetStringUTFChars(ref, JNI_FALSE),
edge,
value
);
}
static void SetPadding(JNIEnv *env, jobject jcaller,
jstring instanceId, jstring ref, jint edge, jfloat value) {
WeexCoreManager::getInstance()->getPlatformBridge()->setPadding(
env->GetStringUTFChars(instanceId, JNI_FALSE),
env->GetStringUTFChars(ref, JNI_FALSE),
edge,
value
);
}
static void SetPosition(JNIEnv *env, jobject jcaller,
jstring instanceId, jstring ref, jint edge, jfloat value) {
WeexCoreManager::getInstance()->getPlatformBridge()->setPosition(
env->GetStringUTFChars(instanceId, JNI_FALSE),
env->GetStringUTFChars(ref, JNI_FALSE),
edge,
value
);
}
static void MarkDirty(JNIEnv *env, jobject jcaller,
jstring instanceId, jstring ref, jboolean dirty) {
WeexCoreManager::getInstance()->getPlatformBridge()->markDirty(
env->GetStringUTFChars(instanceId, JNI_FALSE),
env->GetStringUTFChars(ref, JNI_FALSE),
dirty
);
}
static void RegisterCoreEnv(JNIEnv *env, jobject jcaller, jstring key, jstring value) {
LOGE("RegisterCoreEnv,key: %s, value: %s", jString2StrFast(env, key).c_str(),
jString2StrFast(env, value).c_str());
WXCoreEnvironment::getInstance()->AddOption(jString2StrFast(env, key), jString2StrFast(env, value));
}
static jint InitFramework(JNIEnv *env, jobject object, jstring script, jobject params) {
jThis = env->NewGlobalRef(object);
jclass tempClass = env->FindClass(
"com/taobao/weex/bridge/WXBridge");
jBridgeClazz = (jclass) env->NewGlobalRef(tempClass);
env->DeleteLocalRef(tempClass);
return WeexProxy::doInitFramework(env, jThis, script, params);
}
static jint ExecJSService(JNIEnv *env, jobject object, jstring script) {
if (script == nullptr)
return false;
return WeexProxy::execJSService(env, object, script);
}
static void TakeHeapSnapshot(JNIEnv *env, jobject object, jstring name) {
}
/**
* Called to execute JavaScript such as . createInstance(),destroyInstance ext.
*
*/
static jint ExecJS(JNIEnv *env, jobject jthis, jstring jinstanceid, jstring jnamespace, jstring jfunction, jobjectArray jargs) {
if (jfunction == NULL || jinstanceid == NULL) {
LOGE("native_execJS function is NULL");
return false;
}
return WeexProxy::execJS(env, jThis, jinstanceid, jnamespace, jfunction, jargs);
}
static jbyteArray ExecJSWithResult(JNIEnv* env, jobject jcaller, jstring instanceId, jstring _namespace, jstring _function, jobjectArray args) {
if (_function == NULL || instanceId == NULL) {
LOGE("native_execJS function is NULL");
return NULL;
}
return WeexProxy::execJSWithResult(env, jcaller, instanceId, _namespace, _function, args);
}
static void UpdateGlobalConfig(JNIEnv* env, jobject jcaller, jstring config) {
WeexProxy::updateGlobalConfig(env, jcaller, config);
}
static jint CreateInstanceContext(JNIEnv* env, jobject jcaller, jstring instanceId, jstring name, jstring function, jobjectArray args) {
return WeexProxy::createInstanceContext(env, jcaller, instanceId, name, function, args);
}
static jint DestoryInstance(JNIEnv* env, jobject jcaller, jstring instanceId, jstring name, jstring function, jobjectArray args) {
return WeexProxy::destoryInstance(env, jcaller, instanceId, name, function, args);
}
static jstring ExecJSOnInstance(JNIEnv* env, jobject jcaller, jstring instanceId, jstring script, jint type) {
return WeexProxy::execJSOnInstance(env, jcaller, instanceId, script, type);
}
static jint native_initAppFramework(JNIEnv* env,
jobject jcaller,
jstring jinstanceid,
jstring jframwork,
jobjectArray jargs) {
jWMThis = env->NewGlobalRef(jcaller);
Bridge_Impl_Android::getInstance()->setGlobalWMRef(jWMThis);
return WeexProxy::initAppFramework(env, jcaller, jinstanceid, jframwork, jargs);
}
static jint native_destoryAppContext(JNIEnv* env,
jobject jcaller,
jstring jinstanceid) {
return WeexProxy::destoryAppContext(env, jcaller, jinstanceid);
}
static jint native_createAppContext(JNIEnv* env,
jobject jcaller,
jstring jinstanceid,
jstring jbundle,
jobject jargs) {
return WeexProxy::createAppContext(env, jcaller, jinstanceid, jbundle, jargs);
}
static jbyteArray native_execJsOnAppWithResult(JNIEnv* env,
jobject jcaller,
jstring jinstanceid,
jstring jbundle,
jobject jargs) {
return WeexProxy::execJsOnAppWithResult(env, jcaller, jinstanceid, jbundle, jargs);
}
static jint native_execJsOnApp(JNIEnv* env,
jobject jcaller,
jstring jinstanceid,
jstring jfunction,
jobjectArray jargs) {
return WeexProxy::execJsOnApp(env, jcaller, jinstanceid, jfunction, jargs);
}
namespace WeexCore {
bool RegisterJNIUtils(JNIEnv *env) {
return RegisterNativesImpl(env);
}
static JNINativeMethod gWMMethods[] = {
{"initAppFramework",
"(Ljava/lang/String;Ljava/lang/String;[Lcom/taobao/weex/bridge/WXJSObject;)I",
(void *) native_initAppFramework},
{"createAppContext",
"(Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;)I",
(void *) native_createAppContext},
{ "execJsOnApp",
"(Ljava/lang/String;Ljava/lang/String;"
"[Lcom/taobao/weex/bridge/WXJSObject;)I",
(void*)native_execJsOnApp },
{ "execJsOnAppWithResult",
"(Ljava/lang/String;Ljava/lang/String;"
"Ljava/util/Map;)[B",
(void*)native_execJsOnAppWithResult },
{ "destoryAppContext",
"(Ljava/lang/String;)I",
(void*)native_destoryAppContext },
};
static int registerWMLBridgeNativeMethods(JNIEnv* env, JNINativeMethod* methods, int numMethods) {
if (jWMBridgeClazz == NULL) {
LOGE("registerWMLBridgeNativeMethods failed to find bridge class.");
return JNI_FALSE;
}
if ((env)->RegisterNatives(jWMBridgeClazz, methods, numMethods) < 0) {
LOGE("registerWMLBridgeNativeMethods failed to register native methods for bridge class.");
return JNI_FALSE;
}
return JNI_TRUE;
}
jint OnLoad(JavaVM *vm, void *reserved) {
LOGD("begin JNI_OnLoad");
JNIEnv *env;
/* Get environment */
if ((vm)->GetEnv((void **) &env, JNI_VERSION_1_4) != JNI_OK) {
return JNI_FALSE;
}
try {
throw 1;
} catch (int) {
}
sVm = vm;
jclass tempClass = env->FindClass(
"com/taobao/weex/bridge/WXBridge");
jBridgeClazz = (jclass) env->NewGlobalRef(tempClass);
tempClass = env->FindClass("com/taobao/weex/bridge/WXJSObject");
jWXJSObject = (jclass) env->NewGlobalRef(tempClass);
tempClass = env->FindClass("com/taobao/weex/utils/WXLogUtils");
jWXLogUtils = (jclass) env->NewGlobalRef(tempClass);
tempClass = env->FindClass("com/taobao/weex/utils/WXMap");
jMapClazz = (jclass) env->NewGlobalRef(tempClass);
tempClass = env->FindClass("java/util/HashSet");
jSetClazz = (jclass) env->NewGlobalRef(tempClass);
jMapConstructorMethodId = env->GetMethodID(jMapClazz, "<init>", "()V");
jMapPutMethodId = env->GetMethodID(jMapClazz, "put", "(Ljava/lang/String;[B)Ljava/lang/String;");
jSetConstructorMethodId = env->GetMethodID(jSetClazz, "<init>", "()V");
jSetAddMethodId = env->GetMethodID(jSetClazz, "add", "(Ljava/lang/Object;)Z");
// can use this code to manal register jni
tempClass = nullptr;
tempClass = env->FindClass("com/taobao/windmill/bridge/WMLBridge");
// use to check WMLBridge has already on env
if (env->ExceptionOccurred()) {
LOGE("failed find class WMBridge");
env->ExceptionDescribe();
env->ExceptionClear();
jWMBridgeClazz = nullptr;
} else if (tempClass != nullptr) {
jWMBridgeClazz = (jclass)env->NewGlobalRef(tempClass);
LOGE("success find class WMBridge");
registerWMLBridgeNativeMethods(env, gWMMethods, sizeof(gWMMethods) / sizeof(gWMMethods[0]));
}
env->DeleteLocalRef(tempClass);
LOGD("end JNI_OnLoad");
WeexProxy::setCacheDir(env);
return JNI_VERSION_1_4;
}
void Unload(JavaVM *vm, void *reserved) {
LOGD("beigin JNI_OnUnload");
JNIEnv *env;
/* Get environment */
if ((vm)->GetEnv((void **) &env, JNI_VERSION_1_4) != JNI_OK) {
return;
}
env->DeleteGlobalRef(jBridgeClazz);
env->DeleteGlobalRef(jWXJSObject);
env->DeleteGlobalRef(jWXLogUtils);
env->DeleteGlobalRef(jMapClazz);
jMapConstructorMethodId = nullptr;
jMapPutMethodId = nullptr;
jSetConstructorMethodId = nullptr;
jSetAddMethodId = nullptr;
if (jFirstScreenRenderTime != nullptr) {
env->DeleteLocalRef(jFirstScreenRenderTime);
jFirstScreenRenderTime = nullptr;
}
if (jRenderFinishTime != nullptr) {
env->DeleteLocalRef(jRenderFinishTime);
jRenderFinishTime = nullptr;
}
for (auto iter = componentTypeCache.begin(); iter != componentTypeCache.end(); iter++) {
if (iter->second != nullptr) {
env->DeleteGlobalRef(iter->second);
iter->second = nullptr;
}
}
componentTypeCache.clear();
refCache.clearRefCache(env);
if (jThis)
env->DeleteGlobalRef(jThis);
if (jWMThis)
env->DeleteLocalRef(jWMThis);
WeexProxy::reset();
LOGD(" end JNI_OnUnload");
}
}