Flutter中与硬件相关的部分,一直都挺蛋疼的。方案基本上有两种,本身写,或者等出相关的库。html
最近作的一个项目中,须要对相机作定制。有过相关模块开发经验的,就知道这种需求并不简单,何况是这种跨平台解决方案的初期。android
需求来了,怎么办呢?那就只能硬着头皮上了。先去pub上找找,有没有可使用的库。初步挑到两个库,一个camera,另外一个是image_picker。ide
image_picker试了下,基本上就pass了,只能调用系统相机或者选择相册,相机相关部分,确定是无法使用。相册部分却是能够拿来使用。this
camera试着运行了下demo,感受这个库可使用,直接将相机预览封装成一个flutter widget。咱们能够很方便的在上面进行各类定制。插件
设计图上须要相机全屏显示,试着在demo上修改为全屏,悲剧出现了,风通常的拉伸效果。添加一个调取相机的页面,在退出相机页面后,demo置后台,切换到前台的时候,Android这边crash了,试了N屡次,100%的crash,我勒个擦,谷歌官方的插件写的这么随意~设计
而后,重点来了,本文主要是解决这两个问题,一个是全屏显示的问题,另外一个则是crash问题
。code
先上一张Android端的拍照效果图:htm
对于这种相机拉伸问题,作过相机定制相关的,都会知道是预览的分辨率选择错误致使的,知道这一点事后,修改起来就简单的多了。直接拉camer plugin的源码,Android的实现,相对仍是比较简单,一个文件700来行代码。找到计算预览尺寸的方法。blog
private void computeBestPreviewAndRecordingSize( StreamConfigurationMap streamConfigurationMap, Size minPreviewSize, Size captureSize) { .... }
考虑到之后camera插件升级的问题,直接单独新建一个文件进行最佳预览尺寸的计算,而后在调用处进行替换便可。生命周期
Android端先后台切换的问题,查看log发现是resume事后崩溃的,直接撸源代码,发现插件监听了Activity的生命周期,在resume的时候进行了open操做。
@Override public void onActivityResumed(Activity activity) { if (requestingPermission) { requestingPermission = false; return; } if (activity == CameraPlugin.this.activity) { if (camera != null) { camera.open(null); } } }
问题来了,关键是,插件没有进行unregister操做,在退出相机页面事后,调用dispose方法,会将camera关闭,而且将cameraDevice置为null,其余生命周期回调中调用cameraDevice的都会crash。onActivityResumed调用camer.open也会crash。这些crash的根本缘由是由于没有将回调unregister掉。了解这些事后,修改起来就简单了,在dispose的时候,将插件的生命周期回调给unregister掉。修改完成后,试下效果,果真都没有crash。
相关代码段我就不贴出来了,关于全屏预览尺寸的计算,网上太多的资料了,将previewSize计算正确便可。第二个crash的问题,添加一个unregisterActivityLifecycleCallbacks便可。对于修改的地方,作好注释,后续升级插件合入的时候不错乱便可。
目前来看Flutter第三方真的不好,若是只是本身我的项目,或者一些偏向于数据展现的项目,能够试一下。可是对于商业项目,尤为是硬件依赖性比较强的,仍是建议一段时间事后再看看。
谷歌官方的camera插件,若是只是本身使用的话,能够按照上面的方法去修改,若是想要用在商业项目上,仍是劝三思。
谷歌官方camera插件Android部分,用的是camera2 API,这个API有什么问题呢?
最后,重写了Android部分,直接采用camera API,支持版本从16开始,彻底没啥问题,对硬件支持也都很是完美。谷歌这个坑埋的有点深,最开始考虑时间因素,结果花在插件上修改分辨率、修改crash、排查特殊机型问题的时间很多。