Flutter插件开发:Android视角完整指南

Viewed 0

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.yamlREADME.mdCHANGELOG.md文件。

插件注册发生在Host App的MainActivity中,通过GeneratedPluginRegistrant.registerWith(this)调用插件的registerWith方法完成注册。GeneratedPluginRegistrant是Flutter工具自动生成的类,负责注册所有依赖的插件。

总之,Flutter插件开发涉及原生端与Flutter端的紧密协作,通过Platform Channels实现通信。Android端需充分利用Registrar获取上下文和处理回调,确保插件功能完整。

0 Answers