前言
最近有人來跟我要android的圖片選擇demo,而且需要將選擇結果回調給web.雖然這個功能在好久以前做過,但是在這次重寫的時候,發現很多東西都不太一樣了,例如以前使用的圖片選擇框架PhotoPicker現在沒有維護的,推薦了一個知乎的圖片選擇Matisse.
先說說傳給web的方案,demo中由於沒有服務器交互,所以回將選擇好的圖片轉換成base64字符串,通過jsb傳給web,這種方案在一些小圖選擇的情況下非常常見,但也有一定的弊端,這個在最後就給出修改建議.
demo工程:https://github.com/lewis-v/ImageSelect
選擇圖片
manifest中添加
<activity
android:name="com.yalantis.ucrop.UCropActivity"
android:screenOrientation="portrait"
android:theme="@style/Theme.AppCompat.Light.NoActionBar" />
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.lewis.imageselect"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepaths"/>
</provider>
res目錄中添加xml目錄,創建文件filepaths.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<paths>
<external-path
name="my_images"
path="Pictures"/>
</paths>
</resources>
activity中的初始化操作
private val imageViewModel by lazy {
ViewModelProvider(
this,
ViewModelProvider.AndroidViewModelFactory.getInstance(application)
).get(ImageViewModel::class.java)
}
override fun onCreate(savedInstanceState: Bundle?) {
imageViewModel.imageErrorLiveData.observe(this, Observer {
Toast.makeText(this, it, Toast.LENGTH_SHORT).show()
})
imageViewModel.imageSelectResultViewModel.observe(this, Observer {
//圖片選擇結果
Toast.makeText(this, "select success ${it.size}", Toast.LENGTH_SHORT).show()
})
}
//權限處理
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (permissions.isNotEmpty()) {
imageViewModel.selectImage(this)
}
}
//選擇回調
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
imageViewModel.onResult(this, requestCode, resultCode, data)
}
選擇圖片調用
if (PermissionUtil.checkAllPermission(this)) {
//選擇一張圖片,不裁剪
imageViewModel.selectImage(this, 1, null, ImageCompressionInfo())
}
if (PermissionUtil.checkAllPermission(this)) {
//選擇1張圖片,裁剪
imageViewModel.selectImage(this, 1, ImageCropInfo(), ImageCompressionInfo())
}
到此,圖片選擇的初始化和調用就完成的,具體的實現在ImageViewModel中.
回調給web
ImageJsbModul類中提供了jsb的方法調用
初始化
override fun onCreate(savedInstanceState: Bundle?) {
imageJsbModul = ImageJsbModul(this, web)
webView.addJavascriptInterface(imageJsbModul, "ImageSelect")//將jsb方法加入到js中
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (permissions.isNotEmpty()) {
imageJsbModul.onGetPermission()
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
imageViewModel.onResult(this, requestCode, resultCode, data)
}
網頁調用圖片選擇的方法,在asset的js_webView.html有示例
window.ImageSelect.selectImage(num, '{"ratio":{"x":16.0,"y":9.0}}',true,"callBack");
//其中第一個參數num爲選擇圖片數量,
//第二個參數爲裁剪的配置(支持裁剪比例和大小)
//第三個參數爲是否壓縮
//第四個參數是選擇結果的回調方法
最後
圖片選擇到這裏結束啦,其實也沒什麼複雜的,就只是將各種框架結合在一起封裝一下就完事了(具體實現可見工程demo源碼, 主要的實現在ImageJsbModul和ImageViewModel中),但是這裏也有一些細節是沒有考慮的,例如在不保留活動下,選擇完圖片回來是否有問題等
建議
jsb的回調方式是將圖片轉成base64的形式,這裏最好不要這樣做,因爲文件轉成base64之後會很大,這裏會佔用很多內存,當然如果只是一張小頭像問題到不是很大,最好的做法是將選擇好的圖片上傳到服務器,將圖片鏈接傳給web.