前言
最近有人来跟我要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.