invokeMethod method
Invokes a method
on this channel with the specified arguments
.
The static type of arguments
is dynamic
, but only values supported by
the codec of this channel can be used. The same applies to the returned
result. The values supported by the default codec and their platform-specific
counterparts are documented with StandardMessageCodec.
Returns a Future which completes to one of the following:
- a result (possibly null), on successful invocation;
- a PlatformException, if the invocation failed in the platform plugin;
- a MissingPluginException, if the method has not been implemented by a platform plugin.
The following code snippets demonstrate how to invoke platform methods in Dart using a MethodChannel and how to implement those methods in Java (for Android) and Objective-C (for iOS).
The code might be packaged up as a musical plugin, see
flutter.io/developing-packages/:
class Music {
static const MethodChannel _channel = MethodChannel('music');
static Future<bool> isLicensed() async {
// invokeMethod returns a Future<dynamic>, and we cannot pass that for
// a Future<bool>, hence the indirection.
final bool result = await _channel.invokeMethod('isLicensed');
return result;
}
static Future<List<Song>> songs() async {
// invokeMethod here returns a Future<dynamic> that completes to a
// List<dynamic> with Map<dynamic, dynamic> entries. Post-processing
// code thus cannot assume e.g. List<Map<String, String>> even though
// the actual values involved would support such a typed container.
final List<dynamic> songs = await _channel.invokeMethod('getSongs');
return songs.map(Song.fromJson).toList();
}
static Future<void> play(Song song, double volume) async {
// Errors occurring on the platform side cause invokeMethod to throw
// PlatformExceptions.
try {
await _channel.invokeMethod('play', <String, dynamic>{
'song': song.id,
'volume': volume,
});
} on PlatformException catch (e) {
throw 'Unable to play ${song.title}: ${e.message}';
}
}
}
class Song {
Song(this.id, this.title, this.artist);
final String id;
final String title;
final String artist;
static Song fromJson(dynamic json) {
return Song(json['id'], json['title'], json['artist']);
}
}
Java (for Android):
// Assumes existence of an Android MusicApi.
public class MusicPlugin implements MethodCallHandler {
@Override
public void onMethodCall(MethodCall call, Result result) {
switch (call.method) {
case "isLicensed":
result.success(MusicApi.checkLicense());
break;
case "getSongs":
final List<MusicApi.Track> tracks = MusicApi.getTracks();
final List<Object> json = ArrayList<>(tracks.size());
for (MusicApi.Track track : tracks) {
json.add(track.toJson()); // Map<String, Object> entries
}
result.success(json);
break;
case "play":
final String song = call.argument("song");
final double volume = call.argument("volume");
try {
MusicApi.playSongAtVolume(song, volume);
result.success(null);
} catch (MusicalException e) {
result.error("playError", e.getMessage(), null);
}
break;
default:
result.notImplemented();
}
}
// Other methods elided.
}
Objective-C (for iOS):
@interface MusicPlugin : NSObject<FlutterPlugin>
@end
// Assumes existence of an iOS Broadway Play Api.
@implementation MusicPlugin
- (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
if ([@"isLicensed" isEqualToString:call.method]) {
result([NSNumber numberWithBool:[BWPlayApi isLicensed]]);
} else if ([@"getSongs" isEqualToString:call.method]) {
NSArray* items = [BWPlayApi items];
NSMutableArray* json = [NSMutableArray arrayWithCapacity:items.count];
for (BWPlayItem* item in items) {
[json addObject:@{@"id":item.itemId, @"title":item.name, @"artist":item.artist}];
}
result(json);
} else if ([@"play" isEqualToString:call.method]) {
NSString* itemId = call.arguments[@"song"];
NSNumber* volume = call.arguments[@"volume"];
NSError* error = nil;
BOOL success = [BWPlayApi playItem:itemId volume:volume.doubleValue error:&error];
if (success) {
result(nil);
} else {
result([FlutterError errorWithCode:[NSString stringWithFormat:@"Error %ld", error.code]
message:error.domain
details:error.localizedDescription]);
}
} else {
result(FlutterMethodNotImplemented);
}
}
// Other methods elided.
@end
See also:
- StandardMessageCodec which defines the payload values supported by StandardMethodCodec.
- JSONMessageCodec which defines the payload values supported by JSONMethodCodec.
- docs.flutter.io/javadoc/io/flutter/plugin/common/MethodCall.html for how to access method call arguments on Android.
Implementation
Future<dynamic> invokeMethod(String method, [dynamic arguments]) async {
assert(method != null);
final dynamic result = await BinaryMessages.send(
name,
codec.encodeMethodCall(MethodCall(method, arguments)),
);
if (result == null)
throw MissingPluginException('No implementation found for method $method on channel $name');
return codec.decodeEnvelope(result);
}