Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
471c97df
Commit
471c97df
authored
Mar 30, 2017
by
Mikkel Nygaard Ravn
Committed by
GitHub
Mar 30, 2017
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Platform channel API cleanup (#9048)
parent
0e43e581
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
131 additions
and
55 deletions
+131
-55
MainActivity.java
...c/main/java/com/example/platformchannel/MainActivity.java
+4
-1
AppDelegate.m
examples/platform_channel/ios/Runner/AppDelegate.m
+3
-7
message_codec.dart
packages/flutter/lib/src/services/message_codec.dart
+19
-3
message_codecs.dart
packages/flutter/lib/src/services/message_codecs.dart
+0
-4
platform_channel.dart
packages/flutter/lib/src/services/platform_channel.dart
+74
-33
text_input.dart
packages/flutter/lib/src/services/text_input.dart
+2
-0
platform_channel_test.dart
packages/flutter/test/services/platform_channel_test.dart
+29
-7
No files found.
examples/platform_channel/android/app/src/main/java/com/example/platformchannel/MainActivity.java
View file @
471c97df
...
...
@@ -37,9 +37,12 @@ public class MainActivity extends FlutterActivity {
}
else
{
response
.
error
(
"UNAVAILABLE"
,
"Battery level not available."
,
null
);
}
}
else
{
response
.
notImplemented
();
}
}
});
}
);
}
private
int
getBatteryLevel
()
{
...
...
examples/platform_channel/ios/Runner/AppDelegate.m
View file @
471c97df
...
...
@@ -13,8 +13,7 @@
(
FlutterViewController
*
)
self
.
window
.
rootViewController
;
FlutterMethodChannel
*
batteryChannel
=
[
FlutterMethodChannel
methodChannelWithName
:
@"battery"
binaryMessenger
:
controller
codec:
[
FlutterStandardMethodCodec
sharedInstance
]];
binaryMessenger
:
controller
];
[
batteryChannel
setMethodCallHandler
:
^
(
FlutterMethodCall
*
call
,
FlutterResultReceiver
result
)
{
if
([
@"getBatteryLevel"
isEqualToString
:
call
.
method
])
{
...
...
@@ -25,15 +24,12 @@
message
:
@"Battery info unavailable"
details:
nil
]);
}
else
{
result
(
[
NSNumber
numberWithInt
:(
int
)(
device
.
batteryLevel
*
100
)]
);
result
(
@
((
int
)(
device
.
batteryLevel
*
100
))
);
}
}
else
{
result
([
FlutterError
errorWithCode
:
@"UNKNOWN_METHOD"
message
:
@"Unknown battery method called"
details:
nil
]);
result
(
FlutterMethodNotImplemented
);
}
}];
return
YES
;
}
@end
packages/flutter/lib/src/services/message_codec.dart
View file @
471c97df
...
...
@@ -105,6 +105,8 @@ class MethodCall {
///
/// * [PlatformMethodChannel], which use [MethodCodec]s for communication
/// between Flutter and platform plugins.
/// * [PlatformEventChannel], which use [MethodCodec]s for communication
/// between Flutter and platform plugins.
abstract
class
MethodCodec
{
/// Encodes the specified [methodCall] in binary.
ByteData
encodeMethodCall
(
MethodCall
methodCall
);
...
...
@@ -139,7 +141,7 @@ abstract class MethodCodec {
/// * [PlatformMethodChannel.invokeMethod], which completes the returned future
/// with a [PlatformException], if invoking the platform plugin method
/// results in an error envelope.
/// * [Platform
Method
Channel.receiveBroadcastStream], which emits
/// * [Platform
Event
Channel.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
{
...
...
@@ -167,8 +169,22 @@ class PlatformException implements Exception {
String
toString
()
=>
'PlatformException(
$code
,
$message
,
$details
)'
;
}
/// Thrown to indicate that a platform interaction failed to find the plugin.
/// Thrown to indicate that a platform interaction failed to find a handling
/// plugin.
///
/// See also:
///
/// * [PlatformMethodChannel.invokeMethod], which completes the returned future
/// with a [MissingPluginException], 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'
;
String
toString
()
=>
'MissingPluginException
(
$message
)
'
;
}
packages/flutter/lib/src/services/message_codecs.dart
View file @
471c97df
...
...
@@ -120,8 +120,6 @@ class JSONMethodCodec implements MethodCodec {
@override
dynamic
decodeEnvelope
(
ByteData
envelope
)
{
if
(
envelope
==
null
)
throw
new
MissingPluginException
();
final
dynamic
decoded
=
const
JSONMessageCodec
().
decodeMessage
(
envelope
);
if
(
decoded
is
!
List
)
throw
new
FormatException
(
'Expected envelope List, got
$decoded
'
);
...
...
@@ -461,8 +459,6 @@ class StandardMethodCodec implements MethodCodec {
@override
dynamic
decodeEnvelope
(
ByteData
envelope
)
{
if
(
envelope
==
null
)
throw
new
MissingPluginException
();
// First byte is zero in success case, and non-zero otherwise.
if
(
envelope
.
lengthInBytes
==
0
)
throw
const
FormatException
(
'Expected envelope, got nothing'
);
...
...
packages/flutter/lib/src/services/platform_channel.dart
View file @
471c97df
...
...
@@ -90,7 +90,7 @@ class PlatformMessageChannel<T> {
}
/// A named channel for communicating with platform plugins using asynchronous
/// method calls
and event streams
.
/// method calls.
///
/// Method calls are encoded into binary before being sent, and binary results
/// received are decoded into Dart values. The [MethodCodec] used must be
...
...
@@ -125,12 +125,16 @@ class PlatformMethodChannel {
/// * a result (possibly `null`), on successful invocation;
/// * a [PlatformException], if the invocation failed in the platform plugin;
/// * a [FormatException], if encoding or decoding failed.
/// * a [MissingPluginException], if the method has not been implemented.
Future
<
dynamic
>
invokeMethod
(
String
method
,
[
dynamic
arguments
])
async
{
assert
(
method
!=
null
);
return
codec
.
decodeEnvelope
(
await
PlatformMessages
.
sendBinary
(
final
dynamic
result
=
await
PlatformMessages
.
sendBinary
(
name
,
codec
.
encodeMethodCall
(
new
MethodCall
(
method
,
arguments
)),
));
);
if
(
result
==
null
)
throw
new
MissingPluginException
(
"No implementation found for method
$method
on channel
$name
"
);
return
codec
.
decodeEnvelope
(
result
);
}
/// Sets a callback for receiving method calls on this channel.
...
...
@@ -143,7 +147,9 @@ class PlatformMethodChannel {
/// is sent back to the platform plugin caller wrapped in a success envelope
/// as defined by the [codec] of this channel. If the future completes with
/// a [PlatformException], the fields of that exception will be used to
/// populate an error envelope which is sent back instead.
/// populate an error envelope which is sent back instead. If the future
/// completes with a [MissingPluginException], an empty reply is sent
/// similarly to what happens if no method call handler has been set.
void
setMethodCallHandler
(
Future
<
dynamic
>
handler
(
MethodCall
call
))
{
if
(
handler
==
null
)
{
PlatformMessages
.
setBinaryMessageHandler
(
name
,
null
);
...
...
@@ -158,6 +164,8 @@ class PlatformMethodChannel {
}
on
PlatformException
catch
(
e
)
{
return
codec
.
encodeErrorEnvelope
(
code:
e
.
code
,
message:
e
.
message
,
details:
e
.
details
);
}
on
MissingPluginException
{
return
null
;
}
},
);
...
...
@@ -170,9 +178,10 @@ class PlatformMethodChannel {
/// this channel, if any. To remove the mock handler, pass `null` as the
/// `handler` argument.
///
/// If the future returned by the handler completes with a result, that value
/// is used as the result of the method invocation. If the future completes
/// with a [PlatformException], that will be thrown instead.
/// Later calls to [invokeMethod] will result in a successful result,
/// a [PlatformException] or a [MissingPluginException], determined by how
/// the future returned by the mock callback completes. The [codec] of this
/// channel is used to encode and decode values and errors.
///
/// This is intended for testing. Method calls intercepted in this manner are
/// not sent to platform plugins.
...
...
@@ -190,11 +199,61 @@ class PlatformMethodChannel {
}
on
PlatformException
catch
(
e
)
{
return
codec
.
encodeErrorEnvelope
(
code:
e
.
code
,
message:
e
.
message
,
details:
e
.
details
);
}
on
MissingPluginException
{
return
null
;
}
},
);
}
}
}
/// A [PlatformMethodChannel] that ignores missing platform plugins.
///
/// When [invokeMethod] fails to find the platform plugin, it returns null
/// instead of throwing an exception.
class
OptionalPlatformMethodChannel
extends
PlatformMethodChannel
{
/// Creates a [PlatformMethodChannel] that ignores missing platform plugins.
const
OptionalPlatformMethodChannel
(
String
name
,
[
MethodCodec
codec
=
const
StandardMethodCodec
()])
:
super
(
name
,
codec
);
@override
Future
<
dynamic
>
invokeMethod
(
String
method
,
[
dynamic
arguments
])
async
{
try
{
return
await
super
.
invokeMethod
(
method
,
arguments
);
}
on
MissingPluginException
{
return
null
;
}
}
}
/// A named channel for communicating with platform plugins using event streams.
///
/// Stream setup requests are encoded into binary before being sent,
/// and binary events received are decoded into Dart values. The [MethodCodec]
/// used must be compatible with the one used by the platform plugin. This can
/// be achieved by creating a FlutterEventChannel counterpart of this channel on
/// the platform side. The Dart type of events sent and received is `dynamic`,
/// but only values supported by the specified [MethodCodec] can be used.
///
/// The identity of the channel is given by its name, so other uses of that name
/// with may interfere with this channel's communication.
///
/// See: <https://flutter.io/platform-channels/>
class
PlatformEventChannel
{
/// Creates a [PlatformEventChannel] with the specified [name].
///
/// The [codec] used will be [StandardMethodCodec], unless otherwise
/// specified.
///
/// Neither [name] nor [codec] may be `null`.
const
PlatformEventChannel
(
this
.
name
,
[
this
.
codec
=
const
StandardMethodCodec
()]);
/// The logical channel on which communication happens, not `null`.
final
String
name
;
/// The message codec used by this channel, not `null`.
final
MethodCodec
codec
;
/// Sets up a broadcast stream for receiving events on this channel.
///
...
...
@@ -206,15 +265,15 @@ class PlatformMethodChannel {
/// received from the platform plugin;
/// * an error event containing a [FormatException] for each event received
/// where decoding fails;
/// * an error event containing a [PlatformException]
or [FormatException]
///
whenever stream setup fails (stream setup is done only when listener
/// count changes from 0 to 1).
/// * an error event containing a [PlatformException]
,
///
[MissingPluginException], or [FormatException] whenever stream setup fails
///
(stream setup is done only when listener
count changes from 0 to 1).
///
/// Notes for platform plugin implementers:
///
/// Plugins must expose methods named `listen` and `cancel` suitable for
/// invocations by [
invokeMethod]. Both methods are invoked with the specified
/// [arguments].
/// invocations by [
PlatformMethodChannel.invokeMethod]. Both methods are
///
invoked with the specified
[arguments].
///
/// Following the semantics of broadcast streams, `listen` will be called as
/// the first listener registers with the returned stream, and `cancel` when
...
...
@@ -222,6 +281,7 @@ class PlatformMethodChannel {
/// indefinitely. Platform plugins should consume no stream-related resources
/// while listener count is zero.
Stream
<
dynamic
>
receiveBroadcastStream
([
dynamic
arguments
])
{
final
PlatformMethodChannel
methodChannel
=
new
PlatformMethodChannel
(
name
,
codec
);
StreamController
<
dynamic
>
controller
;
controller
=
new
StreamController
<
dynamic
>.
broadcast
(
onListen:
()
async
{
...
...
@@ -239,7 +299,7 @@ class PlatformMethodChannel {
}
);
try
{
await
invokeMethod
(
'listen'
,
arguments
);
await
methodChannel
.
invokeMethod
(
'listen'
,
arguments
);
}
catch
(
e
)
{
PlatformMessages
.
setBinaryMessageHandler
(
name
,
null
);
controller
.
addError
(
e
);
...
...
@@ -247,7 +307,7 @@ class PlatformMethodChannel {
},
onCancel:
()
async
{
PlatformMessages
.
setBinaryMessageHandler
(
name
,
null
);
try
{
await
invokeMethod
(
'cancel'
,
arguments
);
await
methodChannel
.
invokeMethod
(
'cancel'
,
arguments
);
}
catch
(
exception
,
stack
)
{
FlutterError
.
reportError
(
new
FlutterErrorDetails
(
exception:
exception
,
...
...
@@ -261,22 +321,3 @@ class PlatformMethodChannel {
return
controller
.
stream
;
}
}
/// A [PlatformMethodChannel] that ignores missing platform plugins.
///
/// When [invokeMethod] fails to find the platform plugin, it returns null
/// instead of throwing an exception.
class
OptionalPlatformMethodChannel
extends
PlatformMethodChannel
{
/// Creates a [PlatformMethodChannel] that ignores missing platform plugins.
const
OptionalPlatformMethodChannel
(
String
name
,
[
MethodCodec
codec
=
const
StandardMethodCodec
()])
:
super
(
name
,
codec
);
@override
Future
<
dynamic
>
invokeMethod
(
String
method
,
[
dynamic
arguments
])
async
{
try
{
return
await
super
.
invokeMethod
(
method
,
arguments
);
}
on
MissingPluginException
{
return
null
;
}
}
}
packages/flutter/lib/src/services/text_input.dart
View file @
471c97df
...
...
@@ -261,6 +261,8 @@ class _TextInputClientHandler {
case
'TextInputClient.performAction'
:
_currentConnection
.
_client
.
performAction
(
_toTextInputAction
(
args
[
1
]));
break
;
default
:
throw
new
MissingPluginException
();
}
}
...
...
packages/flutter/test/services/platform_channel_test.dart
View file @
471c97df
...
...
@@ -37,10 +37,10 @@ void main() {
group
(
'PlatformMethodChannel'
,
()
{
const
MessageCodec
<
dynamic
>
jsonMessage
=
const
JSONMessageCodec
();
const
MethodCodec
jsonMethod
=
const
JSONMethodCodec
();
const
PlatformMethodChannel
channel
=
const
PlatformMethodChannel
(
'ch'
,
jsonMethod
);
const
PlatformMethodChannel
channel
=
const
PlatformMethodChannel
(
'ch
7
'
,
jsonMethod
);
test
(
'can invoke method and get result'
,
()
async
{
PlatformMessages
.
setMockBinaryMessageHandler
(
'ch'
,
'ch
7
'
,
(
ByteData
message
)
async
{
final
Map
<
dynamic
,
dynamic
>
methodCall
=
jsonMessage
.
decodeMessage
(
message
);
if
(
methodCall
[
'method'
]
==
'sayHello'
)
...
...
@@ -54,11 +54,11 @@ void main() {
});
test
(
'can invoke method and get error'
,
()
async
{
PlatformMessages
.
setMockBinaryMessageHandler
(
'ch'
,
'ch
7
'
,
(
ByteData
message
)
async
{
return
jsonMessage
.
encodeMessage
(<
dynamic
>[
'
unknown
'
,
'
Method not understoo
d'
,
'
bad
'
,
'
Something happene
d'
,
<
String
,
dynamic
>{
'a'
:
42
,
'b'
:
3.14
},
]);
},
...
...
@@ -67,11 +67,33 @@ void main() {
await
channel
.
invokeMethod
(
'sayHello'
,
'hello'
);
fail
(
'Exception expected'
);
}
on
PlatformException
catch
(
e
)
{
expect
(
e
.
code
,
equals
(
'
unknown
'
));
expect
(
e
.
message
,
equals
(
'
Method not understoo
d'
));
expect
(
e
.
code
,
equals
(
'
bad
'
));
expect
(
e
.
message
,
equals
(
'
Something happene
d'
));
expect
(
e
.
details
,
equals
(<
String
,
dynamic
>{
'a'
:
42
,
'b'
:
3.14
}));
}
catch
(
e
)
{
fail
(
'PlatformException expected'
);
}
});
test
(
'can invoke unimplemented method'
,
()
async
{
PlatformMessages
.
setMockBinaryMessageHandler
(
'ch7'
,
(
ByteData
message
)
async
=>
null
,
);
try
{
await
channel
.
invokeMethod
(
'sayHello'
,
'hello'
);
fail
(
'Exception expected'
);
}
on
MissingPluginException
catch
(
e
)
{
expect
(
e
.
message
,
contains
(
'sayHello'
));
expect
(
e
.
message
,
contains
(
'ch7'
));
}
catch
(
e
)
{
fail
(
'MissingPluginException expected'
);
}
});
});
group
(
'PlatformEventChannel'
,
()
{
const
MessageCodec
<
dynamic
>
jsonMessage
=
const
JSONMessageCodec
();
const
MethodCodec
jsonMethod
=
const
JSONMethodCodec
();
const
PlatformEventChannel
channel
=
const
PlatformEventChannel
(
'ch'
,
jsonMethod
);
test
(
'can receive event stream'
,
()
async
{
void
emitEvent
(
dynamic
event
)
{
PlatformMessages
.
handlePlatformMessage
(
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment