mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
217 lines
7.7 KiB
Dart
217 lines
7.7 KiB
Dart
// Copyright 2014 The Flutter Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
import 'package:flutter/foundation.dart';
|
|
|
|
import 'platform_channel.dart';
|
|
|
|
export 'dart:typed_data' show ByteData;
|
|
|
|
/// A message encoding/decoding mechanism.
|
|
///
|
|
/// Both operations throw an exception, if conversion fails. Such situations
|
|
/// should be treated as programming errors.
|
|
///
|
|
/// See also:
|
|
///
|
|
/// * [BasicMessageChannel], which use [MessageCodec]s for communication
|
|
/// between Flutter and platform plugins.
|
|
abstract class MessageCodec<T> {
|
|
/// Encodes the specified [message] in binary.
|
|
///
|
|
/// Returns null if the message is null.
|
|
ByteData? encodeMessage(T message);
|
|
|
|
/// Decodes the specified [message] from binary.
|
|
///
|
|
/// Returns null if the message is null.
|
|
T? decodeMessage(ByteData? message);
|
|
}
|
|
|
|
/// An command object representing the invocation of a named method.
|
|
@immutable
|
|
class MethodCall {
|
|
/// Creates a [MethodCall] representing the invocation of [method] with the
|
|
/// specified [arguments].
|
|
const MethodCall(this.method, [this.arguments])
|
|
: assert(method != null);
|
|
|
|
/// The name of the method to be called.
|
|
final String method;
|
|
|
|
/// The arguments for the method.
|
|
///
|
|
/// Must be a valid value for the [MethodCodec] used.
|
|
///
|
|
/// This property is `dynamic`, which means type-checking is skipped when accessing
|
|
/// this property. To minimize the risk of type errors at runtime, the value should
|
|
/// be cast to `Object?` when accessed.
|
|
final dynamic arguments;
|
|
|
|
@override
|
|
String toString() => '${objectRuntimeType(this, 'MethodCall')}($method, $arguments)';
|
|
}
|
|
|
|
/// A codec for method calls and enveloped results.
|
|
///
|
|
/// All operations throw an exception, if conversion fails.
|
|
///
|
|
/// See also:
|
|
///
|
|
/// * [MethodChannel], which use [MethodCodec]s for communication
|
|
/// between Flutter and platform plugins.
|
|
/// * [EventChannel], which use [MethodCodec]s for communication
|
|
/// between Flutter and platform plugins.
|
|
abstract class MethodCodec {
|
|
/// Encodes the specified [methodCall] into binary.
|
|
ByteData encodeMethodCall(MethodCall methodCall);
|
|
|
|
/// Decodes the specified [methodCall] from binary.
|
|
MethodCall decodeMethodCall(ByteData? methodCall);
|
|
|
|
/// Decodes the specified result [envelope] from binary.
|
|
///
|
|
/// Throws [PlatformException], if [envelope] represents an error, otherwise
|
|
/// returns the enveloped result.
|
|
///
|
|
/// The type returned from [decodeEnvelope] is `dynamic` (not `Object?`),
|
|
/// which means *no type checking is performed on its return value*. It is
|
|
/// strongly recommended that the return value be immediately cast to a known
|
|
/// type to prevent runtime errors due to typos that the type checker could
|
|
/// otherwise catch.
|
|
dynamic decodeEnvelope(ByteData envelope);
|
|
|
|
/// Encodes a successful [result] into a binary envelope.
|
|
ByteData encodeSuccessEnvelope(Object? result);
|
|
|
|
/// Encodes an error result into a binary envelope.
|
|
///
|
|
/// The specified error [code], human-readable error [message] and error
|
|
/// [details] correspond to the fields of [PlatformException].
|
|
ByteData encodeErrorEnvelope({ required String code, String? message, Object? details});
|
|
}
|
|
|
|
/// Thrown to indicate that a platform interaction failed in the platform
|
|
/// plugin.
|
|
///
|
|
/// See also:
|
|
///
|
|
/// * [MethodCodec], which throws a [PlatformException], if a received result
|
|
/// envelope represents an error.
|
|
/// * [MethodChannel.invokeMethod], which completes the returned future
|
|
/// with a [PlatformException], if invoking the platform plugin method
|
|
/// results in an error envelope.
|
|
/// * [EventChannel.receiveBroadcastStream], which emits
|
|
/// [PlatformException]s as error events, whenever an event received from the
|
|
/// platform plugin is wrapped in an error envelope.
|
|
class PlatformException implements Exception {
|
|
/// Creates a [PlatformException] with the specified error [code] and optional
|
|
/// [message], and with the optional error [details] which must be a valid
|
|
/// value for the [MethodCodec] involved in the interaction.
|
|
PlatformException({
|
|
required this.code,
|
|
this.message,
|
|
this.details,
|
|
this.stacktrace,
|
|
}) : assert(code != null);
|
|
|
|
/// An error code.
|
|
final String code;
|
|
|
|
/// A human-readable error message, possibly null.
|
|
final String? message;
|
|
|
|
/// Error details, possibly null.
|
|
///
|
|
/// This property is `dynamic`, which means type-checking is skipped when accessing
|
|
/// this property. To minimize the risk of type errors at runtime, the value should
|
|
/// be cast to `Object?` when accessed.
|
|
final dynamic details;
|
|
|
|
/// Native stacktrace for the error, possibly null.
|
|
///
|
|
/// This contains the native platform stack trace, not the Dart stack trace.
|
|
///
|
|
/// The stack trace for Dart exceptions can be obtained using try-catch blocks, for example:
|
|
///
|
|
/// ```dart
|
|
/// try {
|
|
/// // ...
|
|
/// } catch (e, stacktrace) {
|
|
/// print(stacktrace);
|
|
/// }
|
|
/// ```
|
|
///
|
|
/// On Android this field is populated when a `RuntimeException` or a subclass of it is thrown in the method call handler,
|
|
/// as shown in the following example:
|
|
///
|
|
/// ```kotlin
|
|
/// import androidx.annotation.NonNull
|
|
/// import io.flutter.embedding.android.FlutterActivity
|
|
/// import io.flutter.embedding.engine.FlutterEngine
|
|
/// import io.flutter.plugin.common.MethodChannel
|
|
///
|
|
/// class MainActivity: FlutterActivity() {
|
|
/// private val CHANNEL = "channel_name"
|
|
///
|
|
/// override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
|
|
/// super.configureFlutterEngine(flutterEngine)
|
|
/// MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler {
|
|
/// call, result -> throw RuntimeException("Oh no")
|
|
/// }
|
|
/// }
|
|
/// }
|
|
/// ```
|
|
///
|
|
/// It is also populated on Android if the method channel result is not serializable.
|
|
/// If the result is not serializable, an exception gets thrown during the serialization process.
|
|
/// This can be seen in the following example:
|
|
///
|
|
/// ```kotlin
|
|
/// import androidx.annotation.NonNull
|
|
/// import io.flutter.embedding.android.FlutterActivity
|
|
/// import io.flutter.embedding.engine.FlutterEngine
|
|
/// import io.flutter.plugin.common.MethodChannel
|
|
///
|
|
/// class MainActivity: FlutterActivity() {
|
|
/// private val CHANNEL = "channel_name"
|
|
///
|
|
/// override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
|
|
/// super.configureFlutterEngine(flutterEngine)
|
|
/// MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler {
|
|
/// call, result -> result.success(Object())
|
|
/// }
|
|
/// }
|
|
/// }
|
|
/// ```
|
|
///
|
|
/// In the cases described above, the content of [stacktrace] will be the unprocessed output of calling `toString()` on the exception.
|
|
final String? stacktrace;
|
|
|
|
@override
|
|
String toString() => 'PlatformException($code, $message, $details, $stacktrace)';
|
|
}
|
|
|
|
/// Thrown to indicate that a platform interaction failed to find a handling
|
|
/// plugin.
|
|
///
|
|
/// See also:
|
|
///
|
|
/// * [MethodChannel.invokeMethod], which completes the returned future
|
|
/// with a [MissingPluginException], if no plugin handler for the method call
|
|
/// was found.
|
|
/// * [OptionalMethodChannel.invokeMethod], which completes the returned future
|
|
/// with null, if no plugin handler for the method call was found.
|
|
class MissingPluginException implements Exception {
|
|
/// Creates a [MissingPluginException] with an optional human-readable
|
|
/// error message.
|
|
MissingPluginException([this.message]);
|
|
|
|
/// A human-readable error message, possibly null.
|
|
final String? message;
|
|
|
|
@override
|
|
String toString() => 'MissingPluginException($message)';
|
|
}
|