Skip to content

Commit 33c1a25

Browse files
committed
Merge branch 'release/0.3.16'
2 parents b410edf + edf03df commit 33c1a25

File tree

9 files changed

+136
-89
lines changed

9 files changed

+136
-89
lines changed

dart_native/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 0.3.16
2+
3+
* [Fix] JNI environment issue on Android.
4+
15
## 0.3.15
26

37
* [Fix] Performance issue on iOS.

dart_native/android/src/main/jni/dart_native.cpp

Lines changed: 67 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ extern "C" {
1616
static JavaVM *gJvm = nullptr;
1717
static jobject gClassLoader;
1818
static jmethodID gFindClassMethod;
19-
static JNIEnv *gCurEnv = nullptr;
2019
static pthread_key_t detachKey = 0;
2120

2221
typedef void (*NativeMethodCallback)(
@@ -36,45 +35,48 @@ static std::map<void *, jobject> callbackObjCache;
3635
static std::map<jlong, std::map<std::string, NativeMethodCallback>> callbackManagerCache;
3736
static std::map<jlong, void *> targetCache;
3837

39-
JNIEnv *getEnv() {
40-
JNIEnv *env;
41-
int status = gJvm->GetEnv((void **) &env, JNI_VERSION_1_6);
42-
if (status < 0) {
43-
status = gJvm->AttachCurrentThread(&env, NULL);
44-
if (status < 0) {
45-
return nullptr;
46-
}
47-
}
48-
return env;
49-
}
5038

5139
void detachThreadDestructor(void* arg) {
5240
NSLog("detach from current thread");
5341
gJvm->DetachCurrentThread();
5442
detachKey = 0;
5543
}
5644

57-
void attachThread() {
45+
JNIEnv *getEnv() {
46+
if (gJvm == nullptr) {
47+
return nullptr;
48+
}
49+
5850
if (detachKey == 0) {
59-
NSLog("attach to current thread");
6051
pthread_key_create(&detachKey, detachThreadDestructor);
61-
gJvm->AttachCurrentThread(&gCurEnv, NULL);
62-
pthread_setspecific(detachKey, nullptr);
52+
}
53+
JNIEnv *env;
54+
jint ret = gJvm->GetEnv((void **) &env, JNI_VERSION_1_6);
55+
56+
switch (ret) {
57+
case JNI_OK:
58+
return env;
59+
case JNI_EDETACHED:
60+
NSLog("attach to current thread");
61+
gJvm->AttachCurrentThread(&env, NULL);
62+
return env;
63+
default:
64+
NSLog("fail to get env");
65+
return nullptr;
6366
}
6467
}
6568

6669
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *pjvm, void *reserved) {
6770
NSLog("JNI_OnLoad");
6871
gJvm = pjvm; // cache the JavaVM pointer
69-
gCurEnv = getEnv();
7072
//replace with one of your classes in the line below
71-
auto randomClass = gCurEnv->FindClass("com/dartnative/dart_native/DartNativePlugin");
72-
jclass classClass = gCurEnv->GetObjectClass(randomClass);
73-
auto classLoaderClass = gCurEnv->FindClass("java/lang/ClassLoader");
74-
auto getClassLoaderMethod = gCurEnv->GetMethodID(classClass, "getClassLoader",
73+
auto randomClass = getEnv()->FindClass("com/dartnative/dart_native/DartNativePlugin");
74+
jclass classClass = getEnv()->GetObjectClass(randomClass);
75+
auto classLoaderClass = getEnv()->FindClass("java/lang/ClassLoader");
76+
auto getClassLoaderMethod = getEnv()->GetMethodID(classClass, "getClassLoader",
7577
"()Ljava/lang/ClassLoader;");
76-
gClassLoader = gCurEnv->NewGlobalRef(gCurEnv->CallObjectMethod(randomClass, getClassLoaderMethod));
77-
gFindClassMethod = gCurEnv->GetMethodID(classLoaderClass, "findClass",
78+
gClassLoader = getEnv()->NewGlobalRef(getEnv()->CallObjectMethod(randomClass, getClassLoaderMethod));
79+
gFindClassMethod = getEnv()->GetMethodID(classLoaderClass, "findClass",
7880
"(Ljava/lang/String;)Ljava/lang/Class;");
7981

8082
NSLog("JNI_OnLoad finish");
@@ -88,12 +90,11 @@ char *spliceChar(char *dest, char *src) {
8890
return result;
8991
}
9092

91-
char *generateSignature(char **argTypes) {
93+
char *generateSignature(char **argTypes, int argCount) {
9294
char *signature = const_cast<char *>("(");
93-
int argCount = 0;
9495
if (argTypes != nullptr)
9596
{
96-
for (; *argTypes; ++argTypes, ++argCount) {
97+
for (int i = 0; i < argCount; ++argTypes, i++) {
9798
char *templeSignature = spliceChar(signature, *argTypes);
9899
signature = templeSignature;
99100
free(templeSignature);
@@ -102,12 +103,12 @@ char *generateSignature(char **argTypes) {
102103
return spliceChar(signature, const_cast<char *>(")"));
103104
}
104105

105-
void fillArgs(void **args, char **argTypes, jvalue *argValues) {
106-
for(jsize index(0); *argTypes ; ++args, ++index, ++argTypes) {
106+
void fillArgs(void **args, char **argTypes, jvalue *argValues, int argCount) {
107+
for(jsize index(0); index < argCount ; ++args, ++index, ++argTypes) {
107108
char *argType = *argTypes;
108109
if (strlen(argType) > 1) {
109110
if (strcmp(argType, "Ljava/lang/String;") == 0) {
110-
argValues[index].l = gCurEnv->NewStringUTF((char *)*args);
111+
argValues[index].l = getEnv()->NewStringUTF((char *)*args);
111112
}
112113
else {
113114
jobject object = callbackObjCache.count(*args) ? callbackObjCache[*args] : static_cast<jobject>(*args);
@@ -156,38 +157,34 @@ jclass findClass(JNIEnv *env, const char *name) {
156157
return nativeClass;
157158
}
158159

159-
jobject newObject(jclass cls, void **args, char **argTypes) {
160-
char *signature = generateSignature(argTypes);
161-
jvalue *argValues = new jvalue[strlen(signature) - 2];
162-
if (strlen(signature) - 2 > 0) {
163-
fillArgs(args, argTypes, argValues);
160+
jobject newObject(jclass cls, void **args, char **argTypes, int argCount) {
161+
char *signature = generateSignature(argTypes, argCount);
162+
jvalue *argValues = new jvalue[argCount];
163+
if (argCount > 0) {
164+
fillArgs(args, argTypes, argValues, argCount);
164165
}
165166
char *constructorSig = spliceChar(signature, const_cast<char *>("V"));
166-
jmethodID constructor = gCurEnv->GetMethodID(cls, "<init>", constructorSig);
167-
jobject newObj = gCurEnv->NewObjectA(cls, constructor, argValues);
167+
jmethodID constructor = getEnv()->GetMethodID(cls, "<init>", constructorSig);
168+
jobject newObj = getEnv()->NewObjectA(cls, constructor, argValues);
168169
free(argValues);
169170
free(constructorSig);
170171
return newObj;
171172
}
172173

173-
void *createTargetClass(char *targetClassName, void **args, char **argTypes) {
174-
attachThread();
175-
176-
jclass cls = findClass(gCurEnv, targetClassName);
174+
void *createTargetClass(char *targetClassName, void **args, char **argTypes, int argCount) {
175+
jclass cls = findClass(getEnv(), targetClassName);
177176

178-
jobject newObj = gCurEnv->NewGlobalRef(newObject(cls, args, argTypes));
179-
cache[newObj] = static_cast<jclass>(gCurEnv->NewGlobalRef(cls));
177+
jobject newObj = getEnv()->NewGlobalRef(newObject(cls, args, argTypes, argCount));
178+
cache[newObj] = static_cast<jclass>(getEnv()->NewGlobalRef(cls));
180179

181180
return newObj;
182181
}
183182

184183

185184
void releaseTargetClass(void *classPtr) {
186-
attachThread();
187-
188185
jobject object = static_cast<jobject>(classPtr);
189186
cache.erase(object);
190-
gCurEnv->DeleteGlobalRef(object);
187+
getEnv()->DeleteGlobalRef(object);
191188
}
192189

193190
void retain(void *classPtr) {
@@ -211,71 +208,69 @@ void release(void *classPtr) {
211208
referenceCount[object] = count - 1;
212209
}
213210

214-
void *invokeNativeMethodNeo(void *classPtr, char *methodName, void **args, char **argTypes, char *returnType) {
211+
void *invokeNativeMethodNeo(void *classPtr, char *methodName, void **args, char **argTypes, int argCount, char *returnType) {
215212
void *nativeInvokeResult = nullptr;
216213

217-
attachThread();
218214
jobject object = static_cast<jobject>(classPtr);
219215
jclass cls = cache[object];
220-
char *signature = generateSignature(argTypes);
221-
jvalue *argValues = new jvalue[strlen(signature) - 2];
222-
if ((strlen(signature) - 2) > 0) {
223-
fillArgs(args, argTypes, argValues);
216+
char *signature = generateSignature(argTypes, argCount);
217+
jvalue *argValues = new jvalue[argCount];
218+
if (argCount > 0) {
219+
fillArgs(args, argTypes, argValues, argCount);
224220
}
225221
char *methodSignature = spliceChar(signature, returnType);
226-
jmethodID method = gCurEnv->GetMethodID(cls, methodName, methodSignature);
227-
NSLog("call method: %s descriptor: %s", methodName, methodSignature);
222+
jmethodID method = getEnv()->GetMethodID(cls, methodName, methodSignature);
228223

229224
if (strlen(returnType) > 1) {
230225
if (strcmp(returnType, "Ljava/lang/String;") == 0) {
231-
jstring javaString = (jstring)gCurEnv->CallObjectMethodA(object, method, argValues);
226+
jstring javaString = (jstring) getEnv()->CallObjectMethodA(object, method, argValues);
232227
jboolean isCopy = JNI_FALSE;
233-
nativeInvokeResult = (char *) gCurEnv->GetStringUTFChars(javaString, &isCopy);
228+
nativeInvokeResult = (char *) getEnv()->GetStringUTFChars(javaString, &isCopy);
234229
}
235230
else {
236-
jobject obj = gCurEnv->NewGlobalRef(gCurEnv->CallObjectMethodA(object, method, argValues));
237-
jclass objCls = gCurEnv->GetObjectClass(obj);
231+
jobject obj = getEnv()->NewGlobalRef(getEnv()->CallObjectMethodA(object, method, argValues));
232+
jclass objCls = getEnv()->GetObjectClass(obj);
238233
//store class value
239-
cache[obj] = static_cast<jclass>(gCurEnv->NewGlobalRef(objCls));
234+
cache[obj] = static_cast<jclass>(getEnv()->NewGlobalRef(objCls));
240235
nativeInvokeResult = obj;
241236
}
242237
}
243238
else if (strcmp(returnType, "C") == 0) {
244-
auto nativeChar = gCurEnv->CallCharMethodA(object, method, argValues);
239+
auto nativeChar = getEnv()->CallCharMethodA(object, method, argValues);
245240
nativeInvokeResult = (void *) nativeChar;
246241
}
247242
else if(strcmp(returnType, "I") == 0) {
248-
auto nativeInt = gCurEnv->CallIntMethodA(object, method, argValues);
243+
auto nativeInt = getEnv()->CallIntMethodA(object, method, argValues);
249244
nativeInvokeResult = (void *) nativeInt;
250245
}
251246
else if(strcmp(returnType, "D") == 0) {
252-
auto nativeDouble = gCurEnv->CallDoubleMethodA(object, method, argValues);
247+
auto nativeDouble = getEnv()->CallDoubleMethodA(object, method, argValues);
253248
double cDouble = (double) nativeDouble;
254249
memcpy(&nativeInvokeResult, &cDouble, sizeof(double));
255250
}
256251
else if(strcmp(returnType, "F") == 0) {
257-
auto nativeDouble = gCurEnv->CallFloatMethodA(object, method, argValues);
252+
auto nativeDouble = getEnv()->CallFloatMethodA(object, method, argValues);
258253
float cDouble = (float) nativeDouble;
259254
memcpy(&nativeInvokeResult, &cDouble, sizeof(float));
260255
}
261256
else if(strcmp(returnType, "B") == 0) {
262-
auto nativeByte = gCurEnv->CallByteMethodA(object, method, argValues);
257+
auto nativeByte = getEnv()->CallByteMethodA(object, method, argValues);
263258
nativeInvokeResult = (void *) nativeByte;
264259
}
265260
else if(strcmp(returnType, "S") == 0) {
266-
auto nativeShort = gCurEnv->CallShortMethodA(object, method, argValues);
261+
auto nativeShort = getEnv()->CallShortMethodA(object, method, argValues);
267262
nativeInvokeResult = (void *) nativeShort;
268263
}
269264
else if(strcmp(returnType, "J") == 0) {
270-
auto nativeLong = gCurEnv->CallLongMethodA(object, method, argValues);
265+
auto nativeLong = getEnv()->CallLongMethodA(object, method, argValues);
271266
nativeInvokeResult = (void *) nativeLong;
272267
}
273268
else if(strcmp(returnType, "Z") == 0) {
274-
auto nativeBool = gCurEnv->CallBooleanMethodA(object, method, argValues);
269+
auto nativeBool = getEnv()->CallBooleanMethodA(object, method, argValues);
275270
nativeInvokeResult = (void *) nativeBool;
276271
}
277272
else if(strcmp(returnType, "V") == 0) {
278-
gCurEnv->CallVoidMethodA(object, method, argValues);
273+
getEnv()->CallVoidMethodA(object, method, argValues);
279274
}
280275

281276
free(argValues);
@@ -307,20 +302,18 @@ NativeMethodCallback getCallbackMethod(jlong targetAddr, char *functionName) {
307302
}
308303

309304
void registerNativeCallback(void *target, char* targetName, char *funName, void *callback) {
310-
attachThread();
311-
312-
jclass callbackManager = findClass(gCurEnv, "com/dartnative/dart_native/CallbackManager");
313-
jmethodID registerCallback = gCurEnv->GetStaticMethodID(callbackManager, "registerCallback", "(JLjava/lang/String;)Ljava/lang/Object;");
305+
jclass callbackManager = findClass(getEnv(), "com/dartnative/dart_native/CallbackManager");
306+
jmethodID registerCallback = getEnv()->GetStaticMethodID(callbackManager, "registerCallback", "(JLjava/lang/String;)Ljava/lang/Object;");
314307
jlong targetAddr = (jlong)target;
315308
jvalue *argValues = new jvalue[2];
316309
argValues[0].j = targetAddr;
317-
argValues[1].l = gCurEnv->NewStringUTF(targetName);
318-
jobject callbackOJ = gCurEnv->NewGlobalRef(gCurEnv->CallStaticObjectMethodA(callbackManager, registerCallback, argValues));
310+
argValues[1].l = getEnv()->NewStringUTF(targetName);
311+
jobject callbackOJ = getEnv()->NewGlobalRef(getEnv()->CallStaticObjectMethodA(callbackManager, registerCallback, argValues));
319312
callbackObjCache[target] = callbackOJ;
320313
targetCache[targetAddr] = target;
321314

322315
registerCallbackManager(targetAddr, funName, callback);
323-
gCurEnv->DeleteLocalRef(callbackManager);
316+
getEnv()->DeleteLocalRef(callbackManager);
324317
free(argValues);
325318
}
326319

dart_native/example/android/app/src/main/java/com/dartnative/dart_native_example/MainActivity.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,15 @@
66
import io.flutter.Log;
77
import io.flutter.embedding.android.FlutterActivity;
88
import io.flutter.embedding.engine.FlutterEngine;
9+
import io.flutter.plugin.common.MethodCall;
10+
import io.flutter.plugin.common.MethodChannel;
11+
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
12+
import io.flutter.plugin.common.MethodChannel.Result;
913
import io.flutter.plugins.GeneratedPluginRegistrant;
1014

1115
public class MainActivity extends FlutterActivity {
1216
public static final String TAG = "dart_java";
17+
private final String CHANNEL_NAME = "dart_native.example";
1318

1419
static {
1520
DartNativePlugin.setSoPath("");
@@ -18,6 +23,18 @@ public class MainActivity extends FlutterActivity {
1823
@Override
1924
public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
2025
GeneratedPluginRegistrant.registerWith(flutterEngine);
26+
new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), CHANNEL_NAME).setMethodCallHandler(new MethodCallHandler() {
27+
@Override
28+
public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
29+
if ("channelInt".equals(call.method)) {
30+
result.success(100);
31+
} else if ("channelString".equals(call.method)) {
32+
result.success("test success");
33+
} else {
34+
result.notImplemented();
35+
}
36+
}
37+
});
2138
}
2239

2340
public int getInt(int i){

dart_native/example/android/app/src/main/java/com/dartnative/dart_native_example/RuntimeStub.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ public class RuntimeStub {
1313
private final String TAG = "dart_java";
1414

1515
public int getInt(int i){
16-
Log.d(TAG, "getInt : " + i);
1716
return 100;
1817
}
1918

@@ -53,7 +52,6 @@ public boolean getBool(boolean b) {
5352
}
5453

5554
public String getString(String s) {
56-
Log.d(TAG, "getString : " + s);
5755
return "test success";
5856
}
5957

dart_native/example/lib/android/android_new_main.dart

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,16 @@ import 'package:dart_native_example/android/unit_test.dart';
33
import 'package:flutter/material.dart';
44
import 'dart:async';
55

6+
import 'package:flutter/services.dart';
7+
68
class AndroidNewApp extends StatefulWidget {
79
@override
810
_AndroidNewApp createState() => _AndroidNewApp();
911
}
1012

1113
class _AndroidNewApp extends State<AndroidNewApp> {
1214
RuntimeStub stub = RuntimeStub();
15+
static const platform = const MethodChannel('dart_native.example');
1316

1417
@override
1518
void initState() {
@@ -19,7 +22,32 @@ class _AndroidNewApp extends State<AndroidNewApp> {
1922

2023
// Platform messages are asynchronous, so we initialize in an async method.
2124
Future<void> initPlatformState() async {
22-
// testAndroid(stub);
25+
// Benchmark
26+
String testString =
27+
'This is a long string: sdlfdksjflksndhiofuu2893873(*(%¥#@)*&……¥撒肥料开发时傅雷家书那份会计师东方丽景三等奖';
28+
int time = DateTime.now().millisecondsSinceEpoch;
29+
for (var i = 0; i < 10000; i++) {
30+
String _ = await platform.invokeMethod('channelString', testString);
31+
}
32+
print(
33+
"Flutter Channel String Cost: ${DateTime.now().millisecondsSinceEpoch - time}");
34+
time = DateTime.now().millisecondsSinceEpoch;
35+
for (var i = 0; i < 10000; i++) {
36+
String _ = stub.getString(testString);
37+
}
38+
print("DartNative String Cost: ${DateTime.now().millisecondsSinceEpoch - time}");
39+
40+
time = DateTime.now().millisecondsSinceEpoch;
41+
for (var i = 0; i < 10000; i++) {
42+
int _ = await platform.invokeMethod('channelInt', testString);
43+
}
44+
print(
45+
"Flutter Channel int Cost: ${DateTime.now().millisecondsSinceEpoch - time}");
46+
time = DateTime.now().millisecondsSinceEpoch;
47+
for (var i = 0; i < 10000; i++) {
48+
int _ = stub.getInt(100);
49+
}
50+
print("DartNative int Cost: ${DateTime.now().millisecondsSinceEpoch - time}");
2351
}
2452

2553
@override

dart_native/example/pubspec.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ packages:
168168
path: ".."
169169
relative: true
170170
source: path
171-
version: "0.3.15"
171+
version: "0.3.16"
172172
dart_native_gen:
173173
dependency: transitive
174174
description:

0 commit comments

Comments
 (0)