Skip to content

Commit 8c72d96

Browse files
author
Mihail Slavchev
committed
fix android activity life cycle
1 parent 52035ff commit 8c72d96

File tree

10 files changed

+4018
-220
lines changed

10 files changed

+4018
-220
lines changed

src/jni/Android.mk

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ include $(PREBUILT_STATIC_LIBRARY)
6262
include $(CLEAR_VARS)
6363
LOCAL_CPPFLAGS += -std=c++11
6464
LOCAL_MODULE := NativeScript
65-
LOCAL_SRC_FILES := com_tns_Platform.cpp com_tns_JsDebugger.cpp com_tns_AssetExtractor.cpp \
65+
LOCAL_SRC_FILES := com_tns_Platform.cpp com_tns_JsDebugger.cpp com_tns_AssetExtractor.cpp com_tns_NativeScriptActity.cpp \
6666
JEnv.cpp DirectBuffer.cpp \
6767
JsDebugger.cpp \
6868
NativeScriptRuntime.cpp MetadataNode.cpp MetadataTreeNode.cpp MetadataReader.cpp \

src/jni/MetadataNode.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1261,6 +1261,15 @@ void MetadataNode::CreateTopLevelNamespaces(const Handle<Object>& global)
12611261
}
12621262
}
12631263

1264+
void MetadataNode::InjectPrototype(Handle<Object>& target, Handle<Object>& implementationObject)
1265+
{
1266+
auto isolate = Isolate::GetCurrent();
1267+
1268+
implementationObject->SetAccessor(ConvertToV8String("super"), SuperAccessorGetterCallback, nullptr, implementationObject);
1269+
implementationObject->SetPrototype(target->GetPrototype());
1270+
target->SetPrototype(implementationObject);
1271+
}
1272+
12641273

12651274
string MetadataNode::TNS_PREFIX = "com/tns/gen/";
12661275
std::map<std::string, MetadataNode*> MetadataNode::s_name2NodeCache;

src/jni/MetadataNode.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,8 @@ namespace tns
8686

8787
static void BuildMetadata(uint32_t nodesLength, uint8_t *nodeData, uint32_t nameLength, uint8_t *nameData, uint32_t valueLength, uint8_t *valueData);
8888

89+
static void InjectPrototype(v8::Handle<v8::Object>& target, v8::Handle<v8::Object>& implementationObject);
90+
8991

9092
private:
9193
struct MethodCallbackData

src/jni/NativeScriptRuntime.cpp

Lines changed: 4 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,6 @@ void NativeScriptRuntime::Init(JavaVM *jvm, ObjectManager *objectManager)
4141
RequireClass = env.FindClass("com/tns/Require");
4242
assert(RequireClass != nullptr);
4343

44-
MAKE_CLASS_INSTANCE_OF_TYPE_STRONG = env.GetStaticMethodID(PlatformClass, "makeClassInstanceOfTypeStrong", "(Ljava/lang/String;)I");
45-
assert(MAKE_CLASS_INSTANCE_OF_TYPE_STRONG != nullptr);
46-
4744
CREATE_INSTANCE_METHOD_ID = env.GetStaticMethodID(PlatformClass, "createInstance", "([Ljava/lang/Object;II)Ljava/lang/Object;");
4845
assert(CREATE_INSTANCE_METHOD_ID != nullptr);
4946

@@ -126,17 +123,6 @@ bool NativeScriptRuntime::RegisterInstance(const Handle<Object>& jsObject, const
126123
return success;
127124
}
128125

129-
void NativeScriptRuntime::MakeClassInstanceOfTypeStrong(const string& className, const Handle<Object>& classObj)
130-
{
131-
JEnv env;
132-
133-
JniLocalRef param(env.NewStringUTF(className.c_str()));
134-
jint javaObjectID = env.CallStaticIntMethod(PlatformClass, MAKE_CLASS_INSTANCE_OF_TYPE_STRONG, (jstring)param);
135-
136-
jclass clazz = env.FindClass(className);
137-
objectManager->Link(classObj, javaObjectID, clazz);
138-
}
139-
140126
Handle<Value> NativeScriptRuntime::GetArrayElement(const Handle<Object>& array, uint32_t index, const string& arraySignature)
141127
{
142128
return arrayElementAccessor.GetArrayElement(array, index, arraySignature);
@@ -925,7 +911,7 @@ void NativeScriptRuntime::CreateTopLevelNamespaces(const Handle<Object>& global)
925911
MetadataNode::CreateTopLevelNamespaces(global);
926912
}
927913

928-
Handle<Value> NativeScriptRuntime::CallJSMethod(JNIEnv *_env, const Handle<Object>& jsObject, jstring methodName, jobjectArray args, TryCatch& tc)
914+
Handle<Value> NativeScriptRuntime::CallJSMethod(JNIEnv *_env, const Handle<Object>& jsObject, const string& methodName, jobjectArray args, TryCatch& tc)
929915
{
930916
SET_PROFILER_FRAME();
931917

@@ -936,29 +922,22 @@ Handle<Value> NativeScriptRuntime::CallJSMethod(JNIEnv *_env, const Handle<Objec
936922

937923
auto exceptionUtil = ExceptionUtil::GetInstance();
938924

939-
auto jsMethodName = ArgConverter::jstringToV8String(methodName);
940-
941925
//auto method = MetadataNode::GetPropertyFromImplementationObject(jsObject, jsMethodName);
942-
string name2 = ConvertToString(jsMethodName);
943-
auto method = jsObject->Get(ConvertToV8String(name2));
926+
auto method = jsObject->Get(ConvertToV8String(methodName));
944927

945928
if (method.IsEmpty() || method->IsUndefined())
946929
{
947-
string name = ConvertToString(jsMethodName);
948-
949930
stringstream ss;
950-
ss << "Cannot find method '" << name << "' implementation";
931+
ss << "Cannot find method '" << methodName << "' implementation";
951932

952933
ExceptionUtil::GetInstance()->ThrowExceptionToJs(ss.str());
953934

954935
result = Undefined(isolate);
955936
}
956937
else if (!method->IsFunction())
957938
{
958-
string name = ConvertToString(jsMethodName);
959-
960939
stringstream ss;
961-
ss << "Property '" << name << "' is not a function";
940+
ss << "Property '" << methodName << "' is not a function";
962941

963942
ExceptionUtil::GetInstance()->ThrowExceptionToJs(ss.str());
964943

@@ -1039,7 +1018,6 @@ JavaVM* NativeScriptRuntime::jvm = nullptr;
10391018
jclass NativeScriptRuntime::PlatformClass = nullptr;
10401019
jclass NativeScriptRuntime::RequireClass = nullptr;
10411020
jclass NativeScriptRuntime::JAVA_LANG_STRING = nullptr;
1042-
jmethodID NativeScriptRuntime::MAKE_CLASS_INSTANCE_OF_TYPE_STRONG = nullptr;
10431021
jmethodID NativeScriptRuntime::CREATE_INSTANCE_METHOD_ID = nullptr;
10441022
jmethodID NativeScriptRuntime::CACHE_CONSTRUCTOR_METHOD_ID = nullptr;
10451023
jmethodID NativeScriptRuntime::APP_FAIL_METHOD_ID = nullptr;

src/jni/NativeScriptRuntime.h

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,6 @@ namespace tns
3333

3434
static bool RegisterInstance(const v8::Handle<v8::Object>& jsObject, const std::string& name, const std::string& className, const ArgsWrapper& argWrapper, const v8::Handle<v8::Object>& implementationObject, bool isInterface);
3535

36-
static void MakeClassInstanceOfTypeStrong(const std::string& className, const v8::Handle<v8::Object>& classObj);
37-
3836
//
3937

4038
static v8::Handle<v8::Value> GetArrayElement(const v8::Handle<v8::Object>& array, uint32_t index, const std::string& arraySignature);
@@ -45,7 +43,7 @@ namespace tns
4543

4644
static void CallJavaMethod(const v8::Handle<v8::Object>& caller, const std::string& className, const std::string& methodName, MetadataEntry *entry, bool isStatic, bool isSuper, const v8::FunctionCallbackInfo<v8::Value>& args);
4745

48-
static v8::Handle<v8::Value> CallJSMethod(JNIEnv *_env, const v8::Handle<v8::Object>& jsObject, jstring methodName, jobjectArray args, v8::TryCatch& tc);
46+
static v8::Handle<v8::Value> CallJSMethod(JNIEnv *_env, const v8::Handle<v8::Object>& jsObject, const std::string& methodName, jobjectArray args, v8::TryCatch& tc);
4947

5048
//
5149

@@ -118,8 +116,6 @@ namespace tns
118116

119117
static JavaVM *jvm;
120118

121-
static jmethodID MAKE_CLASS_INSTANCE_OF_TYPE_STRONG;
122-
123119
static jmethodID CREATE_INSTANCE_METHOD_ID;
124120

125121
static jmethodID CACHE_CONSTRUCTOR_METHOD_ID;
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
#include "NativeScriptRuntime.h"
2+
#include "MetadataNode.h"
3+
#include "JniLocalRef.h"
4+
#include "JsArgConverter.h"
5+
#include "JsArgToArrayConverter.h"
6+
#include "ArgConverter.h"
7+
#include "Util.h"
8+
#include "V8GlobalHelpers.h"
9+
#include "V8StringConstants.h"
10+
#include "ExceptionUtil.h"
11+
#include "v8.h"
12+
#include "JEnv.h"
13+
#include "NativeScriptAssert.h"
14+
#include <sstream>
15+
#include <android/log.h>
16+
#include <assert.h>
17+
#include <string>
18+
19+
using namespace v8;
20+
using namespace std;
21+
using namespace tns;
22+
23+
extern Isolate *g_isolate;
24+
extern ObjectManager *g_objectManager;
25+
extern int AppJavaObjectID;
26+
27+
28+
jobject ConvertJsValueToJavaObject(JEnv& env, const Handle<Value>& value);
29+
30+
extern "C" jobjectArray Java_com_tns_NativeScriptActivity_getMethodOverrides(JNIEnv *_env, jobject obj, jint objectId, jobjectArray packagedArgs)
31+
{
32+
DEBUG_WRITE("getMethodOverrides called");
33+
34+
auto isolate = g_isolate;
35+
Isolate::Scope isolate_scope(isolate);
36+
37+
JEnv env(_env);
38+
39+
HandleScope handleScope(isolate);
40+
41+
TryCatch tc;
42+
43+
auto appInstance = g_objectManager->GetJsObjectByJavaObject(AppJavaObjectID);
44+
if (appInstance.IsEmpty())
45+
{
46+
ExceptionUtil::GetInstance()->ThrowExceptionToJava(tc, "NativeScript application not initialized correctly. Missing the global app object initialization.");
47+
return nullptr;
48+
}
49+
50+
string createActivityMethodName = "getActivity";
51+
auto createActivityFunction = appInstance->Get(ConvertToV8String(createActivityMethodName.c_str()));
52+
53+
if (createActivityFunction.IsEmpty() || !createActivityFunction->IsFunction())
54+
{
55+
ExceptionUtil::GetInstance()->ThrowExceptionToJava(tc, "NativeScript application not initialized correctly. No function 'createActivity' found on the application object.");
56+
return nullptr;
57+
}
58+
59+
auto jsResult = NativeScriptRuntime::CallJSMethod(env, appInstance, createActivityMethodName, packagedArgs, tc);
60+
auto jsInstance = jsResult.As<Object>();
61+
if (jsInstance.IsEmpty() || jsInstance->IsNull() || jsInstance->IsUndefined())
62+
{
63+
ExceptionUtil::GetInstance()->ThrowExceptionToJava(tc, "NativeScript application not initialized correctly. getActivity method returned invalid value.");
64+
return nullptr;
65+
}
66+
67+
auto jsActivity = g_objectManager->GetJsObjectByJavaObject(objectId);
68+
69+
MetadataNode::InjectPrototype(jsActivity, jsInstance);
70+
71+
jobjectArray methodOverrides = NativeScriptRuntime::GetMethodOverrides(env, jsInstance);
72+
return methodOverrides;
73+
}

src/jni/com_tns_Platform.cpp

Lines changed: 13 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -341,7 +341,7 @@ extern "C" jobject Java_com_tns_Platform_callJSMethodNative(JNIEnv *_env, jobjec
341341

342342
string method_name = ArgConverter::jstringToString(methodName);
343343

344-
auto jsResult = NativeScriptRuntime::CallJSMethod(env, jsObject, methodName, packagedArgs, tc);
344+
auto jsResult = NativeScriptRuntime::CallJSMethod(env, jsObject, method_name, packagedArgs, tc);
345345

346346
stringstream ss;
347347
ss << "Calling js method " << method_name << " failed";
@@ -355,7 +355,7 @@ extern "C" jobject Java_com_tns_Platform_callJSMethodNative(JNIEnv *_env, jobjec
355355
return javaObject;
356356
}
357357

358-
extern "C" jobjectArray Java_com_tns_Platform_createJSInstanceNative(JNIEnv *_env, jobject obj, jobject javaObject, jint javaObjectID, jstring className, jboolean createActivity, jobjectArray packagedCreationArgs)
358+
extern "C" void Java_com_tns_Platform_createJSInstanceNative(JNIEnv *_env, jobject obj, jobject javaObject, jint javaObjectID, jstring className)
359359
{
360360
SET_PROFILER_FRAME();
361361

@@ -375,139 +375,31 @@ extern "C" jobjectArray Java_com_tns_Platform_createJSInstanceNative(JNIEnv *_en
375375
Handle<Object> jsInstance;
376376
Handle<Object> implementationObject;
377377

378-
bool isActivity = createActivity == JNI_TRUE;
379-
380-
if (isActivity)
378+
auto proxyClassName = g_objectManager->GetClassName(javaObject);
379+
//
380+
if (proxyClassName == "com/tns/NativeScriptActivity")
381381
{
382-
auto appInstance = g_objectManager->GetJsObjectByJavaObject(AppJavaObjectID);
383-
if (appInstance.IsEmpty())
384-
{
385-
ExceptionUtil::GetInstance()->ThrowExceptionToJava(tc, "NativeScript application not initialized correctly. Missing the global app object initialization.");
386-
return nullptr;
387-
}
388-
389-
string createActivityMethodName = "getActivity";
390-
auto createActivityFunction = appInstance->Get(ConvertToV8String(createActivityMethodName.c_str()));
391-
392-
if (createActivityFunction.IsEmpty() || !createActivityFunction->IsFunction())
393-
{
394-
ExceptionUtil::GetInstance()->ThrowExceptionToJava(tc, "NativeScript application not initialized correctly. No function 'createActivity' found on the application object.");
395-
return nullptr;
396-
}
397-
398-
JniLocalRef jMethodName(env.NewStringUTF(createActivityMethodName.c_str()));
399-
TryCatch tc;
400-
auto jsResult = NativeScriptRuntime::CallJSMethod(env, appInstance, jMethodName, packagedCreationArgs, tc);
401-
jsInstance = jsResult.As<Object>();
402-
if (jsInstance.IsEmpty() || jsInstance->IsNull() || jsInstance->IsUndefined())
403-
{
404-
ExceptionUtil::GetInstance()->ThrowExceptionToJava(tc, "NativeScript application not initialized correctly. getActivity method returned invalid value.");
405-
return nullptr;
406-
}
407-
408-
//@@@
409-
// auto node = MetadataNode::GetNodeFromHandle(jsInstance);
410-
// string nodeName = node->GetName();
411-
//
412-
// if (nodeName != jniName)
413-
// {
414-
// ExceptionUtil::GetInstance()->ThrowExceptionToJava(tc, "NativeScript application not initialized correctly. createActivity returned wrong type.");
415-
// return nullptr;
416-
// }
382+
return;
417383
}
418-
else
384+
//
385+
DEBUG_WRITE("createJSInstanceNative class %s", proxyClassName.c_str());
386+
jsInstance = MetadataNode::CreateExtendedJSWrapper(isolate, proxyClassName);
387+
if (jsInstance.IsEmpty())
419388
{
420-
auto proxyClassName = g_objectManager->GetClassName(javaObject);
421-
DEBUG_WRITE("createJSInstanceNative class %s", proxyClassName.c_str());
422-
jsInstance = MetadataNode::CreateExtendedJSWrapper(isolate, proxyClassName);
423-
if (jsInstance.IsEmpty())
424-
{
425-
ExceptionUtil::GetInstance()->ThrowExceptionToJava(tc, "NativeScript application not initialized correctly. Cannot create extended JS wrapper.");
426-
return nullptr;
427-
}
389+
ExceptionUtil::GetInstance()->ThrowExceptionToJava(tc, "NativeScript application not initialized correctly. Cannot create extended JS wrapper.");
390+
return;
428391
}
429392

430393
implementationObject = MetadataNode::GetImplementationObject(jsInstance);
431394
if (implementationObject.IsEmpty())
432395
{
433396
NativeScriptRuntime::APP_FAIL("createJSInstanceNative: implementationObject is empty");
434-
return nullptr;
397+
return;
435398
}
436399
DEBUG_WRITE("createJSInstanceNative: implementationObject :%d", implementationObject->GetIdentityHash());
437400

438-
bool createTypeScriptActivity = isActivity && jsInstance->HasOwnProperty(V8StringConstants::GetIsPrototypeImplementationObject());
439-
440-
if (isActivity && !createTypeScriptActivity)
441-
{
442-
DEBUG_WRITE("createJSInstanceNative: creating js activity with classProxy: %d", jsInstance->GetIdentityHash());
443-
}
444-
445-
if (createTypeScriptActivity)
446-
{
447-
DEBUG_WRITE("createJSInstanceNative: creating typescript activity with classProxy: %d", jsInstance->GetIdentityHash());
448-
449-
auto node = MetadataNode::GetNodeFromHandle(jsInstance);
450-
451-
//call extends function on the prototype which must the be Parent function
452-
auto parent = jsInstance->GetPrototype().As<Function>();
453-
auto extendsFunc = parent->Get(String::NewFromUtf8(isolate, "__activityExtend")).As<Function>();
454-
ASSERT_MESSAGE(!extendsFunc.IsEmpty(), "__activityExtend support function not found on activity parent");
455-
456-
457-
Handle<Value> arguments[3];
458-
arguments[0] = parent;
459-
arguments[1] = jsInstance.As<Function>()->GetName();
460-
arguments[2] = implementationObject;
461-
auto extended = extendsFunc->Call(parent, 3, arguments).As<Function>();
462-
ASSERT_MESSAGE(!extended.IsEmpty(), "extend result is not an function");
463-
464-
extended->SetHiddenValue(ConvertToV8String("t::TypescriptActivity::DonNotRegisterInstance"), Boolean::New(isolate, true));
465-
auto extendedObject = extended->CallAsConstructor(0, nullptr).As<Object>();
466-
DEBUG_WRITE("createJSInstanceNative: typescript activity extendedObject's prototype : %d", extendedObject->GetPrototype().As<Object>()->GetIdentityHash());
467-
468-
469-
extendedObject->SetPrototype(implementationObject);
470-
//@@@
471-
//extendedObject->SetHiddenValue(ConvertToV8String(MetadataNode::METADATA_NODE_KEY_NAME), External::New(isolate, node));
472-
473-
bool success = extendedObject->SetHiddenValue(ConvertToV8String("t::ActivityImplementationObject"), implementationObject);
474-
ASSERT_MESSAGE(success == true, "Setting up the typescript activity implementation object failed");
475-
476-
//This will cause the Link to link the extendedObject not the empty object instance. This is on par with all typescript objects created through JS
477-
jsInstance = extendedObject;
478-
g_objectManager->Unlink(jsInstance);
479-
}
480-
481-
//@@@
482401
jclass clazz = env.FindClass(jniName);
483402
g_objectManager->Link(jsInstance, javaObjectID, clazz);
484-
485-
vector<jstring> methods;
486-
487-
auto propNames = implementationObject->GetOwnPropertyNames();
488-
auto propsLen = propNames->Length();
489-
for (auto i = 0; i < propsLen; i++)
490-
{
491-
auto name = propNames->Get(i).As<String>();
492-
auto method = implementationObject->Get(name);
493-
494-
if (method->IsFunction())
495-
{
496-
String::Utf8Value stringValue(name);
497-
jstring value = env.NewStringUTF(*stringValue);
498-
499-
methods.push_back(value);
500-
}
501-
}
502-
503-
jclass stringClass = env.FindClass("java/lang/String");
504-
jobjectArray methodOverrides = env.NewObjectArray(methods.size(), stringClass, nullptr);
505-
for (int i = 0; i < methods.size(); i++)
506-
{
507-
env.SetObjectArrayElement(methodOverrides, i, methods[i]);
508-
}
509-
510-
return methodOverrides;
511403
}
512404

513405
extern "C" jint Java_com_tns_Platform_generateNewObjectId(JNIEnv *env, jobject obj)

0 commit comments

Comments
 (0)