Flutter插件开发:Android视角
在Flutter插件开发中,Android端需要处理与Flutter应用通信的Platform Channels。本文从Android视角详细介绍如何开发一个音乐播放插件,涵盖MethodChannel、EventChannel的使用以及插件注册流程。
MethodChannel与EventChannel的实现
首先,在Android插件代码中,通过MethodChannel接收Flutter端的方法调用。例如,在onMethodCall方法中处理播放控制逻辑:
@Override
public void onMethodCall(MethodCall call, Result result) {
switch (call.method) {
case "start":
// 启动播放逻辑
break;
case "pause":
// 暂停播放逻辑
break;
default:
result.notImplemented();
break;
}
}
除了MethodChannel,还需要上报播放器状态和进度,这通过EventChannel实现。在registerWith方法中注册两个EventChannel:
public static void registerWith(Registrar registrar) {
// 上报播放器状态的EventChannel
EventChannel status_channel = new EventChannel(registrar.messenger(), "flutter_music_plugin.event.status");
status_channel.setStreamHandler(new EventChannel.StreamHandler() {
@Override
public void onListen(Object o, EventChannel.EventSink eventSink) {
plugin.setStateSink(eventSink);
}
@Override
public void onCancel(Object o) { }
});
// 上报播放进度的EventChannel
EventChannel position_channel = new EventChannel(registrar.messenger(), "flutter_music_plugin.event.position");
position_channel.setStreamHandler(new EventChannel.StreamHandler() {
@Override
public void onListen(Object o, EventChannel.EventSink eventSink) {
plugin.setPositionSink(eventSink);
}
@Override
public void onCancel(Object o) { }
});
}
注册后,通过保存的EventSink实例,可以在需要时向Flutter应用上报事件。
处理本地音频文件选择
在插件中打开本地音频文件时,由于插件不是Activity,需要利用Registrar接口获取Host App的Activity。Registrar提供了丰富的方法,例如activity()返回Host App的Activity,addActivityResultListener用于注册结果回调。
修改插件类实现PluginRegistry.ActivityResultListener:
public class FlutterMusicPlugin implements MethodCallHandler, PluginRegistry.ActivityResultListener {
private Activity mActivity;
private FlutterMusicPlugin(Activity activity) {
mActivity = activity;
}
public static void registerWith(Registrar registrar) {
final FlutterMusicPlugin plugin = new FlutterMusicPlugin(registrar.activity());
registrar.addActivityResultListener(plugin);
// 其他初始化代码
}
@Override
public void onMethodCall(MethodCall call, Result result) {
switch (call.method) {
case "open":
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("audio/*");
mActivity.startActivityForResult(intent, REQUEST_CODE_OPEN);
break;
// 其他方法处理
}
}
@Override
public boolean onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_CODE_OPEN && resultCode == RESULT_OK) {
Uri uri = data.getData();
if (uri != null) {
play(uri); // 开始播放
} else {
mStateSink.error("ERROR", "invalid media file", null);
}
return true;
}
return false;
}
}
这样,当Flutter端调用open方法时,会启动第三方应用选择音频文件,并在回调中获取文件URI进行播放。
Flutter端插件封装
在Flutter端,插件代码通常位于lib/flutter_music_plugin.dart文件中,封装了与原生端通信的Channel调用:
class FlutterMusicPlugin {
static const MethodChannel _channel = const MethodChannel('flutter_music_plugin');
static const EventChannel _status_channel = const EventChannel('flutter_music_plugin.event.status');
static const EventChannel _position_channel = const EventChannel('flutter_music_plugin.event.position');
static Future open() async {
await _channel.invokeMethod('open');
}
static Future pause() async {
await _channel.invokeMethod('pause');
}
static Future start() async {
await _channel.invokeMethod('start');
}
static Future<Duration> getDuration() async {
int duration = await _channel.invokeMethod('getDuration');
return Duration(milliseconds: duration);
}
static listenStatus(EventHandler onEvent, EventHandler onError) {
_status_channel.receiveBroadcastStream().listen(onEvent, onError: onError);
}
static listenPosition(EventHandler onEvent, EventHandler onError) {
_position_channel.receiveBroadcastStream().listen(onEvent, onError: onError);
}
}
示例应用的使用
在示例应用中,通过插件的API进行交互。例如,在initState中注册EventChannel监听:
@override
void initState() {
super.initState();
FlutterMusicPlugin.listenStatus(_onPlayerStatus, _onPlayerStatusError);
FlutterMusicPlugin.listenPosition(_onPosition, _onPlayerStatusError);
}
然后,根据播放状态调用相应方法,如_playPause切换播放和暂停,_open打开音频文件。
插件发布与注册
开发完成后,通过flutter packages pub publish命令发布插件。在发布前,需检查pubspec.yaml、README.md和CHANGELOG.md文件。
插件注册发生在Host App的MainActivity中,通过GeneratedPluginRegistrant.registerWith(this)调用插件的registerWith方法完成注册。GeneratedPluginRegistrant是Flutter工具自动生成的类,负责注册所有依赖的插件。
总之,Flutter插件开发涉及原生端与Flutter端的紧密协作,通过Platform Channels实现通信。Android端需充分利用Registrar获取上下文和处理回调,确保插件功能完整。