Flutter中與硬件相關(guān)的部分,一直都挺蛋疼的。方案基本上有兩種,自己寫,或者等出相關(guān)的庫。
最近做的一個(gè)項(xiàng)目中,需要對(duì)相機(jī)做定制。有過相關(guān)模塊開發(fā)經(jīng)驗(yàn)的,就知道這種需求并不簡(jiǎn)單,況且是這種跨平臺(tái)解決方案的初期。
需求來了,怎么辦呢?那就只能硬著頭皮上了。先去pub上找找,有沒有可以使用的庫。初步挑到兩個(gè)庫,一個(gè)camera,另一個(gè)是image_picker。
image_picker試了下,基本上就pass了,只能調(diào)用系統(tǒng)相機(jī)或者選擇相冊(cè),相機(jī)相關(guān)部分,肯定是沒法使用。相冊(cè)部分倒是可以拿來使用。
camera試著運(yùn)行了下demo,感覺這個(gè)庫可以使用,直接將相機(jī)預(yù)覽封裝成一個(gè)flutter widget。我們可以很方便的在上面進(jìn)行各種定制。
設(shè)計(jì)圖上需要相機(jī)全屏顯示,試著在demo上修改成全屏,悲劇出現(xiàn)了,風(fēng)一般的拉伸效果。添加一個(gè)調(diào)取相機(jī)的頁面,在退出相機(jī)頁面后,demo置后臺(tái),切換到前臺(tái)的時(shí)候,Android這邊crash了,試了N多次,100%的crash,我勒個(gè)擦,谷歌官方的插件寫的這么隨意~
然后,重點(diǎn)來了,本文主要是解決這兩個(gè)問題,一個(gè)是全屏顯示的問題,另一個(gè)則是crash問題。
先上一張Android端的拍照效果圖:

Android端全屏拉伸問題
對(duì)于這種相機(jī)拉伸問題,做過相機(jī)定制相關(guān)的,都會(huì)知道是預(yù)覽的分辨率選擇錯(cuò)誤導(dǎo)致的,知道這一點(diǎn)過后,修改起來就簡(jiǎn)單的多了。直接拉camer plugin的源碼,Android的實(shí)現(xiàn),相對(duì)還是比較簡(jiǎn)單,一個(gè)文件700來行代碼。找到計(jì)算預(yù)覽尺寸的方法。
private void computeBestPreviewAndRecordingSize(
StreamConfigurationMap streamConfigurationMap, Size minPreviewSize, Size captureSize) {
....
}
考慮到以后camera插件升級(jí)的問題,直接單獨(dú)新建一個(gè)文件進(jìn)行最佳預(yù)覽尺寸的計(jì)算,然后在調(diào)用處進(jìn)行替換即可。
Android端前后臺(tái)切換必現(xiàn)crash問題
Android端前后臺(tái)切換的問題,查看log發(fā)現(xiàn)是resume過后崩潰的,直接擼源代碼,發(fā)現(xiàn)插件監(jiān)聽了Activity的生命周期,在resume的時(shí)候進(jìn)行了open操作。
@Override
public void onActivityResumed(Activity activity) {
if (requestingPermission) {
requestingPermission = false;
return;
}
if (activity == CameraPlugin.this.activity) {
if (camera != null) {
camera.open(null);
}
}
}
問題來了,關(guān)鍵是,插件沒有進(jìn)行unregister操作,在退出相機(jī)頁面過后,調(diào)用dispose方法,會(huì)將camera關(guān)閉,并且將cameraDevice置為null,其他生命周期回調(diào)中調(diào)用cameraDevice的都會(huì)crash。onActivityResumed調(diào)用camer.open也會(huì)crash。這些crash的根本原因是因?yàn)闆]有將回調(diào)unregister掉。了解這些過后,修改起來就簡(jiǎn)單了,在dispose的時(shí)候,將插件的生命周期回調(diào)給unregister掉。修改完成后,試下效果,果然都沒有crash。
后話
相關(guān)代碼段我就不貼出來了,關(guān)于全屏預(yù)覽尺寸的計(jì)算,網(wǎng)上太多的資料了,將previewSize計(jì)算正確即可。第二個(gè)crash的問題,添加一個(gè)unregisterActivityLifecycleCallbacks即可。對(duì)于修改的地方,做好注釋,后續(xù)升級(jí)插件合入的時(shí)候不錯(cuò)亂即可。
目前來看Flutter第三方真的很差,如果只是自己個(gè)人項(xiàng)目,或者一些偏向于數(shù)據(jù)展示的項(xiàng)目,可以試一下。但是對(duì)于商業(yè)項(xiàng)目,尤其是硬件依賴性比較強(qiáng)的,還是建議一段時(shí)間過后再看看。
大后話
谷歌官方的camera插件,如果只是自己使用的話,可以按照上面的方法去修改,如果想要用在商業(yè)項(xiàng)目上,還是勸三思。
谷歌官方camera插件Android部分,用的是camera2 API,這個(gè)API有什么問題呢?
- 從21開始支持,也就是說需要放棄百分之十幾的份額;
- 上面版本不是最坑的,最坑的是什么呢?硬件廠商對(duì)camera2的支持程度,遇到幾臺(tái)機(jī)子,對(duì)camera2支持非常差,這些機(jī)子還是近一年比較新的機(jī)子(vivo x20a),獲取到的最大預(yù)覽分辨率非常低,拍出來的圖片尺寸也對(duì)不上。
最后,重寫了Android部分,直接采用camera API,支持版本從16開始,完全沒啥問題,對(duì)硬件支持也都非常完美。谷歌這個(gè)坑埋的有點(diǎn)深,最開始考慮時(shí)間因素,結(jié)果花在插件上修改分辨率、修改crash、排查特殊機(jī)型問題的時(shí)間不少。