javaStr top-level property
String
javaStr
getter/setter pair
Implementation
String javaStr = '''
package tool;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
import java.lang.reflect.Type;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.MethodChannel;
/**
* custom doc should replace<br>
* ChannelManager manager all changer interfaces.<br>
* add interface impl, use {@link #addChannelImpl(Class, Object)}},<br>
* get interface impl, use {@link #getChannel(Class)}.<br>
* more info, see {@link 'https://pub.dev/packages/spi_flutter_package'}
*/
public class ChannelManager {
private interface ErrorCode {
String NoFoundChannel = "400";//can't found channel
String NoFoundMethod = "401";//can't found method
String CanNotMatchArgs = "402"; //can not match method's args
}
public interface Result<T> {
/**
* Handles a successful result.
*
* @param result The result, possibly null. The result must be an Object type supported by the
* codec. For instance, if you are using StandardMessageCodec (default), please see
* its documentation on what types are supported.
*/
@UiThread
void success(@Nullable T result);
/**
* Handles an error result.
*
* @param errorCode An error code String.
* @param errorMessage A human-readable error message String, possibly null.
* @param errorDetails Error details, possibly null. The details must be an Object type
* supported by the codec. For instance, if you are using StandardMessageCodec
* (default), please see its documentation on what types are supported.
*/
@UiThread
void error(String errorCode, @Nullable String errorMessage, @Nullable Object errorDetails);
/**
* Handles a call to an unimplemented method.
*/
@UiThread
void notImplemented();
}
/**
* json parse
*/
public interface JsonParse {
/**
* passe object to json
* @param object object
* @return json str
*/
@Nullable
public String toJSONString(@Nullable Object object);
/**
* parse json str to obj
* @param text json
* @param clazz obj class
* @param <T> class type
* @return obj
*/
@Nullable
public <T> T parseObject(@Nullable String text, @NonNull Class<T> clazz);
}
private static final String channelName = "123456";
private static final Map<String, Object> channelImplMap = new ConcurrentHashMap<>();
private static MethodChannel methodChannel;
private static final Handler handler = new Handler(Looper.getMainLooper());
private static JsonParse jsonParse;//json parse
public static void init(@NonNull final BinaryMessenger messenger, @NonNull JsonParse jsonParse) {
ChannelManager.jsonParse = jsonParse;
MethodChannel methodChannel = new MethodChannel(messenger, channelName);
ChannelManager.methodChannel = methodChannel;
methodChannel.setMethodCallHandler((call, result) -> {
String callClass = call.method.split("#")[0];
String callMethod = call.method.split("#")[1];
Object targetChanel = channelImplMap.get(callClass);
if (targetChanel != null) {
Method[] methods = targetChanel.getClass().getDeclaredMethods();
Method method = null;
for (Method item : methods) {
if (item.getName().equals(callMethod)) {
method = item;
break;
}
}
if (method == null) {
result.error(ErrorCode.NoFoundMethod, "can't found method: " + callMethod, null);
return;
}
boolean should = true;
List<Object> argList = call.arguments();
if (argList == null) {
argList = new ArrayList<>();
}
Class<?>[] types = method.getParameterTypes();
if (types.length > 0) {
if (types[types.length - 1] == Result.class) {
should = false;
argList.add(new Result() {
@Override
public void success(@Nullable Object value) {
final Object newValue = customClassToString(value);
handler.post(() -> result.success(newValue));
}
@Override
public void error(String errorCode, @Nullable String errorMessage, @Nullable Object errorDetails) {
handler.post(() -> result.error(errorCode, errorMessage, errorDetails));
}
@Override
public void notImplemented() {
handler.post(result::notImplemented);
}
});
}
}
Object[] args = argList.toArray();
//cover integer to long
for (int i = 0; i < args.length; i++) {
if (args[i] == null) {
continue;
}
Object parseCustom = stringToCustomClass(args[i], ".flutter2native.");
args[i] = parseCustom;
args[i] = intToLong(args[i]);
}
try {
Object invokeResult = method.invoke(targetChanel, args);
if (should) {
result.success(invokeResult);
}
} catch (InvocationTargetException e) {
result.error("Invoke Error", e.getMessage(), Log.getStackTraceString(e.getTargetException()));
} catch (IllegalAccessException | IllegalArgumentException e) {
result.error(ErrorCode.CanNotMatchArgs, targetChanel.getClass().getSimpleName()
+ " invoke method: " + callMethod
+ " argument:" + Arrays.toString(method.getParameterTypes())
+ " receiver args: " + Arrays.toString(args), Log.getStackTraceString(e));
} catch (Exception e) {
result.error("Invoke Error", e.getMessage(), Log.getStackTraceString(e));
}
} else {
result.error(ErrorCode.NoFoundChannel, "can't found channel: " + callClass
+ ", do you call ChannelManager.addChannelImpl() in Android Platform ?", null);
}
});
}
public static <T> void addChannelImpl(Class<T> clsName, T object) {
channelImplMap.put(clsName.getName(), object);
}
public static <T> T getChannel(Class<T> clsName) {
return (T) channelImplMap.get(clsName.getName());
}
public static <T> void invoke(Class<?> clsName, String method, List args, @Nullable Result<T> callback) {
ArrayList newList = new ArrayList();
for (Object item : args) {
newList.add(customClassToString(item));
}
methodChannel.invokeMethod(clsName + "#" + method, newList, new MethodChannel.Result() {
@Override
public void success(@Nullable Object result) {
if (callback != null) {
//noinspection unchecked
T parse = (T) stringToCustomClass(result, ".native2flutter.");
if (parse != null) {
callback.success(parse);
} else {
//noinspection unchecked
callback.success((T) result);
}
}
}
@Override
public void error(String errorCode, @Nullable String errorMessage, @Nullable Object errorDetails) {
if (callback != null) {
callback.error(errorCode, errorMessage, errorDetails);
}
}
@Override
public void notImplemented() {
if (callback != null) {
callback.notImplemented();
}
}
});
}
@SuppressWarnings({"UnnecessaryLocalVariable", "rawtypes", "unchecked"})
private static Object intToLong(Object object) {
if (object instanceof Integer) {
Long newValue = (Long) ((Integer) object).longValue();
return newValue;
} else if (object instanceof ArrayList) {
ArrayList tmpArg = (ArrayList) object;
if (tmpArg.isEmpty()) {
return object;
}
ArrayList newList = new ArrayList();
for (Object item : tmpArg) {
newList.add(intToLong(item));
}
return newList;
} else if (object instanceof HashMap) {
HashMap tmpArg = (HashMap) object;
if (tmpArg.isEmpty()) {
return object;
}
HashMap newMap = new HashMap();
for (Object item : tmpArg.keySet()) {
Object key = intToLong(item);
Object value = intToLong(tmpArg.get(item));
newMap.put(key, value);
}
return newMap;
} else {
return object;
}
}
@SuppressWarnings({"rawtypes", "unchecked", "UnnecessaryLocalVariable"})
private static Object customClassToString(Object data) {
if (data != null && data.getClass().getName().startsWith(ChannelManager.class.getPackage().getName())) {
String customInfo = data.getClass().getSimpleName() + "___custom___" + jsonParse.toJSONString(data);
return customInfo;
} else if (data instanceof ArrayList) {
ArrayList newList = new ArrayList();
for (Object item : (ArrayList) data) {
newList.add(customClassToString(item));
}
return newList;
} else if (data instanceof HashMap) {
HashMap newMap = new HashMap();
for (Object item : ((HashMap) data).keySet()) {
Object key = customClassToString(item);
Object value = customClassToString(((HashMap) data).get(item));
newMap.put(key, value);
}
return newMap;
}
return data;
}
@SuppressWarnings({"rawtypes", "unchecked"})
private static Object stringToCustomClass(Object data, String pre) {
try {
if (data instanceof String && ((String) data).contains("___custom___")) {
String[] customInfo = ((String) data).split("___custom___");
Class cls = Class.forName(ChannelManager.class.getPackage().getName() + pre + customInfo[0]);
//noinspection unchecked
return jsonParse.parseObject(customInfo[1], cls);
} else if (data instanceof ArrayList) {
ArrayList newList = new ArrayList();
for (Object item : (ArrayList) data) {
newList.add(stringToCustomClass(item, pre));
}
return newList;
} else if (data instanceof HashMap) {
HashMap newMap = new HashMap();
for (Object item : ((HashMap) data).keySet()) {
Object key = stringToCustomClass(item, pre);
Object value = stringToCustomClass(((HashMap) data).get(item), pre);
newMap.put(key, value);
}
return newMap;
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return data;
}
static {
//generated add native2flutter impl in this
}
}
''';