提交 c4edec74 编写于 作者: M Mikkel Nygaard Ravn 提交者: GitHub

Remove old flutter messaging API (#3482)

Breaking change: removed facilities for JSON and string messaging from FlutterView/FlutterViewController, leaving only binary messaging there. All other use of flutter communication now goes through FlutterMessageChannel and FlutterMethodChannels. Retained use of String and JSON codecs for now.

Companion flutter PR: flutter/flutter#8837
上级 4a5a3246
...@@ -82,18 +82,18 @@ android_library("java") { ...@@ -82,18 +82,18 @@ android_library("java") {
"io/flutter/app/FlutterActivity.java", "io/flutter/app/FlutterActivity.java",
"io/flutter/app/FlutterApplication.java", "io/flutter/app/FlutterApplication.java",
"io/flutter/plugin/common/ActivityLifecycleListener.java", "io/flutter/plugin/common/ActivityLifecycleListener.java",
"io/flutter/plugin/common/BinaryMessageCodec.java", "io/flutter/plugin/common/BinaryCodec.java",
"io/flutter/plugin/common/FlutterException.java",
"io/flutter/plugin/common/FlutterMessageChannel.java", "io/flutter/plugin/common/FlutterMessageChannel.java",
"io/flutter/plugin/common/FlutterMethodChannel.java", "io/flutter/plugin/common/FlutterMethodChannel.java",
"io/flutter/plugin/common/JSONMessageCodec.java", "io/flutter/plugin/common/JSONMessageCodec.java",
"io/flutter/plugin/common/JSONMessageListener.java",
"io/flutter/plugin/common/JSONMethodCodec.java", "io/flutter/plugin/common/JSONMethodCodec.java",
"io/flutter/plugin/common/MessageCodec.java", "io/flutter/plugin/common/MessageCodec.java",
"io/flutter/plugin/common/MethodCodec.java", "io/flutter/plugin/common/MethodCodec.java",
"io/flutter/plugin/common/MethodCall.java", "io/flutter/plugin/common/MethodCall.java",
"io/flutter/plugin/common/StandardMessageCodec.java", "io/flutter/plugin/common/StandardMessageCodec.java",
"io/flutter/plugin/common/StandardMethodCodec.java", "io/flutter/plugin/common/StandardMethodCodec.java",
"io/flutter/plugin/common/StringMessageCodec.java", "io/flutter/plugin/common/StringCodec.java",
"io/flutter/plugin/editing/InputConnectionAdaptor.java", "io/flutter/plugin/editing/InputConnectionAdaptor.java",
"io/flutter/plugin/editing/TextInputPlugin.java", "io/flutter/plugin/editing/TextInputPlugin.java",
"io/flutter/plugin/platform/PlatformPlugin.java", "io/flutter/plugin/platform/PlatformPlugin.java",
......
...@@ -9,11 +9,11 @@ import java.nio.ByteBuffer; ...@@ -9,11 +9,11 @@ import java.nio.ByteBuffer;
/** /**
* A {@link MessageCodec} using unencoded binary messages, represented as {@link ByteBuffer}s. * A {@link MessageCodec} using unencoded binary messages, represented as {@link ByteBuffer}s.
*/ */
public final class BinaryMessageCodec implements MessageCodec<ByteBuffer> { public final class BinaryCodec implements MessageCodec<ByteBuffer> {
// This codec must match the Dart codec of the same name in package flutter/services. // This codec must match the Dart codec of the same name in package flutter/services.
public static final BinaryMessageCodec INSTANCE = new BinaryMessageCodec(); public static final BinaryCodec INSTANCE = new BinaryCodec();
private BinaryMessageCodec() { private BinaryCodec() {
} }
@Override @Override
......
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package io.flutter.plugin.common;
/**
* Thrown to indicate that a Flutter method invocation failed on the Flutter side.
*/
public class FlutterException extends RuntimeException {
public final String code;
public final Object details;
FlutterException(String code, String message, Object details) {
super(message);
assert code != null;
this.code = code;
this.details = details;
}
}
...@@ -6,6 +6,7 @@ package io.flutter.plugin.common; ...@@ -6,6 +6,7 @@ package io.flutter.plugin.common;
import android.util.Log; import android.util.Log;
import io.flutter.view.FlutterView; import io.flutter.view.FlutterView;
import io.flutter.view.FlutterView.BinaryMessageReplyCallback;
import io.flutter.view.FlutterView.BinaryMessageResponse; import io.flutter.view.FlutterView.BinaryMessageResponse;
import io.flutter.view.FlutterView.OnBinaryMessageListenerAsync; import io.flutter.view.FlutterView.OnBinaryMessageListenerAsync;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
...@@ -60,6 +61,27 @@ public final class FlutterMethodChannel { ...@@ -60,6 +61,27 @@ public final class FlutterMethodChannel {
this.codec = codec; this.codec = codec;
} }
/**
* Invokes a method on this channel, expecting no result.
*
* @param method the name String of the method.
* @param arguments the arguments for the invocation, possibly null.
*/
public void invokeMethod(String method, Object arguments) {
invokeMethod(method, arguments, null);
}
/**
* Invokes a method on this channel.
*
* @param call a {@link MethodCall}.
* @param handler a {@link Response} handler for the invocation result.
*/
public void invokeMethod(String method, Object arguments, Response handler) {
view.sendBinaryMessage(name, codec.encodeMethodCall(new MethodCall(method, arguments)),
handler == null ? null : new MethodCallResultCallback(handler));
}
/** /**
* Registers a method call handler on this channel. * Registers a method call handler on this channel.
* *
...@@ -106,7 +128,8 @@ public final class FlutterMethodChannel { ...@@ -106,7 +128,8 @@ public final class FlutterMethodChannel {
* Handles a stream setup request. * Handles a stream setup request.
* *
* @param arguments Stream configuration arguments, possibly null. * @param arguments Stream configuration arguments, possibly null.
* @param eventSink A {@link EventSink} used to emit events once the stream has been set up. * @param eventSink An {@link EventSink} used to emit events once the stream has been set
* up.
*/ */
void listen(Object arguments, EventSink eventSink); void listen(Object arguments, EventSink eventSink);
...@@ -150,6 +173,24 @@ public final class FlutterMethodChannel { ...@@ -150,6 +173,24 @@ public final class FlutterMethodChannel {
void done(); void done();
} }
private final class MethodCallResultCallback implements BinaryMessageReplyCallback {
private final Response handler;
MethodCallResultCallback(Response handler) {
this.handler = handler;
}
@Override
public void onReply(ByteBuffer reply) {
try {
final Object result = codec.decodeEnvelope(reply);
handler.success(result);
} catch (FlutterException e) {
handler.error(e.code, e.getMessage(), e.details);
}
}
}
private final class MethodCallListener implements OnBinaryMessageListenerAsync { private final class MethodCallListener implements OnBinaryMessageListenerAsync {
private final MethodCallHandler handler; private final MethodCallHandler handler;
...@@ -188,7 +229,7 @@ public final class FlutterMethodChannel { ...@@ -188,7 +229,7 @@ public final class FlutterMethodChannel {
}); });
} catch (Exception e) { } catch (Exception e) {
Log.e(TAG + name, "Failed to handle method call", e); Log.e(TAG + name, "Failed to handle method call", e);
response.send(codec.encodeErrorEnvelope("error", e.getMessage(),null)); response.send(codec.encodeErrorEnvelope("error", e.getMessage(), null));
} }
} }
} }
...@@ -236,13 +277,13 @@ public final class FlutterMethodChannel { ...@@ -236,13 +277,13 @@ public final class FlutterMethodChannel {
if (cancelled.get()) { if (cancelled.get()) {
return; return;
} }
FlutterMethodChannel.this.view.sendToFlutter(name,null); FlutterMethodChannel.this.view.sendBinaryMessage(name, null, null);
} }
}); });
response.send(codec.encodeSuccessEnvelope(null)); response.send(codec.encodeSuccessEnvelope(null));
} catch (Exception e) { } catch (Exception e) {
Log.e(TAG + name, "Failed to open event stream", e); Log.e(TAG + name, "Failed to open event stream", e);
response.send(codec.encodeErrorEnvelope("error", e.getMessage(),null)); response.send(codec.encodeErrorEnvelope("error", e.getMessage(), null));
} }
} else if (call.method.equals("cancel")) { } else if (call.method.equals("cancel")) {
cancelled.set(true); cancelled.set(true);
...@@ -251,7 +292,7 @@ public final class FlutterMethodChannel { ...@@ -251,7 +292,7 @@ public final class FlutterMethodChannel {
response.send(codec.encodeSuccessEnvelope(null)); response.send(codec.encodeSuccessEnvelope(null));
} catch (Exception e) { } catch (Exception e) {
Log.e(TAG + name, "Failed to close event stream", e); Log.e(TAG + name, "Failed to close event stream", e);
response.send(codec.encodeErrorEnvelope("error", e.getMessage(),null)); response.send(codec.encodeErrorEnvelope("error", e.getMessage(), null));
} }
} }
} }
......
...@@ -26,7 +26,7 @@ public final class JSONMessageCodec implements MessageCodec<Object> { ...@@ -26,7 +26,7 @@ public final class JSONMessageCodec implements MessageCodec<Object> {
if (message == null) { if (message == null) {
return null; return null;
} }
return StringMessageCodec.INSTANCE.encodeMessage(JSONObject.wrap(message).toString()); return StringCodec.INSTANCE.encodeMessage(JSONObject.wrap(message).toString());
} }
@Override @Override
...@@ -35,7 +35,7 @@ public final class JSONMessageCodec implements MessageCodec<Object> { ...@@ -35,7 +35,7 @@ public final class JSONMessageCodec implements MessageCodec<Object> {
return null; return null;
} }
try { try {
final String json = StringMessageCodec.INSTANCE.decodeMessage(message); final String json = StringCodec.INSTANCE.decodeMessage(message);
final JSONTokener tokener = new JSONTokener(json); final JSONTokener tokener = new JSONTokener(json);
final Object value = tokener.nextValue(); final Object value = tokener.nextValue();
if (tokener.more()) { if (tokener.more()) {
......
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package io.flutter.plugin.common;
import android.util.Log;
import org.json.JSONException;
import org.json.JSONObject;
import io.flutter.view.FlutterView;
/** @deprecated Use {@link FlutterMessageChannel} and {@link JSONMessageCodec} instead. */
@Deprecated
public abstract class JSONMessageListener implements FlutterView.OnMessageListener {
static final String TAG = "FlutterView";
@Override
public String onMessage(FlutterView view, String message) {
try {
JSONObject response = onJSONMessage(view, new JSONObject(message));
if (response == null)
return null;
return response.toString();
} catch (JSONException e) {
Log.e(TAG, "JSON exception", e);
return null;
}
}
public abstract JSONObject onJSONMessage(FlutterView view, JSONObject message) throws JSONException;
public static String getStringOrNull(JSONObject object, String name) throws JSONException {
return object.isNull(name) ? null : object.getString(name);
}
}
...@@ -16,14 +16,28 @@ public final class JSONMethodCodec implements MethodCodec { ...@@ -16,14 +16,28 @@ public final class JSONMethodCodec implements MethodCodec {
private JSONMethodCodec() { private JSONMethodCodec() {
} }
@Override
public ByteBuffer encodeMethodCall(MethodCall methodCall) {
try {
final JSONObject map = new JSONObject();
map.put("method", methodCall.method);
map.put("args", JSONObject.wrap(methodCall.arguments));
return JSONMessageCodec.INSTANCE.encodeMessage(map);
} catch (JSONException e) {
throw new IllegalArgumentException("Invalid JSON", e);
}
}
@Override @Override
public MethodCall decodeMethodCall(ByteBuffer message) { public MethodCall decodeMethodCall(ByteBuffer message) {
try { try {
final Object json = JSONMessageCodec.INSTANCE.decodeMessage(message); final Object json = JSONMessageCodec.INSTANCE.decodeMessage(message);
if (json instanceof JSONArray) { if (json instanceof JSONObject) {
final JSONArray pair = (JSONArray) json; final JSONObject map = (JSONObject) json;
if (pair.length() == 2 && pair.get(0) instanceof String) { final Object method = map.get("method");
return new MethodCall(pair.getString(0), pair.get(1)); final Object arguments = map.get("args");
if (method instanceof String) {
return new MethodCall((String) method, arguments);
} }
} }
throw new IllegalArgumentException("Invalid method call: " + json); throw new IllegalArgumentException("Invalid method call: " + json);
...@@ -34,14 +48,40 @@ public final class JSONMethodCodec implements MethodCodec { ...@@ -34,14 +48,40 @@ public final class JSONMethodCodec implements MethodCodec {
@Override @Override
public ByteBuffer encodeSuccessEnvelope(Object result) { public ByteBuffer encodeSuccessEnvelope(Object result) {
return JSONMessageCodec.INSTANCE.encodeMessage(new JSONArray().put(JSONObject.wrap(result))); return JSONMessageCodec.INSTANCE
.encodeMessage(new JSONArray().put(JSONObject.wrap(result)));
} }
@Override @Override
public ByteBuffer encodeErrorEnvelope(String errorCode, String errorMessage, Object errorDetails) { public ByteBuffer encodeErrorEnvelope(String errorCode, String errorMessage,
Object errorDetails) {
return JSONMessageCodec.INSTANCE.encodeMessage(new JSONArray() return JSONMessageCodec.INSTANCE.encodeMessage(new JSONArray()
.put(errorCode) .put(errorCode)
.put(errorMessage) .put(errorMessage)
.put(JSONObject.wrap(errorDetails))); .put(JSONObject.wrap(errorDetails)));
} }
@Override
public Object decodeEnvelope(ByteBuffer envelope) {
try {
final Object json = JSONMessageCodec.INSTANCE.decodeMessage(envelope);
if (json instanceof JSONArray) {
final JSONArray array = (JSONArray) json;
if (array.length() == 1) {
return array.get(0);
}
if (array.length() == 3) {
final Object code = array.get(0);
final Object message = array.get(1);
final Object details = array.get(2);
if (code instanceof String && (message == null || message instanceof String)) {
throw new FlutterException((String) code, (String) message, details);
}
}
}
throw new IllegalArgumentException("Invalid method call: " + json);
} catch (JSONException e) {
throw new IllegalArgumentException("Invalid JSON", e);
}
}
} }
...@@ -4,8 +4,6 @@ ...@@ -4,8 +4,6 @@
package io.flutter.plugin.common; package io.flutter.plugin.common;
import java.util.Objects;
/** /**
* Command object representing a method call on a {@link FlutterMessageChannel}. * Command object representing a method call on a {@link FlutterMessageChannel}.
*/ */
......
...@@ -16,6 +16,15 @@ import java.nio.ByteBuffer; ...@@ -16,6 +16,15 @@ import java.nio.ByteBuffer;
* All operations throw {@link IllegalArgumentException}, if conversion fails. * All operations throw {@link IllegalArgumentException}, if conversion fails.
*/ */
public interface MethodCodec { public interface MethodCodec {
/**
* Encodes a message call into binary.
*
* @param methodCall a {@link MethodCall}.
* @return a {@link ByteBuffer} containing the encoding between position 0 and
* the current position.
*/
ByteBuffer encodeMethodCall(MethodCall methodCall);
/** /**
* Decodes a message call from binary. * Decodes a message call from binary.
* *
...@@ -29,7 +38,7 @@ public interface MethodCodec { ...@@ -29,7 +38,7 @@ public interface MethodCodec {
* Encodes a successful result into a binary envelope message. * Encodes a successful result into a binary envelope message.
* *
* @param result The result value, possibly null. * @param result The result value, possibly null.
* @return a ByteBuffer containing the encoding between position 0 and * @return a {@link ByteBuffer} containing the encoding between position 0 and
* the current position. * the current position.
*/ */
ByteBuffer encodeSuccessEnvelope(Object result); ByteBuffer encodeSuccessEnvelope(Object result);
...@@ -40,8 +49,17 @@ public interface MethodCodec { ...@@ -40,8 +49,17 @@ public interface MethodCodec {
* @param errorCode An error code String. * @param errorCode An error code String.
* @param errorMessage An error message String, possibly null. * @param errorMessage An error message String, possibly null.
* @param errorDetails Error details, possibly null. * @param errorDetails Error details, possibly null.
* @return a ByteBuffer containing the encoding between position 0 and * @return a {@link ByteBuffer} containing the encoding between position 0 and
* the current position. * the current position.
*/ */
ByteBuffer encodeErrorEnvelope(String errorCode, String errorMessage, Object errorDetails); ByteBuffer encodeErrorEnvelope(String errorCode, String errorMessage, Object errorDetails);
/**
* Decodes a result envelope from binary.
*
* @param envelope the binary encoding of a result envelope as a {@link ByteBuffer}.
* @return the enveloped result Object.
* @throws FlutterException if the envelope was an error envelope.
*/
Object decodeEnvelope(ByteBuffer envelope);
} }
...@@ -25,12 +25,22 @@ public final class StandardMethodCodec implements MethodCodec { ...@@ -25,12 +25,22 @@ public final class StandardMethodCodec implements MethodCodec {
private StandardMethodCodec() { private StandardMethodCodec() {
} }
@Override
public ByteBuffer encodeMethodCall(MethodCall methodCall) {
final ExposedByteArrayOutputStream stream = new ExposedByteArrayOutputStream();
StandardMessageCodec.writeValue(stream, methodCall.method);
StandardMessageCodec.writeValue(stream, methodCall.arguments);
final ByteBuffer buffer = ByteBuffer.allocateDirect(stream.size());
buffer.put(stream.buffer(), 0, stream.size());
return buffer;
}
@Override @Override
public MethodCall decodeMethodCall(ByteBuffer methodCall) { public MethodCall decodeMethodCall(ByteBuffer methodCall) {
methodCall.order(ByteOrder.nativeOrder()); methodCall.order(ByteOrder.nativeOrder());
final Object method = StandardMessageCodec.readValue(methodCall); final Object method = StandardMessageCodec.readValue(methodCall);
final Object arguments = StandardMessageCodec.readValue(methodCall); final Object arguments = StandardMessageCodec.readValue(methodCall);
if (method instanceof String) { if (method instanceof String && !methodCall.hasRemaining()) {
return new MethodCall((String) method, arguments); return new MethodCall((String) method, arguments);
} }
throw new IllegalArgumentException("Method call corrupted"); throw new IllegalArgumentException("Method call corrupted");
...@@ -58,4 +68,29 @@ public final class StandardMethodCodec implements MethodCodec { ...@@ -58,4 +68,29 @@ public final class StandardMethodCodec implements MethodCodec {
buffer.put(stream.buffer(), 0, stream.size()); buffer.put(stream.buffer(), 0, stream.size());
return buffer; return buffer;
} }
@Override
public Object decodeEnvelope(ByteBuffer envelope) {
envelope.order(ByteOrder.nativeOrder());
final byte flag = envelope.get();
switch (flag) {
case 0: {
final Object result = StandardMessageCodec.readValue(envelope);
if (!envelope.hasRemaining()) {
return result;
}
}
case 1: {
final Object code = StandardMessageCodec.readValue(envelope);
final Object message = StandardMessageCodec.readValue(envelope);
final Object details = StandardMessageCodec.readValue(envelope);
if (code instanceof String
&& (message == null || message instanceof String)
&& !envelope.hasRemaining()) {
throw new FlutterException((String) code, (String) message, details);
}
}
}
throw new IllegalArgumentException("Envelope corrupted");
}
} }
...@@ -10,12 +10,12 @@ import java.nio.charset.Charset; ...@@ -10,12 +10,12 @@ import java.nio.charset.Charset;
/** /**
* A {@link MessageCodec} using UTF-8 encoded String messages. * A {@link MessageCodec} using UTF-8 encoded String messages.
*/ */
public final class StringMessageCodec implements MessageCodec<String> { public final class StringCodec implements MessageCodec<String> {
// This codec must match the Dart codec of the same name in package flutter/services. // This codec must match the Dart codec of the same name in package flutter/services.
private static final Charset UTF8 = Charset.forName("UTF8"); private static final Charset UTF8 = Charset.forName("UTF8");
public static final StringMessageCodec INSTANCE = new StringMessageCodec(); public static final StringCodec INSTANCE = new StringCodec();
private StringMessageCodec() { private StringCodec() {
} }
@Override @Override
......
...@@ -6,56 +6,41 @@ package io.flutter.plugin.editing; ...@@ -6,56 +6,41 @@ package io.flutter.plugin.editing;
import android.text.Editable; import android.text.Editable;
import android.text.Selection; import android.text.Selection;
import android.util.Log;
import android.view.inputmethod.BaseInputConnection; import android.view.inputmethod.BaseInputConnection;
import android.view.inputmethod.CompletionInfo;
import android.view.inputmethod.CorrectionInfo;
import android.view.inputmethod.EditorInfo;
import android.view.KeyEvent; import android.view.KeyEvent;
import android.view.View;
import io.flutter.plugin.common.FlutterMethodChannel;
import io.flutter.view.FlutterView; import io.flutter.view.FlutterView;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
class InputConnectionAdaptor extends BaseInputConnection { import java.util.Arrays;
static final String TAG = "FlutterView"; import java.util.HashMap;
static final String MESSAGE_NAME = "flutter/textinputclient"; import java.util.Map;
private FlutterView mView; class InputConnectionAdaptor extends BaseInputConnection {
private int mClient; private final int mClient;
private TextInputPlugin mPlugin; private final TextInputPlugin mPlugin;
private JSONObject mOutgoingState; private final FlutterMethodChannel mFlutterChannel;
private final Map<String, Object> mOutgoingState;
public InputConnectionAdaptor(FlutterView view, int client, TextInputPlugin plugin) { public InputConnectionAdaptor(FlutterView view, int client,
TextInputPlugin plugin, FlutterMethodChannel flutterChannel) {
super(view, true); super(view, true);
mView = view;
mClient = client; mClient = client;
mPlugin = plugin; mPlugin = plugin;
mOutgoingState = new JSONObject(); mFlutterChannel = flutterChannel;
mOutgoingState = new HashMap<>();
} }
private void updateEditingState() { private void updateEditingState() {
try {
final Editable content = getEditable(); final Editable content = getEditable();
mOutgoingState.put("text", content.toString()); mOutgoingState.put("text", content.toString());
mOutgoingState.put("selectionBase", Selection.getSelectionStart(content)); mOutgoingState.put("selectionBase", Selection.getSelectionStart(content));
mOutgoingState.put("selectionExtent", Selection.getSelectionEnd(content)); mOutgoingState.put("selectionExtent", Selection.getSelectionEnd(content));
mOutgoingState.put("composingBase", BaseInputConnection.getComposingSpanStart(content)); mOutgoingState.put("composingBase", BaseInputConnection.getComposingSpanStart(content));
mOutgoingState.put("composingExtent", BaseInputConnection.getComposingSpanEnd(content)); mOutgoingState.put("composingExtent", BaseInputConnection.getComposingSpanEnd(content));
mFlutterChannel.invokeMethod("TextInputClient.updateEditingState", Arrays
final JSONArray args = new JSONArray(); .asList(mClient, mOutgoingState));
args.put(0, mClient);
args.put(1, mOutgoingState);
final JSONObject message = new JSONObject();
message.put("method", "TextInputClient.updateEditingState");
message.put("args", args);
mView.sendPlatformMessage(MESSAGE_NAME, message.toString(), null);
mPlugin.setLatestEditingState(mOutgoingState); mPlugin.setLatestEditingState(mOutgoingState);
} catch (JSONException e) {
Log.e(TAG, "Unexpected error serializing editing state", e);
}
} }
@Override @Override
...@@ -103,7 +88,7 @@ class InputConnectionAdaptor extends BaseInputConnection { ...@@ -103,7 +88,7 @@ class InputConnectionAdaptor extends BaseInputConnection {
// 2. There is a selection. In that case, we want to delete the selection. // 2. There is a selection. In that case, we want to delete the selection.
// event.getNumber() is 0, and commitText("", 1) will do what we want. // event.getNumber() is 0, and commitText("", 1) will do what we want.
if (event.getKeyCode() == KeyEvent.KEYCODE_DEL && if (event.getKeyCode() == KeyEvent.KEYCODE_DEL &&
mOutgoingState.optInt("selectionBase", -1) == mOutgoingState.optInt("selectionExtent", -1)) { optInt("selectionBase", -1) == optInt("selectionExtent", -1)) {
deleteSurroundingText(1, 0); deleteSurroundingText(1, 0);
} else { } else {
String text = event.getNumber() == 0 ? "" : String.valueOf(event.getNumber()); String text = event.getNumber() == 0 ? "" : String.valueOf(event.getNumber());
...@@ -113,21 +98,15 @@ class InputConnectionAdaptor extends BaseInputConnection { ...@@ -113,21 +98,15 @@ class InputConnectionAdaptor extends BaseInputConnection {
return result; return result;
} }
private int optInt(String key, int defaultValue) {
return mOutgoingState.containsKey(key) ? (Integer) mOutgoingState.get(key) : defaultValue;
}
@Override @Override
public boolean performEditorAction(int actionCode) { public boolean performEditorAction(int actionCode) {
try {
// TODO(abarth): Support more actions. // TODO(abarth): Support more actions.
final JSONArray args = new JSONArray(); mFlutterChannel.invokeMethod("TextInputClient.performAction",
args.put(0, mClient); Arrays.asList(mClient, "TextInputAction.done"));
args.put(1, "TextInputAction.done");
final JSONObject message = new JSONObject();
message.put("method", "TextInputClient.performAction");
message.put("args", args);
mView.sendPlatformMessage(MESSAGE_NAME, message.toString(), null);
return true; return true;
} catch (JSONException e) {
Log.e(TAG, "Unexpected error serializing editor action", e);
return false;
}
} }
} }
...@@ -6,17 +6,19 @@ package io.flutter.plugin.editing; ...@@ -6,17 +6,19 @@ package io.flutter.plugin.editing;
import android.app.Activity; import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.text.Editable;
import android.text.InputType; import android.text.InputType;
import android.text.Selection;
import android.text.SpannableStringBuilder;
import android.util.Log;
import android.view.inputmethod.EditorInfo; import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodManager; import android.view.inputmethod.InputMethodManager;
import android.view.View;
import io.flutter.plugin.common.JSONMessageListener; import io.flutter.plugin.common.FlutterMethodChannel;
import io.flutter.plugin.common.FlutterMethodChannel.MethodCallHandler;
import io.flutter.plugin.common.FlutterMethodChannel.Response;
import io.flutter.plugin.common.JSONMethodCodec;
import io.flutter.plugin.common.MethodCall;
import io.flutter.view.FlutterView; import io.flutter.view.FlutterView;
import java.util.Map;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
...@@ -24,37 +26,50 @@ import org.json.JSONObject; ...@@ -24,37 +26,50 @@ import org.json.JSONObject;
/** /**
* Android implementation of the text input plugin. * Android implementation of the text input plugin.
*/ */
public class TextInputPlugin extends JSONMessageListener { public class TextInputPlugin implements MethodCallHandler {
private static final String TAG = "FlutterView";
private final Activity mActivity; private final Activity mActivity;
private final FlutterView mView;
private final FlutterMethodChannel mFlutterChannel;
private int mClient = 0; private int mClient = 0;
private JSONObject mConfiguration; private JSONObject mConfiguration;
private JSONObject mLatestState; private JSONObject mLatestState;
public TextInputPlugin(Activity activity) { public TextInputPlugin(Activity activity, FlutterView view) {
mActivity = activity; mActivity = activity;
mView = view;
mFlutterChannel = new FlutterMethodChannel(view, "flutter/textinput",
JSONMethodCodec.INSTANCE);
mFlutterChannel.setMethodCallHandler(this);
} }
@Override @Override
public JSONObject onJSONMessage(FlutterView view, JSONObject message) throws JSONException { public void onMethodCall(MethodCall call, Response response) {
String method = message.getString("method"); String method = call.method;
JSONArray args = message.getJSONArray("args"); Object args = call.arguments;
try {
if (method.equals("TextInput.show")) { if (method.equals("TextInput.show")) {
showTextInput(view); showTextInput(mView);
response.success(null);
} else if (method.equals("TextInput.hide")) { } else if (method.equals("TextInput.hide")) {
hideTextInput(view); hideTextInput(mView);
response.success(null);
} else if (method.equals("TextInput.setClient")) { } else if (method.equals("TextInput.setClient")) {
setTextInputClient(view, args.getInt(0), args.getJSONObject(1)); final JSONArray argumentList = (JSONArray) args;
setTextInputClient(mView, argumentList.getInt(0), argumentList.getJSONObject(1));
response.success(null);
} else if (method.equals("TextInput.setEditingState")) { } else if (method.equals("TextInput.setEditingState")) {
setTextInputEditingState(view, args.getJSONObject(0)); setTextInputEditingState(mView, (JSONObject) args);
response.success(null);
} else if (method.equals("TextInput.clearClient")) { } else if (method.equals("TextInput.clearClient")) {
clearTextInputClient(); clearTextInputClient();
response.success(null);
} else { } else {
// TODO(abarth): We should throw an exception here that gets response.error("unknown", "Unknown method: " + call.method, null);
// transmitted back to Dart. }
} catch (JSONException e) {
response.error("error", "JSON error: " + e.getMessage(), null);
} }
return null;
} }
private static int inputTypeFromTextInputType(String inputType) { private static int inputTypeFromTextInputType(String inputType) {
...@@ -67,33 +82,30 @@ public class TextInputPlugin extends JSONMessageListener { ...@@ -67,33 +82,30 @@ public class TextInputPlugin extends JSONMessageListener {
return InputType.TYPE_CLASS_TEXT; return InputType.TYPE_CLASS_TEXT;
} }
public InputConnection createInputConnection(FlutterView view, EditorInfo outAttrs) { public InputConnection createInputConnection(FlutterView view, EditorInfo outAttrs)
throws JSONException {
if (mClient == 0) if (mClient == 0)
return null; return null;
try {
outAttrs.inputType = inputTypeFromTextInputType(mConfiguration.getString("inputType")); outAttrs.inputType = inputTypeFromTextInputType(mConfiguration.getString("inputType"));
outAttrs.actionLabel = getStringOrNull(mConfiguration, "actionLabel"); outAttrs.actionLabel = mConfiguration.getString("actionLabel");
outAttrs.imeOptions = EditorInfo.IME_ACTION_DONE | EditorInfo.IME_FLAG_NO_FULLSCREEN; outAttrs.imeOptions = EditorInfo.IME_ACTION_DONE | EditorInfo.IME_FLAG_NO_FULLSCREEN;
InputConnectionAdaptor connection = new InputConnectionAdaptor(view, mClient, this); InputConnectionAdaptor connection = new InputConnectionAdaptor(view, mClient, this,
mFlutterChannel);
if (mLatestState != null) { if (mLatestState != null) {
int selectionBase = mLatestState.getInt("selectionBase"); int selectionBase = (Integer) mLatestState.get("selectionBase");
int selectionExtent = mLatestState.getInt("selectionExtent"); int selectionExtent = (Integer) mLatestState.get("selectionExtent");
outAttrs.initialSelStart = selectionBase; outAttrs.initialSelStart = selectionBase;
outAttrs.initialSelEnd = selectionExtent; outAttrs.initialSelEnd = selectionExtent;
connection.getEditable().append(mLatestState.getString("text")); connection.getEditable().append((String) mLatestState.get("text"));
connection.setSelection(Math.max(selectionBase, 0), connection.setSelection(Math.max(selectionBase, 0),
Math.max(selectionExtent, 0)); Math.max(selectionExtent, 0));
connection.setComposingRegion(mLatestState.getInt("composingBase"), connection.setComposingRegion((Integer) mLatestState.get("composingBase"),
mLatestState.getInt("composingExtent")); (Integer) mLatestState.get("composingExtent"));
} else { } else {
outAttrs.initialSelStart = 0; outAttrs.initialSelStart = 0;
outAttrs.initialSelEnd = 0; outAttrs.initialSelEnd = 0;
} }
return connection; return connection;
} catch (JSONException e) {
Log.e(TAG, "Failed to create input connection", e);
}
return null;
} }
private void showTextInput(FlutterView view) { private void showTextInput(FlutterView view) {
...@@ -108,7 +120,7 @@ public class TextInputPlugin extends JSONMessageListener { ...@@ -108,7 +120,7 @@ public class TextInputPlugin extends JSONMessageListener {
imm.hideSoftInputFromWindow(view.getApplicationWindowToken(), 0); imm.hideSoftInputFromWindow(view.getApplicationWindowToken(), 0);
} }
private void setTextInputClient(FlutterView view, int client, JSONObject configuration) throws JSONException { private void setTextInputClient(FlutterView view, int client, JSONObject configuration) {
mLatestState = null; mLatestState = null;
mClient = client; mClient = client;
mConfiguration = configuration; mConfiguration = configuration;
...@@ -117,15 +129,15 @@ public class TextInputPlugin extends JSONMessageListener { ...@@ -117,15 +129,15 @@ public class TextInputPlugin extends JSONMessageListener {
imm.restartInput(view); imm.restartInput(view);
} }
private void setTextInputEditingState(FlutterView view, JSONObject state) throws JSONException { private void setTextInputEditingState(FlutterView view, JSONObject state) {
mLatestState = state; mLatestState = state;
InputMethodManager imm = InputMethodManager imm =
(InputMethodManager) mActivity.getSystemService(Context.INPUT_METHOD_SERVICE); (InputMethodManager) mActivity.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.restartInput(view); imm.restartInput(view);
} }
void setLatestEditingState(JSONObject state) { void setLatestEditingState(Map<String, Object> state) {
mLatestState = state; mLatestState = (JSONObject) JSONObject.wrap(state);
} }
private void clearTextInputClient() { private void clearTextInputClient() {
......
...@@ -16,9 +16,12 @@ import android.os.Build; ...@@ -16,9 +16,12 @@ import android.os.Build;
import android.view.HapticFeedbackConstants; import android.view.HapticFeedbackConstants;
import android.view.SoundEffectConstants; import android.view.SoundEffectConstants;
import android.view.View; import android.view.View;
import io.flutter.plugin.common.ActivityLifecycleListener; import io.flutter.plugin.common.ActivityLifecycleListener;
import io.flutter.plugin.common.JSONMessageListener; import io.flutter.plugin.common.FlutterMethodChannel.MethodCallHandler;
import io.flutter.view.FlutterView; import io.flutter.plugin.common.FlutterMethodChannel.Response;
import io.flutter.plugin.common.MethodCall;
import org.chromium.base.PathUtils; import org.chromium.base.PathUtils;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
...@@ -27,7 +30,7 @@ import org.json.JSONObject; ...@@ -27,7 +30,7 @@ import org.json.JSONObject;
/** /**
* Android implementation of the platform plugin. * Android implementation of the platform plugin.
*/ */
public class PlatformPlugin extends JSONMessageListener implements ActivityLifecycleListener { public class PlatformPlugin implements MethodCallHandler, ActivityLifecycleListener {
private final Activity mActivity; private final Activity mActivity;
public static final int DEFAULT_SYSTEM_UI = View.SYSTEM_UI_FLAG_LAYOUT_STABLE public static final int DEFAULT_SYSTEM_UI = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
...@@ -39,38 +42,49 @@ public class PlatformPlugin extends JSONMessageListener implements ActivityLifec ...@@ -39,38 +42,49 @@ public class PlatformPlugin extends JSONMessageListener implements ActivityLifec
} }
@Override @Override
public JSONObject onJSONMessage(FlutterView view, JSONObject message) throws JSONException { public void onMethodCall(MethodCall call, Response response) {
String method = message.getString("method"); String method = call.method;
JSONArray args = message.getJSONArray("args"); Object arguments = call.arguments;
try {
if (method.equals("SystemSound.play")) { if (method.equals("SystemSound.play")) {
playSystemSound(args.getString(0)); playSystemSound((String) arguments);
response.success(null);
} else if (method.equals("HapticFeedback.vibrate")) { } else if (method.equals("HapticFeedback.vibrate")) {
vibrateHapticFeedback(); vibrateHapticFeedback();
response.success(null);
} else if (method.equals("UrlLauncher.launch")) { } else if (method.equals("UrlLauncher.launch")) {
launchURL(args.getString(0)); launchURL((String) arguments);
response.success(null);
} else if (method.equals("SystemChrome.setPreferredOrientations")) { } else if (method.equals("SystemChrome.setPreferredOrientations")) {
setSystemChromePreferredOrientatations(args.getJSONArray(0)); setSystemChromePreferredOrientations((JSONArray) arguments);
response.success(null);
} else if (method.equals("SystemChrome.setApplicationSwitcherDescription")) { } else if (method.equals("SystemChrome.setApplicationSwitcherDescription")) {
setSystemChromeApplicationSwitcherDescription(args.getJSONObject(0)); setSystemChromeApplicationSwitcherDescription((JSONObject) arguments);
response.success(null);
} else if (method.equals("SystemChrome.setEnabledSystemUIOverlays")) { } else if (method.equals("SystemChrome.setEnabledSystemUIOverlays")) {
setSystemChromeEnabledSystemUIOverlays(args.getJSONArray(0)); setSystemChromeEnabledSystemUIOverlays((JSONArray) arguments);
response.success(null);
} else if (method.equals("SystemChrome.setSystemUIOverlayStyle")) { } else if (method.equals("SystemChrome.setSystemUIOverlayStyle")) {
setSystemChromeSystemUIOverlayStyle(args.getString(0)); setSystemChromeSystemUIOverlayStyle((String) arguments);
response.success(null);
} else if (method.equals("SystemNavigator.pop")) { } else if (method.equals("SystemNavigator.pop")) {
popSystemNavigator(); popSystemNavigator();
response.success(null);
} else if (method.equals("Clipboard.getData")) { } else if (method.equals("Clipboard.getData")) {
return getClipboardData(args.getString(0)); response.success(getClipboardData((String) arguments));
} else if (method.equals("Clipboard.setData")) { } else if (method.equals("Clipboard.setData")) {
setClipboardData(args.getJSONObject(0)); setClipboardData((JSONObject) arguments);
response.success(null);
} else if (method.equals("PathProvider.getTemporaryDirectory")) { } else if (method.equals("PathProvider.getTemporaryDirectory")) {
return getPathProviderTemporaryDirectory(); response.success(getPathProviderTemporaryDirectory());
} else if (method.equals("PathProvider.getApplicationDocumentsDirectory")) { } else if (method.equals("PathProvider.getApplicationDocumentsDirectory")) {
return getPathProviderApplicationDocumentsDirectory(); response.success(getPathProviderApplicationDocumentsDirectory());
} else { } else {
// TODO(abarth): We should throw an exception here that gets response.error("unknown", "Unknown method: " + method, null);
// transmitted back to Dart. }
} catch (JSONException e) {
response.error("error", "JSON error: " + e.getMessage(), null);
} }
return null;
} }
private void playSystemSound(String soundType) { private void playSystemSound(String soundType) {
...@@ -95,19 +109,19 @@ public class PlatformPlugin extends JSONMessageListener implements ActivityLifec ...@@ -95,19 +109,19 @@ public class PlatformPlugin extends JSONMessageListener implements ActivityLifec
} }
} }
private void setSystemChromePreferredOrientatations(JSONArray orientatations) throws JSONException { private void setSystemChromePreferredOrientations(JSONArray orientations) throws JSONException {
// Currently the Android implementation only supports masks with zero or one // Currently the Android implementation only supports masks with zero or one
// selected device orientations. // selected device orientations.
int androidOrientation; int androidOrientation;
if (orientatations.length() == 0) { if (orientations.length() == 0) {
androidOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; androidOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
} else if (orientatations.getString(0).equals("DeviceOrientation.portraitUp")) { } else if (orientations.getString(0).equals("DeviceOrientation.portraitUp")) {
androidOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; androidOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
} else if (orientatations.getString(0).equals("DeviceOrientation.landscapeLeft")) { } else if (orientations.getString(0).equals("DeviceOrientation.landscapeLeft")) {
androidOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; androidOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
} else if (orientatations.getString(0).equals("DeviceOrientation.portraitDown")) { } else if (orientations.getString(0).equals("DeviceOrientation.portraitDown")) {
androidOrientation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT; androidOrientation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
} else if (orientatations.getString(0).equals("DeviceOrientation.landscapeRight")) { } else if (orientations.getString(0).equals("DeviceOrientation.landscapeRight")) {
androidOrientation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE; androidOrientation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
} else { } else {
return; return;
...@@ -197,16 +211,12 @@ public class PlatformPlugin extends JSONMessageListener implements ActivityLifec ...@@ -197,16 +211,12 @@ public class PlatformPlugin extends JSONMessageListener implements ActivityLifec
clipboard.setPrimaryClip(clip); clipboard.setPrimaryClip(clip);
} }
private JSONObject getPathProviderTemporaryDirectory() throws JSONException { private String getPathProviderTemporaryDirectory() {
JSONObject result = new JSONObject(); return mActivity.getCacheDir().getPath();
result.put("path", mActivity.getCacheDir().getPath());
return result;
} }
private JSONObject getPathProviderApplicationDocumentsDirectory() throws JSONException { private String getPathProviderApplicationDocumentsDirectory() {
JSONObject result = new JSONObject(); return PathUtils.getDataDirectory(mActivity);
result.put("path", PathUtils.getDataDirectory(mActivity));
return result;
} }
@Override @Override
......
...@@ -10,12 +10,10 @@ import android.os.Bundle; ...@@ -10,12 +10,10 @@ import android.os.Bundle;
import android.util.Log; import android.util.Log;
import android.view.View; import android.view.View;
import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityNodeInfo; import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityNodeProvider; import android.view.accessibility.AccessibilityNodeProvider;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
......
...@@ -10,10 +10,8 @@ import android.content.pm.PackageManager; ...@@ -10,10 +10,8 @@ import android.content.pm.PackageManager;
import android.content.res.AssetManager; import android.content.res.AssetManager;
import android.os.Bundle; import android.os.Bundle;
import android.os.SystemClock; import android.os.SystemClock;
import java.io.BufferedReader;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException;
import java.io.InputStreamReader;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
...@@ -21,9 +19,6 @@ import java.util.Collections; ...@@ -21,9 +19,6 @@ import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import org.json.JSONArray;
import org.json.JSONObject;
import org.json.JSONTokener;
import org.chromium.base.JNINamespace; import org.chromium.base.JNINamespace;
import org.chromium.base.PathUtils; import org.chromium.base.PathUtils;
......
...@@ -11,7 +11,6 @@ import android.util.Log; ...@@ -11,7 +11,6 @@ import android.util.Log;
import java.io.File; import java.io.File;
import java.io.FilenameFilter; import java.io.FilenameFilter;
import java.io.IOException;
/** /**
* A class to clean up orphaned resource directories after unclean shutdowns. * A class to clean up orphaned resource directories after unclean shutdowns.
......
...@@ -17,14 +17,11 @@ shared_library("flutter_framework_dylib") { ...@@ -17,14 +17,11 @@ shared_library("flutter_framework_dylib") {
sources = [ sources = [
"framework/Headers/Flutter.h", "framework/Headers/Flutter.h",
"framework/Headers/FlutterAppDelegate.h", "framework/Headers/FlutterAppDelegate.h",
"framework/Headers/FlutterAsyncMessageListener.h",
"framework/Headers/FlutterChannels.h", "framework/Headers/FlutterChannels.h",
"framework/Headers/FlutterCodecs.h", "framework/Headers/FlutterCodecs.h",
"framework/Headers/FlutterBinaryMessenger.h", "framework/Headers/FlutterBinaryMessenger.h",
"framework/Headers/FlutterDartProject.h", "framework/Headers/FlutterDartProject.h",
"framework/Headers/FlutterJSONMessageListener.h",
"framework/Headers/FlutterMacros.h", "framework/Headers/FlutterMacros.h",
"framework/Headers/FlutterMessageListener.h",
"framework/Headers/FlutterViewController.h", "framework/Headers/FlutterViewController.h",
"framework/Source/FlutterAppDelegate.mm", "framework/Source/FlutterAppDelegate.mm",
"framework/Source/FlutterChannels.mm", "framework/Source/FlutterChannels.mm",
...@@ -33,7 +30,6 @@ shared_library("flutter_framework_dylib") { ...@@ -33,7 +30,6 @@ shared_library("flutter_framework_dylib") {
"framework/Source/FlutterDartProject_Internal.h", "framework/Source/FlutterDartProject_Internal.h",
"framework/Source/FlutterDartSource.h", "framework/Source/FlutterDartSource.h",
"framework/Source/FlutterDartSource.mm", "framework/Source/FlutterDartSource.mm",
"framework/Source/FlutterJSONMessageListener.mm",
"framework/Source/FlutterPlatformPlugin.h", "framework/Source/FlutterPlatformPlugin.h",
"framework/Source/FlutterPlatformPlugin.mm", "framework/Source/FlutterPlatformPlugin.mm",
"framework/Source/FlutterStandardCodec_Internal.h", "framework/Source/FlutterStandardCodec_Internal.h",
...@@ -158,14 +154,11 @@ copy("framework_headers") { ...@@ -158,14 +154,11 @@ copy("framework_headers") {
sources = [ sources = [
"framework/Headers/Flutter.h", "framework/Headers/Flutter.h",
"framework/Headers/FlutterAppDelegate.h", "framework/Headers/FlutterAppDelegate.h",
"framework/Headers/FlutterAsyncMessageListener.h",
"framework/Headers/FlutterBinaryMessenger.h", "framework/Headers/FlutterBinaryMessenger.h",
"framework/Headers/FlutterChannels.h", "framework/Headers/FlutterChannels.h",
"framework/Headers/FlutterCodecs.h", "framework/Headers/FlutterCodecs.h",
"framework/Headers/FlutterDartProject.h", "framework/Headers/FlutterDartProject.h",
"framework/Headers/FlutterJSONMessageListener.h",
"framework/Headers/FlutterMacros.h", "framework/Headers/FlutterMacros.h",
"framework/Headers/FlutterMessageListener.h",
"framework/Headers/FlutterViewController.h", "framework/Headers/FlutterViewController.h",
] ]
outputs = [ outputs = [
......
...@@ -6,14 +6,11 @@ ...@@ -6,14 +6,11 @@
#define FLUTTER_FLUTTER_H_ #define FLUTTER_FLUTTER_H_
#include "FlutterAppDelegate.h" #include "FlutterAppDelegate.h"
#include "FlutterAsyncMessageListener.h"
#include "FlutterBinaryMessenger.h" #include "FlutterBinaryMessenger.h"
#include "FlutterChannels.h" #include "FlutterChannels.h"
#include "FlutterCodecs.h" #include "FlutterCodecs.h"
#include "FlutterDartProject.h" #include "FlutterDartProject.h"
#include "FlutterJSONMessageListener.h"
#include "FlutterMacros.h" #include "FlutterMacros.h"
#include "FlutterMessageListener.h"
#include "FlutterViewController.h" #include "FlutterViewController.h"
#endif // FLUTTER_FLUTTER_H_ #endif // FLUTTER_FLUTTER_H_
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_FLUTTERASYNCMESSAGELISTENER_H_
#define FLUTTER_FLUTTERASYNCMESSAGELISTENER_H_
#import <Foundation/Foundation.h>
#include "FlutterMacros.h"
FLUTTER_EXPORT
@protocol FlutterAsyncMessageListener<NSObject>
- (void)didReceiveString:(NSString*)message
callback:(void(^)(NSString*))sendResponse;
@property(readonly, strong, nonatomic) NSString* messageName;
@end
#endif // FLUTTER_FLUTTERASYNCMESSAGELISTENER_H_
...@@ -17,6 +17,10 @@ FLUTTER_EXPORT ...@@ -17,6 +17,10 @@ FLUTTER_EXPORT
+ (instancetype)messageChannelNamed:(NSString*)name + (instancetype)messageChannelNamed:(NSString*)name
binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger
codec:(NSObject<FlutterMessageCodec>*)codec; codec:(NSObject<FlutterMessageCodec>*)codec;
- (instancetype)initWithName:(NSString*)name
binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger
codec:(NSObject<FlutterMessageCodec>*)codec;
- (void)sendMessage:(id)message;
- (void)sendMessage:(id)message replyHandler:(FlutterReplyHandler)handler; - (void)sendMessage:(id)message replyHandler:(FlutterReplyHandler)handler;
- (void)setMessageHandler:(FlutterMessageHandler)handler; - (void)setMessageHandler:(FlutterMessageHandler)handler;
@end @end
...@@ -37,6 +41,13 @@ FLUTTER_EXPORT ...@@ -37,6 +41,13 @@ FLUTTER_EXPORT
+ (instancetype)methodChannelNamed:(NSString*)name + (instancetype)methodChannelNamed:(NSString*)name
binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger
codec:(NSObject<FlutterMethodCodec>*)codec; codec:(NSObject<FlutterMethodCodec>*)codec;
- (instancetype)initWithName:(NSString*)name
binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger
codec:(NSObject<FlutterMethodCodec>*)codec;
- (void)invokeMethod:(NSString*)method arguments:(id)arguments;
- (void)invokeMethod:(NSString*)method
arguments:(id)arguments
resultReceiver:(FlutterResultReceiver)resultReceiver;
- (void)setMethodCallHandler:(FlutterMethodCallHandler)handler; - (void)setMethodCallHandler:(FlutterMethodCallHandler)handler;
- (void)setStreamHandler:(FlutterStreamHandler)handler; - (void)setStreamHandler:(FlutterStreamHandler)handler;
@end @end
......
...@@ -35,8 +35,8 @@ FLUTTER_EXPORT ...@@ -35,8 +35,8 @@ FLUTTER_EXPORT
@interface FlutterMethodCall : NSObject @interface FlutterMethodCall : NSObject
+ (instancetype)methodCallWithMethodName:(NSString*)method + (instancetype)methodCallWithMethodName:(NSString*)method
arguments:(id)arguments; arguments:(id)arguments;
@property(readonly) NSString* method; @property(readonly, nonatomic) NSString* method;
@property(readonly) id arguments; @property(readonly, nonatomic) id arguments;
@end @end
FLUTTER_EXPORT FLUTTER_EXPORT
...@@ -44,9 +44,9 @@ FLUTTER_EXPORT ...@@ -44,9 +44,9 @@ FLUTTER_EXPORT
+ (instancetype)errorWithCode:(NSString*)code + (instancetype)errorWithCode:(NSString*)code
message:(NSString*)message message:(NSString*)message
details:(id)details; details:(id)details;
@property(readonly) NSString* code; @property(readonly, nonatomic) NSString* code;
@property(readonly) NSString* message; @property(readonly, nonatomic) NSString* message;
@property(readonly) id details; @property(readonly, nonatomic) id details;
@end @end
typedef NS_ENUM(NSInteger, FlutterStandardDataType) { typedef NS_ENUM(NSInteger, FlutterStandardDataType) {
...@@ -62,24 +62,26 @@ FLUTTER_EXPORT ...@@ -62,24 +62,26 @@ FLUTTER_EXPORT
+ (instancetype)typedDataWithInt32:(NSData*)data; + (instancetype)typedDataWithInt32:(NSData*)data;
+ (instancetype)typedDataWithInt64:(NSData*)data; + (instancetype)typedDataWithInt64:(NSData*)data;
+ (instancetype)typedDataWithFloat64:(NSData*)data; + (instancetype)typedDataWithFloat64:(NSData*)data;
@property(readonly) NSData* data; @property(readonly, nonatomic) NSData* data;
@property(readonly) FlutterStandardDataType type; @property(readonly, nonatomic) FlutterStandardDataType type;
@property(readonly) UInt32 elementCount; @property(readonly, nonatomic) UInt32 elementCount;
@property(readonly) UInt8 elementSize; @property(readonly, nonatomic) UInt8 elementSize;
@end @end
FLUTTER_EXPORT FLUTTER_EXPORT
@interface FlutterStandardBigInteger : NSObject @interface FlutterStandardBigInteger : NSObject
+ (instancetype)bigIntegerWithHex:(NSString*)hex; + (instancetype)bigIntegerWithHex:(NSString*)hex;
@property(readonly) NSString* hex; @property(readonly, nonatomic) NSString* hex;
@end @end
FLUTTER_EXPORT FLUTTER_EXPORT
@protocol FlutterMethodCodec @protocol FlutterMethodCodec
+ (instancetype)sharedInstance; + (instancetype)sharedInstance;
- (FlutterMethodCall*)decodeMethodCall:(NSData*)message; - (NSData*)encodeMethodCall:(FlutterMethodCall*)methodCall;
- (FlutterMethodCall*)decodeMethodCall:(NSData*)methodCall;
- (NSData*)encodeSuccessEnvelope:(id)result; - (NSData*)encodeSuccessEnvelope:(id)result;
- (NSData*)encodeErrorEnvelope:(FlutterError*)error; - (NSData*)encodeErrorEnvelope:(FlutterError*)error;
- (id)decodeEnvelope:(NSData*)envelope error:(FlutterError**)error;
@end @end
FLUTTER_EXPORT FLUTTER_EXPORT
......
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_FLUTTERJSONMESSAGELISTENER_H_
#define FLUTTER_FLUTTERJSONMESSAGELISTENER_H_
#include "FlutterMessageListener.h"
FLUTTER_EXPORT
@interface FlutterJSONMessageListener : NSObject<FlutterMessageListener>
- (NSDictionary*)didReceiveJSON:(NSDictionary*)message;
@end
#endif // FLUTTER_FLUTTERJSONMESSAGELISTENER_H_
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_FLUTTERMESSAGELISTENER_H_
#define FLUTTER_FLUTTERMESSAGELISTENER_H_
#import <Foundation/Foundation.h>
#include "FlutterMacros.h"
FLUTTER_EXPORT
@protocol FlutterMessageListener<NSObject>
- (NSString*)didReceiveString:(NSString*)message;
@property(readonly, strong, nonatomic) NSString* messageName;
@end
#endif // FLUTTER_FLUTTERMESSAGELISTENER_H_
...@@ -8,11 +8,9 @@ ...@@ -8,11 +8,9 @@
#import <UIKit/UIKit.h> #import <UIKit/UIKit.h>
#include <sys/cdefs.h> #include <sys/cdefs.h>
#include "FlutterAsyncMessageListener.h"
#include "FlutterBinaryMessenger.h" #include "FlutterBinaryMessenger.h"
#include "FlutterDartProject.h" #include "FlutterDartProject.h"
#include "FlutterMacros.h" #include "FlutterMacros.h"
#include "FlutterMessageListener.h"
FLUTTER_EXPORT FLUTTER_EXPORT
@interface FlutterViewController : UIViewController<FlutterBinaryMessenger> @interface FlutterViewController : UIViewController<FlutterBinaryMessenger>
...@@ -22,22 +20,6 @@ FLUTTER_EXPORT ...@@ -22,22 +20,6 @@ FLUTTER_EXPORT
bundle:(NSBundle*)nibBundleOrNil bundle:(NSBundle*)nibBundleOrNil
NS_DESIGNATED_INITIALIZER; NS_DESIGNATED_INITIALIZER;
- (void)sendString:(NSString*)message withMessageName:(NSString*)messageName;
- (void)sendString:(NSString*)message
withMessageName:(NSString*)messageName
callback:(void (^)(NSString*))callback;
- (void)addMessageListener:(NSObject<FlutterMessageListener>*)listener;
- (void)removeMessageListener:(NSObject<FlutterMessageListener>*)listener;
- (void)addAsyncMessageListener:
(NSObject<FlutterAsyncMessageListener>*)listener;
- (void)removeAsyncMessageListener:
(NSObject<FlutterAsyncMessageListener>*)listener;
- (void)handleStatusBarTouches:(UIEvent*)event; - (void)handleStatusBarTouches:(UIEvent*)event;
@end @end
......
...@@ -37,6 +37,11 @@ ...@@ -37,6 +37,11 @@
[super dealloc]; [super dealloc];
} }
- (void)sendMessage:(id)message {
[_messenger sendBinaryMessage:[_codec encode:message]
channelName:_name];
}
- (void)sendMessage:(id)message replyHandler:(FlutterReplyHandler)handler { - (void)sendMessage:(id)message replyHandler:(FlutterReplyHandler)handler {
[_messenger sendBinaryMessage:[_codec encode:message] [_messenger sendBinaryMessage:[_codec encode:message]
channelName:_name channelName:_name
...@@ -147,6 +152,25 @@ ...@@ -147,6 +152,25 @@
[super dealloc]; [super dealloc];
} }
- (void)invokeMethod:(NSString*)method arguments:(id)arguments {
[_messenger sendBinaryMessage:[_codec encodeMethodCall:[FlutterMethodCall methodCallWithMethodName:method arguments:arguments]]
channelName:_name];
}
- (void)invokeMethod:(NSString*)method
arguments:(id)arguments
resultReceiver:(FlutterResultReceiver)resultReceiver {
[_messenger sendBinaryMessage:[_codec encodeMethodCall:[FlutterMethodCall methodCallWithMethodName:method arguments:arguments]]
channelName:_name
binaryReplyHandler:^(NSData* reply) {
if (resultReceiver) {
FlutterError* flutterError = nil;
id result = [_codec decodeEnvelope:reply error:&flutterError];
resultReceiver(result, flutterError);
}
}];
}
- (void)setMethodCallHandler:(FlutterMethodCallHandler)handler { - (void)setMethodCallHandler:(FlutterMethodCallHandler)handler {
[_messenger [_messenger
setBinaryMessageHandlerOnChannel:_name setBinaryMessageHandlerOnChannel:_name
......
...@@ -78,20 +78,43 @@ ...@@ -78,20 +78,43 @@
return _sharedInstance; return _sharedInstance;
} }
- (NSData*)encodeMethodCall:(FlutterMethodCall*)call {
return [[FlutterJSONMessageCodec sharedInstance] encode:@{
@"method": call.method,
@"args": (call.arguments == nil ? [NSNull null] : call.arguments),
}];
}
- (NSData*)encodeSuccessEnvelope:(id)result { - (NSData*)encodeSuccessEnvelope:(id)result {
return [[FlutterJSONMessageCodec sharedInstance] encode:@[ result ]]; return [[FlutterJSONMessageCodec sharedInstance] encode:@[
result == nil ? [NSNull null] : result
]];
} }
- (NSData*)encodeErrorEnvelope:(FlutterError*)error { - (NSData*)encodeErrorEnvelope:(FlutterError*)error {
return [[FlutterJSONMessageCodec sharedInstance] return [[FlutterJSONMessageCodec sharedInstance] encode:@[
encode:@[ error.code, error.message, error.details ]]; error.code,
error.message == nil ? [NSNull null] : error.message,
error.details == nil ? [NSNull null] : error.details,
]];
} }
- (FlutterMethodCall*)decodeMethodCall:(NSData*)message { - (FlutterMethodCall*)decodeMethodCall:(NSData*)message {
NSArray* call = [[FlutterJSONMessageCodec sharedInstance] decode:message]; NSDictionary* dictionary = [[FlutterJSONMessageCodec sharedInstance] decode:message];
NSAssert(call.count == 2, @"Invalid JSON method call"); id method = dictionary[@"method"];
NSAssert([call[0] isKindOfClass:[NSString class]], id arguments = dictionary[@"args"];
@"Invalid JSON method call"); NSAssert([method isKindOfClass:[NSString class]], @"Invalid JSON method call");
return [FlutterMethodCall methodCallWithMethodName:call[0] arguments:call[1]]; return [FlutterMethodCall methodCallWithMethodName:method arguments:arguments];
}
- (id)decodeEnvelope:(NSData*)envelope error:(FlutterError**)error {
NSArray* array = [[FlutterJSONMessageCodec sharedInstance] decode:envelope];
if (array.count == 1)
return array[0];
NSAssert(array.count == 3, @"Invalid JSON envelope");
NSAssert([array[0] isKindOfClass:[NSString class]], @"Invalid JSON envelope");
NSAssert(array[1] == nil || [array[1] isKindOfClass:[NSString class]], @"Invalid JSON envelope");
*error = [FlutterError errorWithCode:array[0] message:array[1] details:array[2]];
return nil;
} }
@end @end
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "flutter/shell/platform/darwin/ios/framework/Headers/FlutterJSONMessageListener.h"
@implementation FlutterJSONMessageListener
- (NSString*)didReceiveString:(NSString*)message {
if (!message)
return nil;
NSError *error = nil;
NSData* data = [message dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary* jsonObject = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
if (error)
return nil;
NSDictionary* response = [self didReceiveJSON:jsonObject];
if (!response)
return nil;
NSData* responseData = [NSJSONSerialization dataWithJSONObject:response options:0 error:nil];
if (!responseData)
return nil;
return [[[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding] autorelease];
}
- (NSDictionary*)didReceiveJSON:(NSDictionary*)message {
return nil;
}
- (NSString *)messageName {
return nil;
}
@end
...@@ -5,9 +5,11 @@ ...@@ -5,9 +5,11 @@
#ifndef SHELL_PLATFORM_IOS_FRAMEWORK_SOURCE_FLUTTERPLATFORMPLUGIN_H_ #ifndef SHELL_PLATFORM_IOS_FRAMEWORK_SOURCE_FLUTTERPLATFORMPLUGIN_H_
#define SHELL_PLATFORM_IOS_FRAMEWORK_SOURCE_FLUTTERPLATFORMPLUGIN_H_ #define SHELL_PLATFORM_IOS_FRAMEWORK_SOURCE_FLUTTERPLATFORMPLUGIN_H_
#include "flutter/shell/platform/darwin/ios/framework/Headers/FlutterJSONMessageListener.h" #include "flutter/shell/platform/darwin/ios/framework/Headers/FlutterChannels.h"
@interface FlutterPlatformPlugin : FlutterJSONMessageListener @interface FlutterPlatformPlugin : NSObject
-(void)handleMethodCall:(FlutterMethodCall*)call resultReceiver:(FlutterResultReceiver)resultReceiver;
@end @end
......
...@@ -41,42 +41,45 @@ using namespace shell; ...@@ -41,42 +41,45 @@ using namespace shell;
@implementation FlutterPlatformPlugin @implementation FlutterPlatformPlugin
- (NSString *)messageName { - (void)handleMethodCall:(FlutterMethodCall*)call resultReceiver:(FlutterResultReceiver)resultReceiver {
return @"flutter/platform"; NSString* method = call.method;
} id args = call.arguments;
- (NSDictionary*)didReceiveJSON:(NSDictionary*)message {
NSString* method = message[@"method"];
NSArray* args = message[@"args"];
if ([method isEqualToString:@"SystemSound.play"]) { if ([method isEqualToString:@"SystemSound.play"]) {
[self playSystemSound:args.firstObject]; [self playSystemSound:args];
resultReceiver(nil, nil);
} else if ([method isEqualToString:@"HapticFeedback.vibrate"]) { } else if ([method isEqualToString:@"HapticFeedback.vibrate"]) {
[self vibrateHapticFeedback]; [self vibrateHapticFeedback];
resultReceiver(nil, nil);
} else if ([method isEqualToString:@"UrlLauncher.launch"]) { } else if ([method isEqualToString:@"UrlLauncher.launch"]) {
[self launchURL:args.firstObject]; [self launchURL:args];
resultReceiver(nil, nil);
} else if ([method isEqualToString:@"SystemChrome.setPreferredOrientations"]) { } else if ([method isEqualToString:@"SystemChrome.setPreferredOrientations"]) {
[self setSystemChromePreferredOrientatations:args.firstObject]; [self setSystemChromePreferredOrientations:args];
resultReceiver(nil, nil);
} else if ([method isEqualToString:@"SystemChrome.setApplicationSwitcherDescription"]) { } else if ([method isEqualToString:@"SystemChrome.setApplicationSwitcherDescription"]) {
[self setSystemChromeApplicationSwitcherDescription:args.firstObject]; [self setSystemChromeApplicationSwitcherDescription:args];
resultReceiver(nil, nil);
} else if ([method isEqualToString:@"SystemChrome.setEnabledSystemUIOverlays"]) { } else if ([method isEqualToString:@"SystemChrome.setEnabledSystemUIOverlays"]) {
[self setSystemChromeEnabledSystemUIOverlays:args.firstObject]; [self setSystemChromeEnabledSystemUIOverlays:args];
resultReceiver(nil, nil);
} else if ([method isEqualToString:@"SystemChrome.setSystemUIOverlayStyle"]) { } else if ([method isEqualToString:@"SystemChrome.setSystemUIOverlayStyle"]) {
[self setSystemChromeSystemUIOverlayStyle:args.firstObject]; [self setSystemChromeSystemUIOverlayStyle:args];
resultReceiver(nil, nil);
} else if ([method isEqualToString:@"SystemNavigator.pop"]) { } else if ([method isEqualToString:@"SystemNavigator.pop"]) {
[self popSystemNavigator]; [self popSystemNavigator];
resultReceiver(nil, nil);
} else if ([method isEqualToString:@"Clipboard.getData"]) { } else if ([method isEqualToString:@"Clipboard.getData"]) {
return [self getClipboardData:args.firstObject]; resultReceiver([self getClipboardData:args], nil);
} else if ([method isEqualToString:@"Clipboard.setData"]) { } else if ([method isEqualToString:@"Clipboard.setData"]) {
[self setClipboardData:args.firstObject]; [self setClipboardData:args];
resultReceiver(nil, nil);
} else if ([method isEqualToString:@"PathProvider.getTemporaryDirectory"]) { } else if ([method isEqualToString:@"PathProvider.getTemporaryDirectory"]) {
return [self getPathProviderTemporaryDirectory]; resultReceiver([self getPathProviderTemporaryDirectory], nil);
} else if ([method isEqualToString:@"PathProvider.getApplicationDocumentsDirectory"]) { } else if ([method isEqualToString:@"PathProvider.getApplicationDocumentsDirectory"]) {
return [self getPathProviderApplicationDocumentsDirectory]; resultReceiver([self getPathProviderApplicationDocumentsDirectory], nil);
} else { } else {
// TODO(abarth): We should signal an error here that gets reported back to resultReceiver(nil, [FlutterError errorWithCode:@"UNKNOWN" message:@"Unknown method" details: nil]);
// Dart.
} }
return nil;
} }
- (void)playSystemSound:(NSString*)soundType { - (void)playSystemSound:(NSString*)soundType {
...@@ -99,7 +102,7 @@ using namespace shell; ...@@ -99,7 +102,7 @@ using namespace shell;
return @{ @"succes": @(success) }; return @{ @"succes": @(success) };
} }
- (void)setSystemChromePreferredOrientatations:(NSArray*)orientations { - (void)setSystemChromePreferredOrientations:(NSArray*)orientations {
UIInterfaceOrientationMask mask = 0; UIInterfaceOrientationMask mask = 0;
if (orientations.count == 0) { if (orientations.count == 0) {
......
...@@ -42,6 +42,14 @@ ...@@ -42,6 +42,14 @@
return _sharedInstance; return _sharedInstance;
} }
- (NSData*)encodeMethodCall:(FlutterMethodCall*)call {
NSMutableData* data = [NSMutableData dataWithCapacity:32];
FlutterStandardWriter* writer = [FlutterStandardWriter writerWithData:data];
[writer writeValue:call.method];
[writer writeValue:call.arguments];
return data;
}
- (NSData*)encodeSuccessEnvelope:(id)result { - (NSData*)encodeSuccessEnvelope:(id)result {
NSMutableData* data = [NSMutableData dataWithCapacity:32]; NSMutableData* data = [NSMutableData dataWithCapacity:32];
FlutterStandardWriter* writer = [FlutterStandardWriter writerWithData:data]; FlutterStandardWriter* writer = [FlutterStandardWriter writerWithData:data];
...@@ -70,6 +78,33 @@ ...@@ -70,6 +78,33 @@
@"Corrupted standard method call"); @"Corrupted standard method call");
return [FlutterMethodCall methodCallWithMethodName:value1 arguments:value2]; return [FlutterMethodCall methodCallWithMethodName:value1 arguments:value2];
} }
- (id)decodeEnvelope:(NSData*)envelope error:(FlutterError**)error {
FlutterStandardReader* reader =
[FlutterStandardReader readerWithData:envelope];
UInt8 flag = [reader readByte];
NSAssert(flag <= 1, @"Corrupted standard envelope");
id result;
switch (flag) {
case 0: {
result = [reader readValue];
NSAssert(![reader hasMore], @"Corrupted standard envelope");
}
break;
case 1: {
id code = [reader readValue];
id message = [reader readValue];
id details = [reader readValue];
NSAssert(![reader hasMore], @"Corrupted standard envelope");
NSAssert([code isKindOfClass:[NSString class]], @"Invalid standard envelope");
NSAssert(message == nil || [message isKindOfClass:[NSString class]], @"Invalid standard envelope");
*error = [FlutterError errorWithCode:code message:message details:details];
result = nil;
}
break;
}
return result;
}
@end @end
using namespace shell; using namespace shell;
......
...@@ -56,6 +56,7 @@ UInt8 elementSizeForFlutterStandardDataType(FlutterStandardDataType type) { ...@@ -56,6 +56,7 @@ UInt8 elementSizeForFlutterStandardDataType(FlutterStandardDataType type) {
@interface FlutterStandardReader : NSObject @interface FlutterStandardReader : NSObject
+ (instancetype)readerWithData:(NSData*)data; + (instancetype)readerWithData:(NSData*)data;
- (BOOL)hasMore; - (BOOL)hasMore;
- (UInt8)readByte;
- (id)readValue; - (id)readValue;
@end @end
......
...@@ -5,12 +5,13 @@ ...@@ -5,12 +5,13 @@
#ifndef SHELL_PLATFORM_IOS_FRAMEWORK_SOURCE_FLUTTERTEXTINPUTPLUGIN_H_ #ifndef SHELL_PLATFORM_IOS_FRAMEWORK_SOURCE_FLUTTERTEXTINPUTPLUGIN_H_
#define SHELL_PLATFORM_IOS_FRAMEWORK_SOURCE_FLUTTERTEXTINPUTPLUGIN_H_ #define SHELL_PLATFORM_IOS_FRAMEWORK_SOURCE_FLUTTERTEXTINPUTPLUGIN_H_
#include "flutter/shell/platform/darwin/ios/framework/Headers/FlutterJSONMessageListener.h" #include "flutter/shell/platform/darwin/ios/framework/Headers/FlutterChannels.h"
#include "flutter/shell/platform/darwin/ios/framework/Source/FlutterTextInputDelegate.h" #include "flutter/shell/platform/darwin/ios/framework/Source/FlutterTextInputDelegate.h"
@interface FlutterTextInputPlugin : FlutterJSONMessageListener @interface FlutterTextInputPlugin : NSObject
@property(nonatomic, assign) id<FlutterTextInputDelegate> textInputDelegate; @property(nonatomic, assign) id<FlutterTextInputDelegate> textInputDelegate;
-(void)handleMethodCall:(FlutterMethodCall*)call resultReceiver:(FlutterResultReceiver)resultReceiver;
@end @end
......
...@@ -154,30 +154,27 @@ static UIKeyboardType ToUIKeyboardType(NSString* inputType) { ...@@ -154,30 +154,27 @@ static UIKeyboardType ToUIKeyboardType(NSString* inputType) {
[super dealloc]; [super dealloc];
} }
- (NSString *)messageName { - (void)handleMethodCall:(FlutterMethodCall*)call resultReceiver:(FlutterResultReceiver)resultReceiver {
return @"flutter/textinput"; NSString* method = call.method;
} id args = call.arguments;
- (NSDictionary*)didReceiveJSON:(NSDictionary*)message {
NSString* method = message[@"method"];
NSArray* args = message[@"args"];
if (!args)
return nil;
if ([method isEqualToString:@"TextInput.show"]) { if ([method isEqualToString:@"TextInput.show"]) {
[self showTextInput]; [self showTextInput];
resultReceiver(nil, nil);
} else if ([method isEqualToString:@"TextInput.hide"]) { } else if ([method isEqualToString:@"TextInput.hide"]) {
[self hideTextInput]; [self hideTextInput];
resultReceiver(nil, nil);
} else if ([method isEqualToString:@"TextInput.setClient"]) { } else if ([method isEqualToString:@"TextInput.setClient"]) {
[self setTextInputClient:[args[0] intValue] withConfiguration:args[1]]; [self setTextInputClient:[args[0] intValue] withConfiguration:args[1]];
resultReceiver(nil, nil);
} else if ([method isEqualToString:@"TextInput.setEditingState"]) { } else if ([method isEqualToString:@"TextInput.setEditingState"]) {
[self setTextInputEditingState:args.firstObject]; [self setTextInputEditingState:args];
resultReceiver(nil, nil);
} else if ([method isEqualToString:@"TextInput.clearClient"]) { } else if ([method isEqualToString:@"TextInput.clearClient"]) {
[self clearTextInputClient]; [self clearTextInputClient];
resultReceiver(nil, nil);
} else { } else {
// TODO(abarth): We should signal an error here that gets reported back to resultReceiver(nil, [FlutterError errorWithCode:@"UNKNOWN" message:@"Unknown method" details: nil]);
// Dart.
} }
return nil;
} }
- (void)showTextInput { - (void)showTextInput {
......
...@@ -68,7 +68,12 @@ void FlutterInit(int argc, const char* argv[]) { ...@@ -68,7 +68,12 @@ void FlutterInit(int argc, const char* argv[]) {
std::unique_ptr<shell::PlatformViewIOS> _platformView; std::unique_ptr<shell::PlatformViewIOS> _platformView;
base::scoped_nsprotocol<FlutterPlatformPlugin*> _platformPlugin; base::scoped_nsprotocol<FlutterPlatformPlugin*> _platformPlugin;
base::scoped_nsprotocol<FlutterTextInputPlugin*> _textInputPlugin; base::scoped_nsprotocol<FlutterTextInputPlugin*> _textInputPlugin;
base::scoped_nsprotocol<FlutterMethodChannel*> _localizationChannel;
base::scoped_nsprotocol<FlutterMethodChannel*> _navigationChannel;
base::scoped_nsprotocol<FlutterMethodChannel*> _platformChannel;
base::scoped_nsprotocol<FlutterMethodChannel*> _textInputChannel;
base::scoped_nsprotocol<FlutterMessageChannel*> _lifecycleChannel;
base::scoped_nsprotocol<FlutterMessageChannel*> _systemChannel;
BOOL _initialized; BOOL _initialized;
} }
...@@ -121,12 +126,46 @@ void FlutterInit(int argc, const char* argv[]) { ...@@ -121,12 +126,46 @@ void FlutterInit(int argc, const char* argv[]) {
reinterpret_cast<CAEAGLLayer*>(self.view.layer)); reinterpret_cast<CAEAGLLayer*>(self.view.layer));
_platformView->SetupResourceContextOnIOThread(); _platformView->SetupResourceContextOnIOThread();
_localizationChannel.reset([[FlutterMethodChannel alloc]
initWithName:@"flutter/localization"
binaryMessenger:self
codec:[FlutterJSONMethodCodec sharedInstance]]);
_navigationChannel.reset([[FlutterMethodChannel alloc]
initWithName:@"flutter/navigation"
binaryMessenger:self
codec:[FlutterJSONMethodCodec sharedInstance]]);
_platformChannel.reset([[FlutterMethodChannel alloc]
initWithName:@"flutter/platform"
binaryMessenger:self
codec:[FlutterJSONMethodCodec sharedInstance]]);
_textInputChannel.reset([[FlutterMethodChannel alloc]
initWithName:@"flutter/textinput"
binaryMessenger:self
codec:[FlutterJSONMethodCodec sharedInstance]]);
_lifecycleChannel.reset([[FlutterMessageChannel alloc]
initWithName:@"flutter/lifecycle"
binaryMessenger:self
codec:[FlutterStringCodec sharedInstance]]);
_systemChannel.reset([[FlutterMessageChannel alloc]
initWithName:@"flutter/system"
binaryMessenger:self
codec:[FlutterJSONMessageCodec sharedInstance]]);
_platformPlugin.reset([[FlutterPlatformPlugin alloc] init]); _platformPlugin.reset([[FlutterPlatformPlugin alloc] init]);
[self addMessageListener:_platformPlugin.get()]; [_platformChannel.get() setMethodCallHandler:^(FlutterMethodCall* call, FlutterResultReceiver resultReceiver) {
[_platformPlugin.get() handleMethodCall:call resultReceiver:resultReceiver];
}];
_textInputPlugin.reset([[FlutterTextInputPlugin alloc] init]); _textInputPlugin.reset([[FlutterTextInputPlugin alloc] init]);
_textInputPlugin.get().textInputDelegate = self; _textInputPlugin.get().textInputDelegate = self;
[self addMessageListener:_textInputPlugin.get()]; [_textInputChannel.get() setMethodCallHandler:^(FlutterMethodCall* call, FlutterResultReceiver resultReceiver) {
[_textInputPlugin.get() handleMethodCall:call resultReceiver:resultReceiver];
}];
[self setupNotificationCenterObservers]; [self setupNotificationCenterObservers];
...@@ -227,13 +266,11 @@ void FlutterInit(int argc, const char* argv[]) { ...@@ -227,13 +266,11 @@ void FlutterInit(int argc, const char* argv[]) {
#pragma mark - Application lifecycle notifications #pragma mark - Application lifecycle notifications
- (void)applicationBecameActive:(NSNotification*)notification { - (void)applicationBecameActive:(NSNotification*)notification {
[self sendString:@"AppLifecycleState.resumed" [_lifecycleChannel.get() sendMessage:@"AppLifecycleState.resumed"];
withMessageName:@"flutter/lifecycle"];
} }
- (void)applicationWillResignActive:(NSNotification*)notification { - (void)applicationWillResignActive:(NSNotification*)notification {
[self sendString:@"AppLifecycleState.paused" [_lifecycleChannel.get() sendMessage:@"AppLifecycleState.paused"];
withMessageName:@"flutter/lifecycle"];
} }
#pragma mark - Touch event handling #pragma mark - Touch event handling
...@@ -392,11 +429,7 @@ static inline PointerChangeMapperPhase PointerChangePhaseFromUITouchPhase( ...@@ -392,11 +429,7 @@ static inline PointerChangeMapperPhase PointerChangePhaseFromUITouchPhase(
#pragma mark - Text input delegate #pragma mark - Text input delegate
- (void)updateEditingClient:(int)client withState:(NSDictionary*)state { - (void)updateEditingClient:(int)client withState:(NSDictionary*)state {
NSDictionary* message = @{ [_textInputChannel.get() invokeMethod:@"TextInputClient.updateEditingState" arguments:@[ @(client), state ]];
@"method" : @"TextInputClient.updateEditingState",
@"args" : @[ @(client), state ],
};
[self sendJSON:message withMessageName:@"flutter/textinputclient"];
} }
#pragma mark - Orientation updates #pragma mark - Orientation updates
...@@ -446,8 +479,7 @@ static inline PointerChangeMapperPhase PointerChangePhaseFromUITouchPhase( ...@@ -446,8 +479,7 @@ static inline PointerChangeMapperPhase PointerChangePhaseFromUITouchPhase(
#pragma mark - Memory Notifications #pragma mark - Memory Notifications
- (void)onMemoryWarning:(NSNotification*)notification { - (void)onMemoryWarning:(NSNotification*)notification {
NSDictionary* message = @{ @"type" : @"memoryPressure" }; [_systemChannel.get() sendMessage:@{ @"type" : @"memoryPressure" }];
[self sendJSON:message withMessageName:@"flutter/system"];
} }
#pragma mark - Locale updates #pragma mark - Locale updates
...@@ -456,10 +488,7 @@ static inline PointerChangeMapperPhase PointerChangePhaseFromUITouchPhase( ...@@ -456,10 +488,7 @@ static inline PointerChangeMapperPhase PointerChangePhaseFromUITouchPhase(
NSLocale* currentLocale = [NSLocale currentLocale]; NSLocale* currentLocale = [NSLocale currentLocale];
NSString* languageCode = [currentLocale objectForKey:NSLocaleLanguageCode]; NSString* languageCode = [currentLocale objectForKey:NSLocaleLanguageCode];
NSString* countryCode = [currentLocale objectForKey:NSLocaleCountryCode]; NSString* countryCode = [currentLocale objectForKey:NSLocaleCountryCode];
NSDictionary* message = [_localizationChannel.get() invokeMethod:@"setLocale" arguments: @[ languageCode, countryCode ]];
@{ @"method" : @"setLocale",
@"args" : @[ languageCode, countryCode ] };
[self sendJSON:message withMessageName:@"flutter/localization"];
} }
#pragma mark - Surface creation and teardown updates #pragma mark - Surface creation and teardown updates
...@@ -549,79 +578,6 @@ constexpr CGFloat kStandardStatusBarHeight = 20.0; ...@@ -549,79 +578,6 @@ constexpr CGFloat kStandardStatusBarHeight = 20.0;
#pragma mark - Application Messages #pragma mark - Application Messages
- (void)sendString:(NSString*)message withMessageName:(NSString*)channel {
NSAssert(message, @"The message must not be null");
NSAssert(channel, @"The channel must not be null");
FlutterStringCodec* codec = [FlutterStringCodec sharedInstance];
[self sendBinaryMessage:[codec encode:message] channelName:channel];
}
- (void)sendString:(NSString*)message
withMessageName:(NSString*)channel
callback:(void (^)(NSString*))callback {
NSAssert(message, @"The message must not be null");
NSAssert(channel, @"The channel must not be null");
NSAssert(callback, @"The callback must not be null");
FlutterStringCodec* codec = [FlutterStringCodec sharedInstance];
[self sendBinaryMessage:[codec encode:message]
channelName:channel
binaryReplyHandler:^(NSData* data) {
callback([codec decode:data]);
}];
}
- (void)sendJSON:(NSDictionary*)message withMessageName:(NSString*)channel {
NSData* data = [[FlutterJSONMessageCodec sharedInstance] encode:message];
[self sendBinaryMessage:data channelName:channel];
}
- (void)addMessageListener:(NSObject<FlutterMessageListener>*)listener {
NSAssert(listener, @"The listener must not be null");
NSString* messageName = listener.messageName;
NSAssert(messageName, @"The messageName must not be null");
FlutterStringCodec* codec = [FlutterStringCodec sharedInstance];
[self
setBinaryMessageHandlerOnChannel:messageName
binaryMessageHandler:^(
NSData* message, FlutterBinaryReplyHandler replyHandler) {
NSString* reply =
[listener didReceiveString:[codec decode:message]];
replyHandler([codec encode:reply]);
}];
}
- (void)removeMessageListener:(NSObject<FlutterMessageListener>*)listener {
NSAssert(listener, @"The listener must not be null");
NSString* messageName = listener.messageName;
NSAssert(messageName, @"The messageName must not be null");
[self setBinaryMessageHandlerOnChannel:messageName binaryMessageHandler:nil];
}
- (void)addAsyncMessageListener:
(NSObject<FlutterAsyncMessageListener>*)listener {
NSAssert(listener, @"The listener must not be null");
NSString* messageName = listener.messageName;
NSAssert(messageName, @"The messageName must not be null");
FlutterStringCodec* codec = [FlutterStringCodec sharedInstance];
[self
setBinaryMessageHandlerOnChannel:messageName
binaryMessageHandler:^(
NSData* message, FlutterBinaryReplyHandler replyHandler) {
[listener didReceiveString:[codec decode:message]
callback:^(NSString* reply) {
replyHandler([codec encode:reply]);
}];
}];
}
- (void)removeAsyncMessageListener:
(NSObject<FlutterAsyncMessageListener>*)listener {
NSAssert(listener, @"The listener must not be null");
NSString* messageName = listener.messageName;
NSAssert(messageName, @"The messageName must not be null");
[self setBinaryMessageHandlerOnChannel:messageName binaryMessageHandler:nil];
}
- (void)sendBinaryMessage:(NSData*)message channelName:(NSString*)channel { - (void)sendBinaryMessage:(NSData*)message channelName:(NSString*)channel {
NSAssert(message, @"The message must not be null"); NSAssert(message, @"The message must not be null");
NSAssert(channel, @"The channel must not be null"); NSAssert(channel, @"The channel must not be null");
......
...@@ -1781,7 +1781,6 @@ FILE: ../../../flutter/shell/platform/android/android_surface_gl.h ...@@ -1781,7 +1781,6 @@ FILE: ../../../flutter/shell/platform/android/android_surface_gl.h
FILE: ../../../flutter/shell/platform/android/android_surface_vulkan.cc FILE: ../../../flutter/shell/platform/android/android_surface_vulkan.cc
FILE: ../../../flutter/shell/platform/android/android_surface_vulkan.h FILE: ../../../flutter/shell/platform/android/android_surface_vulkan.h
FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/common/ActivityLifecycleListener.java FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/common/ActivityLifecycleListener.java
FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/common/JSONMessageListener.java
FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/editing/InputConnectionAdaptor.java FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/editing/InputConnectionAdaptor.java
FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/editing/TextInputPlugin.java FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/editing/TextInputPlugin.java
FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/platform/PlatformPlugin.java FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/platform/PlatformPlugin.java
...@@ -1794,17 +1793,13 @@ FILE: ../../../flutter/shell/platform/darwin/common/process_info_mac.h ...@@ -1794,17 +1793,13 @@ FILE: ../../../flutter/shell/platform/darwin/common/process_info_mac.h
FILE: ../../../flutter/shell/platform/darwin/desktop/vsync_waiter_mac.h FILE: ../../../flutter/shell/platform/darwin/desktop/vsync_waiter_mac.h
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/Flutter.h FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/Flutter.h
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterAppDelegate.h FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterAppDelegate.h
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterAsyncMessageListener.h
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterDartProject.h FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterDartProject.h
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterJSONMessageListener.h
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterMacros.h FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterMacros.h
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterMessageListener.h
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterViewController.h FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterViewController.h
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterDartProject.mm FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterDartProject.mm
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterDartProject_Internal.h FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterDartProject_Internal.h
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterDartSource.h FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterDartSource.h
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterDartSource.mm FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterDartSource.mm
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterJSONMessageListener.mm
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformPlugin.h FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformPlugin.h
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformPlugin.mm FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformPlugin.mm
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterTextInputDelegate.h FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterTextInputDelegate.h
...@@ -1915,7 +1910,8 @@ FILE: ../../../flutter/fml/platform/darwin/cf_utils.cc ...@@ -1915,7 +1910,8 @@ FILE: ../../../flutter/fml/platform/darwin/cf_utils.cc
FILE: ../../../flutter/fml/platform/darwin/cf_utils.h FILE: ../../../flutter/fml/platform/darwin/cf_utils.h
FILE: ../../../flutter/shell/gpu/gpu_surface_software.cc FILE: ../../../flutter/shell/gpu/gpu_surface_software.cc
FILE: ../../../flutter/shell/gpu/gpu_surface_software.h FILE: ../../../flutter/shell/gpu/gpu_surface_software.h
FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/common/BinaryMessageCodec.java FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/common/BinaryCodec.java
FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/common/FlutterException.java
FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/common/FlutterMessageChannel.java FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/common/FlutterMessageChannel.java
FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/common/FlutterMethodChannel.java FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/common/FlutterMethodChannel.java
FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/common/JSONMessageCodec.java FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/common/JSONMessageCodec.java
...@@ -1924,7 +1920,7 @@ FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/common/MethodCal ...@@ -1924,7 +1920,7 @@ FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/common/MethodCal
FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/common/MethodCodec.java FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/common/MethodCodec.java
FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/common/StandardMessageCodec.java FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/common/StandardMessageCodec.java
FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/common/StandardMethodCodec.java FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/common/StandardMethodCodec.java
FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/common/StringMessageCodec.java FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/common/StringCodec.java
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterBinaryMessenger.h FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterBinaryMessenger.h
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterChannels.h FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterChannels.h
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterCodecs.h FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterCodecs.h
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册