Skip to content

Commit

Permalink
Merge branch 'release/0.2.0'
Browse files Browse the repository at this point in the history
# Conflicts:
#	images/dartnative.png
  • Loading branch information
yulingtianxia committed Jul 27, 2020
2 parents f078189 + 043df14 commit 2f55658
Show file tree
Hide file tree
Showing 63 changed files with 1,430 additions and 732 deletions.
5 changes: 5 additions & 0 deletions dart_native/CHANGELOG.md
@@ -1,3 +1,8 @@
## 0.2.0

* Performance optimization and more feature for Android.
* Fix bugs.

## 0.1.18

* Support annotation for API availability.
Expand Down
@@ -1,8 +1,13 @@
package com.dartnative.dart_native;

import android.text.TextUtils;
import android.util.Log;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;

public class DartNative {
Expand Down Expand Up @@ -38,7 +43,7 @@ public static String getMethodType(String methodName) {

public static Method getMethod(String method) {
try {
return targetClass.getDeclaredMethod(method);
return targetClass.getDeclaredMethod(method, double.class);
} catch (NoSuchMethodException e) {
throw new NoSuchElementException(e.getMessage());
}
Expand All @@ -65,4 +70,32 @@ public static String[] getMethodParams(String methodName) {
}
return methodTypes;
}

private static Map<String, Class> basicClassMap = new HashMap<String, Class>(){{
put("I", int.class);
}};

public static String getMethodReturnType(Class cls, String methodName, String[] argTypes) {
try {
Class[] parameterTypes = new Class[argTypes.length];
for (int index = 0; index < argTypes.length; index++) {
String type = argTypes[index];
if (basicClassMap.containsKey(type)) {
parameterTypes[index] = basicClassMap.get(type);
continue;
}

parameterTypes[index] = Class.forName(type);
}
Method findMethod = cls.getMethod(methodName, parameterTypes);
String type = findMethod.getReturnType().toString();
Log.d("HUIZZ", "type info " + type);
return type;
} catch (NoSuchMethodException ignored) {

} catch (ClassNotFoundException ignored) {

}
return null;
}
}
182 changes: 84 additions & 98 deletions dart_native/android/src/main/jni/dart_native.cpp
Expand Up @@ -15,18 +15,6 @@ static JavaVM *gJvm = nullptr;
static jobject gClassLoader;
static jmethodID gFindClassMethod;

static std::map<char, char *> signature_decoding = {
{'C', "char"},
{'I', "int"},
{'D', "double"},
{'F', "float"},
{'B', "byte"},
{'S', "short"},
{'J', "long"},
{'Z', "boolean"},
{'V', "void"}
};

JNIEnv *getEnv() {
JNIEnv *env;
int status = gJvm->GetEnv((void **) &env, JNI_VERSION_1_6);
Expand Down Expand Up @@ -84,14 +72,16 @@ void *createTargetClass(char *targetClassName) {
jobject newObject = curEnv->NewGlobalRef(curEnv->NewObject(cls, constructor));
cache[newObject] = static_cast<jclass>(curEnv->NewGlobalRef(cls));


if (bShouldDetach) {
gJvm->DetachCurrentThread();
}

return newObject;
}

char *nativeMethodType(const char *methodName) {

void releaseTargetClass(void *classPtr) {
JNIEnv *curEnv;
bool bShouldDetach = false;

Expand All @@ -102,160 +92,156 @@ char *nativeMethodType(const char *methodName) {
NSLog("AttachCurrentThread : %d", error);
}

jclass cls = findClass(curEnv, "com/dartnative/dart_native/DartNative");
char *typeResult = nullptr;

if (cls != nullptr) {
jmethodID method = curEnv->GetStaticMethodID(cls, "getMethodType",
"(Ljava/lang/String;)Ljava/lang/String;");
if (method != nullptr) {
jstring type = (jstring) curEnv->CallStaticObjectMethod(cls, method,
curEnv->NewStringUTF(
methodName));
typeResult = (char *) curEnv->GetStringUTFChars(type, 0);
}
}
jobject object = static_cast<jobject>(classPtr);
curEnv->DeleteGlobalRef(object);
cache[object] = NULL;

if (bShouldDetach) {
gJvm->DetachCurrentThread();
}
}

char *findReturnType(JNIEnv *curEnv, jclass cls, jobject object, char* methondName, char **argType) {
jclass nativeClass = curEnv->FindClass("com/dartnative/dart_native/DartNative");
jmethodID nativeMethodID = curEnv->GetStaticMethodID(nativeClass,
"getMethodReturnType", "(Ljava/lang/Class;Ljava/lang/String;[Ljava/lang/String;)Ljava/lang/String;");

// jobjectArray stringArray = new jobjectArray()

// curEnv->CallStaticObjectMethodA(nativeClass, nativeMethodID, argType);
}

char *spliceChar(char *dest, char *src) {
char *result = (char *)malloc(strlen(dest) + strlen(src));
strcpy(result, dest);
strcat(result, src);
return result;
}

return typeResult;
char *generateSignature(char **argTypes) {
char *signature = const_cast<char *>("(");
int argCount = 0;
for(; *argTypes ; ++argTypes, ++argCount) {
signature = spliceChar(signature, *argTypes);
}
return spliceChar(signature, const_cast<char *>(")"));
}

void fillArgsToJvalue(void **args, char **signaturesType, jvalue *argValues, int argsLength, JNIEnv *curEnv) {
NSLog("arg length : %d", argsLength);
for (jsize index(0); index < argsLength; ++index) {
if (strlen(signaturesType[index]) > 1) {
if (strcmp(signaturesType[index], "Ljava/lang/String;") == 0) {
char * stringArg = (char *)*args;
jclass strClass = curEnv->FindClass("java/lang/String");
jmethodID strMethodID = curEnv->GetMethodID(strClass, "<init>","([BLjava/lang/String;)V");
jbyteArray bytes = curEnv->NewByteArray(strlen(stringArg));
curEnv->SetByteArrayRegion(bytes, 0, strlen(stringArg), (jbyte *) stringArg);
jstring encoding = curEnv->NewStringUTF("utf-8");
argValues[index].l = (jstring) curEnv->NewObject(strClass, strMethodID, bytes, encoding);
void fillArgs(void **args, char **argTypes, jvalue *argValues, JNIEnv *curEnv) {
for(jsize index(0); *argTypes ; ++args, ++index, ++argTypes) {
char *argType = *argTypes;
if (strlen(argType) > 1) {
if (strcmp(argType, "Ljava/lang/String;") == 0) {
argValues[index].l = curEnv->NewStringUTF((char *)*args);
}
else {
jobject object = static_cast<jobject>(*args);
argValues[index].l = object;
}
}
else if (strcmp(signaturesType[index], "C") == 0) {
else if (strcmp(argType, "C") == 0) {
argValues[index].c = (jchar) *(char *) args;
}
else if(strcmp(signaturesType[index], "I") == 0) {
else if(strcmp(argType, "I") == 0) {
argValues[index].i = (jint) *((int *) args);
}
else if(strcmp(signaturesType[index], "D") == 0) {
else if(strcmp(argType, "D") == 0) {
argValues[index].d = (jdouble) *((double *) args);
}
else if(strcmp(signaturesType[index], "F") == 0) {
else if(strcmp(argType, "F") == 0) {
argValues[index].f = (jfloat) *((float *) args);
}
else if(strcmp(signaturesType[index], "B") == 0) {
else if(strcmp(argType, "B") == 0) {
argValues[index].b = (jbyte) *((int8_t *) args);
}
else if(strcmp(signaturesType[index], "S") == 0) {
else if(strcmp(argType, "S") == 0) {
argValues[index].s = (jshort) *((int16_t *) args);
}
else if(strcmp(signaturesType[index], "J") == 0) {
else if(strcmp(argType, "J") == 0) {
argValues[index].j = (jlong) *((int64_t *) args);
}
else if(strcmp(signaturesType[index], "Z") == 0) {
else if(strcmp(argType, "Z") == 0) {
argValues[index].z = static_cast<jboolean>(*((int *) args));
}
else if(strcmp(signaturesType[index], "V") == 0) {}
++args;
else if(strcmp(argType, "V") == 0) {}
}
}

void *invokeNativeMethod(void *classPtr, char *methodName, void **args, char *methodSignature) {

void *invokeNativeMethodNeo(void *classPtr, char *methodName, void **args, char **argTypes, char *returnType) {
JNIEnv *curEnv;
bool bShouldDetach = false;
void *nativeInvokeResult = nullptr;

auto error = gJvm->GetEnv((void **) &curEnv, JNI_VERSION_1_6);
if (error < 0) {
error = gJvm->AttachCurrentThread(&curEnv, nullptr);
gJvm->AttachCurrentThread(&curEnv, nullptr);
bShouldDetach = true;
NSLog("AttachCurrentThread : %d", error);
}
jobject object = static_cast<jobject>(classPtr);
jclass cls = cache[object];
jmethodID method = curEnv->GetMethodID(cls, methodName, methodSignature);

//todo ** length
char **signaturesType = new char*[strlen(methodSignature)];
int argumentsCount = 0;
{
std::string strSignature = methodSignature;
std::regex regexSignature("(C|I|D|F|B|S|J|Z|V|L.*?;)");
std::sregex_iterator itBegin(strSignature.begin(), strSignature.end(), regexSignature);
std::sregex_iterator itEnd;
for (std::sregex_iterator i = itBegin; i != itEnd; ++i) {
std::smatch match = *i;
signaturesType[argumentsCount] = const_cast<char *>(match.str().c_str());
++argumentsCount;
}
}

jvalue *argValues = new jvalue[argumentsCount - 1];
fillArgsToJvalue(args, signaturesType, argValues, argumentsCount - 1, curEnv);

if (strlen(signaturesType[argumentsCount - 1]) > 1) {
if (strcmp(signaturesType[argumentsCount - 1], "Ljava/lang/String;") == 0) {
jstring nativeString = (jstring)curEnv->CallObjectMethodA(object, method, argValues);
char *toChar = NULL;
jclass clsstring = curEnv->FindClass("java/lang/String");
jstring strencode = curEnv->NewStringUTF("utf-8");
jmethodID strMethodID = curEnv->GetMethodID(clsstring, "getBytes", "(Ljava/lang/String;)[B");
jbyteArray byteArr = (jbyteArray) curEnv->CallObjectMethod(nativeString, strMethodID, strencode);
jsize jsLength = curEnv->GetArrayLength(byteArr);
jbyte *rbyte = curEnv->GetByteArrayElements(byteArr, JNI_FALSE);
if (jsLength > 0) {
toChar = (char *) malloc(static_cast<size_t>(jsLength + 1));
memcpy(toChar, rbyte, static_cast<size_t>(jsLength));
toChar[jsLength] = 0;
}
curEnv->ReleaseByteArrayElements(byteArr, rbyte, 0);
nativeInvokeResult = (void *) toChar;
char *signature = generateSignature(argTypes);
jvalue *argValues = new jvalue[strlen(signature) - 2];
fillArgs(args, argTypes, argValues, curEnv);
jmethodID method = curEnv->GetMethodID(cls, methodName, spliceChar(signature, returnType));

if (strlen(returnType) > 1) {
if (strcmp(returnType, "Ljava/lang/String;") == 0) {
jstring javaString = (jstring)curEnv->CallObjectMethodA(object, method, argValues);
nativeInvokeResult = (char *) curEnv->GetStringUTFChars(javaString, 0);
curEnv->DeleteLocalRef(javaString);
}
else {
jobject obj = curEnv->NewGlobalRef(curEnv->CallObjectMethodA(object, method, argValues));
//store class value
char* clsName= new char[strlen(returnType)];
strlcpy(clsName, returnType + 1, strlen(returnType) - 1);
cache[obj] = static_cast<jclass>(curEnv->NewGlobalRef(findClass(curEnv, clsName)));
free(clsName);
nativeInvokeResult = obj;
}
}
else if (strcmp(signaturesType[argumentsCount - 1], "C") == 0) {
else if (strcmp(returnType, "C") == 0) {
auto nativeChar = curEnv->CallCharMethodA(object, method, argValues);
nativeInvokeResult = (void *) nativeChar;
}
else if(strcmp(signaturesType[argumentsCount - 1], "I") == 0) {
else if(strcmp(returnType, "I") == 0) {
auto nativeInt = curEnv->CallIntMethodA(object, method, argValues);
nativeInvokeResult = (void *) nativeInt;
}
else if(strcmp(signaturesType[argumentsCount - 1], "D") == 0) {
else if(strcmp(returnType, "D") == 0) {
auto nativeDouble = curEnv->CallDoubleMethodA(object, method, argValues);
double cDouble = (double) nativeDouble;
memcpy(&nativeInvokeResult, &cDouble, sizeof(double));
}
else if(strcmp(signaturesType[argumentsCount - 1], "F") == 0) {
else if(strcmp(returnType, "F") == 0) {
auto nativeDouble = curEnv->CallFloatMethodA(object, method, argValues);
float cDouble = (float) nativeDouble;
memcpy(&nativeInvokeResult, &cDouble, sizeof(float));
}
else if(strcmp(signaturesType[argumentsCount - 1], "B") == 0) {
else if(strcmp(returnType, "B") == 0) {
auto nativeByte = curEnv->CallByteMethodA(object, method, argValues);
nativeInvokeResult = (void *) nativeByte;
}
else if(strcmp(signaturesType[argumentsCount - 1], "S") == 0) {
else if(strcmp(returnType, "S") == 0) {
auto nativeShort = curEnv->CallShortMethodA(object, method, argValues);
nativeInvokeResult = (void *) nativeShort;
}
else if(strcmp(signaturesType[argumentsCount - 1], "J") == 0) {
else if(strcmp(returnType, "J") == 0) {
auto nativeLong = curEnv->CallLongMethodA(object, method, argValues);
nativeInvokeResult = (void *) nativeLong;
}
else if(strcmp(signaturesType[argumentsCount - 1], "Z") == 0) {
else if(strcmp(returnType, "Z") == 0) {
auto nativeBool = curEnv->CallBooleanMethodA(object, method, argValues);
nativeInvokeResult = (void *) nativeBool;
}
else if(strcmp(signaturesType[argumentsCount - 1], "V") == 0) {}
else if(strcmp(returnType, "V") == 0) {
curEnv->CallVoidMethodA(object, method, argValues);
}

free(argValues);
free(signaturesType);
free(signature);
if (bShouldDetach) {
gJvm->DetachCurrentThread();
}
Expand Down
@@ -0,0 +1,11 @@
package com.dartnative.dart_native_example;

/**
* Created by huizzzhou on 2020/6/4.
*/
public class Entity {

public int getCurrentTime() {
return (int) System.currentTimeMillis();
}
}
@@ -1,6 +1,5 @@
package com.dartnative.dart_native_example;

import androidx.annotation.NonNull;
import io.flutter.Log;

public class RuntimeStub {
Expand Down Expand Up @@ -55,4 +54,21 @@ public int add(int a, int b) {
Log.d(TAG, "add :" + a + " + " + b);
return a + b;
}

public void log(String tag, String message) {
Log.d(tag, message);
}

public boolean complexCall(String s, int i, char c, double d, float f, byte b, short sh, long l, boolean bool) {
Log.d(TAG, "tag :" + s + " + " + i + " + " + c + " + " + d + " + " + f + " + " + b + " + " + sh + " + " + l + " + " + bool);
return true;
}

public Entity createEntity() {
return new Entity();
}

public int getTime(Entity entity) {
return entity.getCurrentTime();
}
}
Binary file not shown.
Binary file not shown.
Binary file modified dart_native/example/android/jniLibs/x86/libdart_native.so
Binary file not shown.
Binary file modified dart_native/example/android/jniLibs/x86_64/libdart_native.so
Binary file not shown.
2 changes: 1 addition & 1 deletion dart_native/example/ios/Podfile.lock
Expand Up @@ -28,4 +28,4 @@ SPEC CHECKSUMS:

PODFILE CHECKSUM: 9a73c7a50a979210dd9e86ea91a651e23f545314

COCOAPODS: 1.9.1
COCOAPODS: 1.9.3

0 comments on commit 2f55658

Please sign in to comment.