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、排查特殊機型問題的時間很多。