最近做了需要实现一个小功能,在安卓的离线数据录入程序中,要支持文件的的上传。简单而言,就是在一个webview包装起来的离线的Web
App中,通过input[type=file]的指定需要上传的文件,然后点击保存按钮的时候将数据先保存到本地(因为是离线状态),然后当网络连通的时候再将数据和文件一起上传到服务器。由于程序主要操作界面是一个类似于phonegap封装的纯JS的Web
APP,所以基本上限定了文件的选择获取只能通过input[type=file]来。并且由于一般安卓的手机或者平台都是支持相机的,所以我手欠的加了一个便捷的功能:点击input[type=file]时直接从相机照相然后保存数据的功能。这就是这一趟受罪的开始。
一般来说,实现这种功能,都是在webview的WebChromeClient中覆盖掉openFileChooser方法,打开文件选择,网上一般流传的都市从安卓系统的浏览器源代码里抄出来的这一套:
public void
openFileChooser(ValueCallback uploadMsg) {
openFileChooser(uploadMsg,
"**");
Intent chooser =
createChooserIntent(createCameraIntent());
chooser.putExtra(Intent.EXTRA_INTENT,
i);
((Activity)
ctx).startActivityForResult(chooser, 5173);
}
public ValueCallback
getValueCallback() {
return
this.mUploadMessage;
}
private Intent
createChooserIntent(Intent... intents) {
Intent chooser = new
Intent(Intent.ACTION_CHOOSER);
chooser.putExtra(Intent.EXTRA_INITIAL_INTENTS,
intents);
chooser.putExtra(Intent.EXTRA_TITLE,
ctx.getString(R.string.FileBrowser));
return chooser;
}
private Intent
createCameraIntent() {
Intent cameraIntent = new
Intent(MediaStore.ACTION_IMAGE_CAPTURE);
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT,
Uri.fromFile(new File(imageFilePath)));
return cameraIntent;
}
除此之外就是在Activity的onActivityResult的方法中判断如果是从相机来就直接从图像路径取图而不是从Intent里取数据。
但是很不幸的是,这套代码在安卓2.2/2.3上是不能实现从相机照相然后传到input[type=file]上的,file控件总是显示空白。各种奇异的情况总是让人莫名的很抓狂。
由于功能要的紧,我头一个晚上弄的晚上4点都没找到解决的办法。这个似乎就是webview的限制。于是第二天一早起来接着看,就连stackoverflow上都一帮人说没办法解决,我差点就直接放弃了。静下心来一想,为什么直接从图片库中选择的图片能够在file控件中正确的显示而就只文件的不行呢?难道就是因为WebView不支持file://格式的Uri而仅仅只支持content格式的Uri?
于是我傻乎的又去把android的java部分的源代码弄下来,可问题是居然部分的实现都是native的代码,在系统自带的浏览器里是把uri和文件路径的映射存在了BrowserFrame的一个hashmap里,似乎在Java这一层和Webview的file控件的联系就这么直接的断了。
于是又换一个方向,既然webView不支持file://格式的Uri,那我为何不将file://格式的Uri转换成content://格式的Uri呢?于是又是一番搜索,两行代码就搞定了这个事情:
String media
=MediaStore.Images.Media.insertImage(getContentResolver(),filepath,"","");
result = Uri.parse(media);
mUploadMessage.onReceiveValue(result);
总之,在人类这个世界上写程序,面对很多莫名其妙的问题时,如果变通一下一小部分的问题还是能解决的。希望下次我碰到的还是这种能解决的小疑难。呵呵呵。