// 上报播放器的状态的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) {
// 把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) {
// 把eventSink存起来
plugin.setPositionSink(eventSink);
}

@Override
public void onCancel(Object o) {

}
});
}

注册完以后我们就拿到了两个EventSink,当需要的时候就可以用需要的EventSink给Flutter App上报事件了。

Native这边还有一环是打开本地音频文件的操作,这里我偷个懒,用发送Intent的方式来让用户在第三方app中选择音频文件。如果是在Activity中我会用startActivityForResultonActivityResult来获取音频文件,可是我们现在开发的是一个插件,不是Activity怎么办?

回想一下我们用来注册插件的静态函数registerWith,入参的类型是Registrar。看看它里面都有啥?

public interface Registrar {
//返回 Host app的Activity
Activity activity();
//返回 Application Context.
Context context();
//返回 活动Context
Context activeContext();
//返回 BinaryMessenger 主要用来注册Platform channels
BinaryMessenger messenger();
//返回 TextureRegistry,从里面可以拿到SurfaceTexture
TextureRegistry textures();
//返回 当前Host app创建的FlutterView
FlutterView view();
//返回Asset对应的文件路径
String lookupKeyForAsset(String var1);
//返回Asset对应的文件路径
String lookupKeyForAsset(String var1, String var2);
//插件对外发布的一个"值"
PluginRegistry.Registrar publish(Object var1);
//注册权限相关的回调
PluginRegistry.Registrar addRequestPermissionsResultListener(PluginRegistry.RequestPermissionsResultListener var1);
//注册ActivityResult回调
PluginRegistry.Registrar addActivityResultListener(PluginRegistry.ActivityResultListener var1);
//注册NewIntent回调
PluginRegistry.Registrar addNewIntentListener(PluginRegistry.NewIntentListener var1);
//注册UserLeaveHint回调
PluginRegistry.Registrar addUserLeaveHintListener(PluginRegistry.UserLeaveHintListener var1);
//注册View销毁回调
PluginRegistry.Registrar addViewDestroyListener(PluginRegistry.ViewDestroyListener var1);
}

。。。简直就是个宝库啊。里面的中文注释我是照官方英文文档翻译的,有些方法的用途也不太明确,有待大家的发掘。本例中目前只需要两个方法,调用activity()就拿到Host App的Activity。addActivityResultListener设置处理返回结果的回调。代码如下:

// 实现 PluginRegistry.ActivityResultListener
public class FlutterMusicPlugin implements MethodCallHandler, PluginRegistry.ActivityResultListener {

private Activity mActivity;
// 加个构造函数,入参是Activity
private FlutterMusicPlugin(Activity activity) {
// 存起来
mActivity = activity;
}

public static void registerWith(Registrar registrar) {
//传入Activity
final FlutterMusicPlugin plugin = new FlutterMusicPlugin(registrar.activity());

// 注册ActivityResult回调
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) {
// 拿到音频文件uri,开始播放。
play(uri);
} else {
mStateSink.error(“ERROR”, “invalid media file”, null);
}
return true;
}
return false;
}
}

我们改造一下FlutterMusicPlugin, 增加以Activity为入参的构造函数,在静态函数registerWith里实例化的时候传入Host app的Activity。同时注册自身来处理onActivityResult回调。 在onMethodCall方法内"open"下启动第三方选择音频文件的页面。当用户选好了某首歌返回的时候,插件这边就会拿到音频文件uri,并开始播放。

至此,Native端的逻辑就完成了,我们再来看看插件的Flutter端怎么做。

插件Flutter端

IDE在lib目录下会帮你自动生成flutter_music_plugin.dart文件,这个就是插件的Flutter代码所在了,内容比较简单,就是对我们定义好的Platform channels的包装。直接上代码:

typedef void EventHandler(Object event);

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 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);
}
}

插件Example App

除了自身的逻辑之外,一个插件还要有示例应用来演示其API怎么使用,同时,示例应用也是我们开发,调试,验证插件的必备工具。本例中的示例可参考example目录下的main.dart文件。使用插件API的主要逻辑都在State中。简要代码如下

@override
void initState() {
super.initState();
// 在这里注册EventChannles,参数传入响应的回调
FlutterMusicPlugin.listenStatus(_onPlayerStatus, _onPlayerStatusError);
FlutterMusicPlugin.listenPosition(_onPosition, _onPlayerStatusError);
}

// 根据播放状态调用pause或start
void _playPause() {
switch (_status) {
case “started”:
FlutterMusicPlugin.pause();
break;
case “paused”:
case “completed”:
FlutterMusicPlugin.start();
break;
}
}
// 打开媒体文件
void _open() {
FlutterMusicPlugin.open();
}
// MediaPlayer出错事件处理
void _onPlayerStatusError(Object event) {
print(event);
}
// MediaPlayer状态改变事件处理
void _onPlayerStatus(Object event) {
setState(() {
_status = event;
});
if (_status == “started”) {
_getDuration();
}
}
// 获取音频时长
void _getDuration() async {
Duration duration = await FlutterMusicPlugin.getDuration();
setState(() {
_duration = duration;
});
}
// 播放进度事件处理
void _onPosition(Object event) {
Duration position = Duration(milliseconds: event);
setState(() {
_position = position;
});
}

发布

当你的插件开发测试完成以后,你就可以把你的插件发布出去了。 发布之前,先检查pubspec.yaml, README.mdCHANGELOG.md这几个文件的内容是否完整正确。然后运行下面这个命令检查插件是否可以发布。

$ flutter packages pub publish --dry-run

如果有问题存在的话,会在终端输出相关信息,你需要据此做出修改直到返回成功。具体遇到的问题可以参考官方文档

最后去掉--dry-run以后再运行以上命令。

$ flutter packages pub publish

最后

总而言之,成功是留给准备好的人的。无论是参加什么面试,都要做好充足的准备,注意好面试的礼仪和穿着,向面试官表现出自己的热忱与真诚就好。即使最后没有过关,也要做好经验的总结,为下一次面试做好充足准备。

这里我为大家准备了一些我在面试后整理的面试专题资料,除了面试题,还总结出了互联网公司Android程序员面试涉及到的绝大部分面试题及答案,并整理做成了文档,以及系统的进阶学习视频资料,免费分享给大家,希望能帮助到你面试前的复习,且找到一个好的工作,也节省大家在网上搜索资料的时间来学习。

毕竟不管遇到什么样的面试官,去面试首先最主要的就是自己的实力,只要实力够硬,技术够强,就不怕面试拿不到offer!

想要面试顺通嘛,赶紧领取下面的面试资料为之后的面试做足准备叭!这里提前祝各位面试成功!

资料领取方式:  Android架构设计

为什么某些人会一直比你优秀,是因为他本身就很优秀还一直在持续努力变得更优秀,而你是不是还在满足于现状内心在窃喜!希望读到这的您能点个小赞和关注下我,以后还会更新技术干货,谢谢您的支持!

%BD%95%E9%9D%A2%E8%AF%95%E6%8B%BF%E9%AB%98%E8%96%AA%EF%BC%81.md)

[外链图片转存中…(img-bZIBr6LN-1646142202268)]

[外链图片转存中…(img-sZBHkGsZ-1646142202269)]

为什么某些人会一直比你优秀,是因为他本身就很优秀还一直在持续努力变得更优秀,而你是不是还在满足于现状内心在窃喜!希望读到这的您能点个小赞和关注下我,以后还会更新技术干货,谢谢您的支持!

Flutter插件(Plugin)开发 - Android视角,flutter安装视频相关推荐

  1. android flutter 混合开发,Flutter(六)Android与Flutter混合开发(Hybird)

    因为笔者本身主要从事是Android开发,所以很多角度都是作为一个Android开发者学习Flutter的角度出发,IOS或者H5的开发同学可以选择性阅读 目录 前言 如果我们目前的项目是Androi ...

  2. 与Flutter第一次亲密接触-Android 视角

    作者简介 万坤,5年安卓开发经验,16年加入饿了么,现任职饿了么资深安卓开发工程师,负责饿了么物流安卓相关APP线上的高稳定运行. 前言 Flutter在今年6月份发布第一个Release预览版以来, ...

  3. Android插件化开发之运行未安装apk的activity

    1.介绍 我们知道PathClassLoader是一个应用的默认加载器(而且他只能加载data/app/xxx.apk的文件),但是我们加载插件一般使用DexClassLoader加载器,所以这里就有 ...

  4. 【Flutter】开发 Flutter 包和插件 ( Flutter 包和插件简介 | 创建 Flutter 插件 | 创建 Dart 包 )

    文章目录 一.Flutter 包和插件简介 二.创建 Flutter 插件 1.Android Studio 中可视化创建 2.命令行创建 三.创建 Dart 包 1.Android Studio 中 ...

  5. flutter 获取定位_从头开发一个Flutter插件(二)高德地图定位插件

    在上一篇文章从头开发一个Flutter插件(一)开发流程里具体介绍了flutter插件的具体开发流程,从创建项目到发布.接下来将会为Flutter天气项目开发一个基于高德定位sdk的flutter定位 ...

  6. 【Flutter】Flutter 项目中使用 Flutter 插件 ( Flutter 插件管理平台 | 搜索 Flutter 插件 | 安装 Flutter 插件 | 使用 Flutter 插件 )

    文章目录 一.Flutter 包和插件管理平台 二.Flutter 插件搜索示例 三.Flutter 插件装示例 1.添加 Dart 包依赖 2.获取 Dart 包 3.使用 Dart 包 4.官方的 ...

  7. 抖音Flutter插件的使用

    Flutter是一个开源的移动应用程序开发框架,由谷歌开发,支持Android和iOS.随着Flutter的发展和成熟,许多人开始使用它来开发跨平台应用程序.本文将介绍如何使用抖音的Flutter插件 ...

  8. 高德开放平台地图Flutter插件的使用

    高德地图Flutter插件官网 高德地图Flutter插件官网,可根据官网中的定位Flutter插件和地图Flutter插件,实现在flutter项目中实现定位以及地图展示等相关功能. 高德地图Flu ...

  9. 开发Android第一步,安装SDK 1.6, 模拟器及安装游戏

    转自:http://bbs.weiphone.com/read.php?tid=516501 开发Android第一步,安装SDK 1.6, 模拟器及安装游戏 windows 方法 (1) 下载 An ...

最新文章

  1. 使用Vue.js进行数据绑定以及父子组件传值
  2. NND年年回家这么难买火车票
  3. CentOS误删除glibc导致系统系统一系列错误的解决办法
  4. 华为防火墙查看日志命令_防火墙接入互联网方式,到底有哪些呢?5分钟学会防火墙入网...
  5. 如何提高Debug效率
  6. noip复赛批量移动文件夹下的文件
  7. 学习OpenVINO笔记之Inference Engine Device Query API
  8. c语言结构体在内存中的存储,C语言结构体在内存中的存储情况探究------内存对齐...
  9. Java案例:Swing摇奖器
  10. 【故障分析】基于matlab ICA故障监测【含Matlab源码 1590期】
  11. 8,JESD204B协议介绍
  12. 你们让我推荐的营销管理书籍找到了!
  13. Azure Az-900认证 04——-考取AZ900所有知识点总结--获取证书!
  14. 了解前沿信息科技 做好学习就业规划
  15. vue 用webpack打包文件名添加版本号
  16. Matlab实现倒谱法 求 基音频率和共振峰
  17. 如何才能通过一线互联网公司面试?下载量瞬秒百万
  18. nck课程笔记:破解补丁工具的使用
  19. R语言ggplot2可视化:使用patchwork包将两个ggplot2可视化结果组合起来、使用labs函数为第二个子图添加标题信息
  20. json在线编辑(xml转json,json视图,json格式检验,等等)神器

热门文章

  1. 高新技术企业认定条件2023
  2. Apple Pay编程指南(1) - 简介
  3. antd 走马灯案例
  4. 小米airU盘启动正确食用方法
  5. 数据分析技能点-MySQL编程基础
  6. DLL Hell(DLL地狱)浅谈
  7. Debug无忧!清华校友打造Python调试神器
  8. 怎样让自我评价变成简历最出彩的地方?
  9. uin-app md5加密(超简单)
  10. 龙芯linux内核,最新龙芯3A2000/3B2000爆发!Linux内核官方支持