博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
ndroid笔记:Webview 支持 input type=file选择上传图片
阅读量:5749 次
发布时间:2019-06-18

本文共 9590 字,大约阅读时间需要 31 分钟。

在一个带有input tpye=file标签的Html页面,通过WebView,上传android手机上的图片,发现不工作。(在Ios和微信上完全正常工作)所以,需要研究一下Android的WebView,来支持type=file的标签。

WebView设置WebChromeClient

重写WebChromeClient中关于文件选择的方法,onShowFileChooser和openFileChooser。(项目中只需要选择图片,所以加上了图片过滤。)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
public 
static 
final 
int 
INPUT_FILE_REQUEST_CODE = 
1
;
private 
ValueCallback<Uri> mUploadMessage;
private 
final 
static 
int 
FILECHOOSER_RESULTCODE = 
2
;
private 
ValueCallback<Uri[]> mFilePathCallback;
 
private 
String mCameraPhotoPath;
private 
WebChromeClient mWebChromeClient = 
new 
WebChromeClient() {
 
   
// android 5.0
   
public 
boolean 
onShowFileChooser(
         
WebView webView, ValueCallback<Uri[]> filePathCallback,
         
WebChromeClient.FileChooserParams fileChooserParams) {
      
if 
(mFilePathCallback != 
null
) {
         
mFilePathCallback.onReceiveValue(
null
);
      
}
      
mFilePathCallback = filePathCallback;
 
      
Intent takePictureIntent = 
new 
Intent(MediaStore.ACTION_IMAGE_CAPTURE);
      
if 
(takePictureIntent.resolveActivity(getPackageManager()) != 
null
) {
         
// Create the File where the photo should go
         
File photoFile = 
null
;
         
try 
{
            
photoFile = createImageFile();
            
takePictureIntent.putExtra(
"PhotoPath"
, mCameraPhotoPath);
         
catch 
(IOException ex) {
            
// Error occurred while creating the File
            
Log.e(
"WebViewSetting"
"Unable to create Image File"
, ex);
         
}
 
         
// Continue only if the File was successfully created
         
if 
(photoFile != 
null
) {
            
mCameraPhotoPath = 
"file:" 
+ photoFile.getAbsolutePath();
            
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT,
                  
Uri.fromFile(photoFile));
         
else 
{
            
takePictureIntent = 
null
;
         
}
      
}
 
      
Intent contentSelectionIntent = 
new 
Intent(Intent.ACTION_GET_CONTENT);
      
contentSelectionIntent.addCategory(Intent.CATEGORY_OPENABLE);
      
contentSelectionIntent.setType(
"image/*"
);
 
      
Intent[] intentArray;
      
if 
(takePictureIntent != 
null
) {
         
intentArray = 
new 
Intent[]{takePictureIntent};
      
else 
{
         
intentArray = 
new 
Intent[
0
];
      
}
 
      
Intent chooserIntent = 
new 
Intent(Intent.ACTION_CHOOSER);
      
chooserIntent.putExtra(Intent.EXTRA_INTENT, contentSelectionIntent);
      
chooserIntent.putExtra(Intent.EXTRA_TITLE, 
"Image Chooser"
);
      
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentArray);
 
      
startActivityForResult(chooserIntent, INPUT_FILE_REQUEST_CODE);
 
      
return 
true
;
   
}
 
   
//The undocumented magic method override
   
//Eclipse will swear at you if you try to put @Override here
   
// For Android 3.0+
   
public 
void 
openFileChooser(ValueCallback<Uri> uploadMsg) {
 
      
mUploadMessage = uploadMsg;
      
Intent i = 
new 
Intent(Intent.ACTION_GET_CONTENT);
      
i.addCategory(Intent.CATEGORY_OPENABLE);
      
i.setType(
"image/*"
);
      
WebViewActivity.
this
.startActivityForResult(Intent.createChooser(i, 
"Image Chooser"
), FILECHOOSER_RESULTCODE);
 
   
}
 
   
// For Android 3.0+
   
public 
void 
openFileChooser(ValueCallback uploadMsg, String acceptType) {
      
mUploadMessage = uploadMsg;
      
Intent i = 
new 
Intent(Intent.ACTION_GET_CONTENT);
      
i.addCategory(Intent.CATEGORY_OPENABLE);
      
i.setType(
"image/*"
);
      
WebViewActivity.
this
.startActivityForResult(
            
Intent.createChooser(i, 
"Image Chooser"
),
            
FILECHOOSER_RESULTCODE);
   
}
 
   
//For Android 4.1
   
public 
void 
openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
      
mUploadMessage = uploadMsg;
      
Intent i = 
new 
Intent(Intent.ACTION_GET_CONTENT);
      
i.addCategory(Intent.CATEGORY_OPENABLE);
      
i.setType(
"image/*"
);
      
WebViewActivity.
this
.startActivityForResult(Intent.createChooser(i, 
"Image Chooser"
), WebViewActivity.FILECHOOSER_RESULTCODE);
 
   
}
};

选择结果的回调

在onActivityResult中获取对应的选取文件的返回结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
public 
void 
onActivityResult(
int 
requestCode, 
int 
resultCode, Intent data) {
   
if 
(requestCode == FILECHOOSER_RESULTCODE) {
      
if 
(
null 
== mUploadMessage) 
return
;
      
Uri result = data == 
null 
|| resultCode != RESULT_OK ? 
null
            
: data.getData();
      
if 
(result != 
null
) {
         
String imagePath = ImageFilePath.getPath(
this
, result);
         
if 
(!StrUtils.isEmpty(imagePath)) {
            
result = Uri.parse(
"file:///" 
+ imagePath);
         
}
      
}
      
mUploadMessage.onReceiveValue(result);
      
mUploadMessage = 
null
;
   
else 
if 
(requestCode == INPUT_FILE_REQUEST_CODE && mFilePathCallback != 
null
) {
      
// 5.0的回调
      
Uri[] results = 
null
;
 
      
// Check that the response is a good one
      
if 
(resultCode == Activity.RESULT_OK) {
         
if 
(data == 
null
) {
            
// If there is not data, then we may have taken a photo
            
if 
(mCameraPhotoPath != 
null
) {
               
Logger.d(
"camera_photo_path"
, mCameraPhotoPath);
               
results = 
new 
Uri[]{Uri.parse(mCameraPhotoPath)};
            
}
         
else 
{
            
String dataString = data.getDataString();
            
Logger.d(
"camera_dataString"
, dataString);
            
if 
(dataString != 
null
) {
               
results = 
new 
Uri[]{Uri.parse(dataString)};
            
}
         
}
      
}
 
      
mFilePathCallback.onReceiveValue(results);
      
mFilePathCallback = 
null
;
   
else 
{
      
super
.onActivityResult(requestCode, resultCode, data);
      
return
;
   
}
}

文件路径的获取

返回文件的解析,因为html页面需要的是文件,所以客户端需要返回的是对应文件的路径。这样,就会存在一个问题,在Android 4.4上,通过文件选择返回的结果都是对应以content开头格式的对应的路径。这就得需要咱们来进行判断,最终都需要转回成以file开头对应的格式文件。下面,我封装成了一个ImageFilePath的类,通过调用getPath方法来获取最终的结果。这个类的方法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
/**
 
* Method for return file path of Gallery image
 
*
 
* @param context
 
* @param uri
 
* @return path of the selected image file from gallery
 
*/
public 
static 
String getPath(
final 
Context context, 
final 
Uri uri) {
 
   
// check here to KITKAT or new version
   
final 
boolean 
isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
 
   
// DocumentProvider
   
if 
(isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
 
      
// ExternalStorageProvider
      
if 
(isExternalStorageDocument(uri)) {
         
final 
String docId = DocumentsContract.getDocumentId(uri);
         
final 
String[] split = docId.split(
":"
);
         
final 
String type = split[
0
];
 
         
if 
(
"primary"
.equalsIgnoreCase(type)) {
            
return 
Environment.getExternalStorageDirectory() + 
"/"
                  
+ split[
1
];
         
}
      
}
      
// DownloadsProvider
      
else 
if 
(isDownloadsDocument(uri)) {
 
         
final 
String id = DocumentsContract.getDocumentId(uri);
         
final 
Uri contentUri = ContentUris.withAppendedId(
               
Uri.parse(
"content://downloads/public_downloads"
),
               
Long.valueOf(id));
 
         
return 
getDataColumn(context, contentUri, 
null
null
);
      
}
      
// MediaProvider
      
else 
if 
(isMediaDocument(uri)) {
         
final 
String docId = DocumentsContract.getDocumentId(uri);
         
final 
String[] split = docId.split(
":"
);
         
final 
String type = split[
0
];
 
         
Uri contentUri = 
null
;
         
if 
(
"image"
.equals(type)) {
            
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
         
else 
if 
(
"video"
.equals(type)) {
            
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
         
else 
if 
(
"audio"
.equals(type)) {
            
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
         
}
 
         
final 
String selection = 
"_id=?"
;
         
final 
String[] selectionArgs = 
new 
String[] { split[
1
] };
 
         
return 
getDataColumn(context, contentUri, selection,
               
selectionArgs);
      
}
   
}
   
// MediaStore (and general)
   
else 
if 
(
"content"
.equalsIgnoreCase(uri.getScheme())) {
 
      
// Return the remote address
      
if 
(isGooglePhotosUri(uri))
         
return 
uri.getLastPathSegment();
 
      
return 
getDataColumn(context, uri, 
null
null
);
   
}
   
// File
   
else 
if 
(
"file"
.equalsIgnoreCase(uri.getScheme())) {
      
return 
uri.getPath();
   
}
 
   
return 
null
;
}
 
/**
 
* Get the value of the data column for this Uri. This is useful for
 
* MediaStore Uris, and other file-based ContentProviders.
 
*
 
* @param context
 
*            The context.
 
* @param uri
 
*            The Uri to query.
 
* @param selection
 
*            (Optional) Filter used in the query.
 
* @param selectionArgs
 
*            (Optional) Selection arguments used in the query.
 
* @return The value of the _data column, which is typically a file path.
 
*/
public 
static 
String getDataColumn(Context context, Uri uri,
                           
String selection, String[] selectionArgs) {
 
   
Cursor cursor = 
null
;
   
final 
String column = 
"_data"
;
   
final 
String[] projection = { column };
 
   
try 
{
      
cursor = context.getContentResolver().query(uri, projection,
            
selection, selectionArgs, 
null
);
      
if 
(cursor != 
null 
&& cursor.moveToFirst()) {
         
final 
int 
index = cursor.getColumnIndexOrThrow(column);
         
return 
cursor.getString(index);
      
}
   
finally 
{
      
if 
(cursor != 
null
)
         
cursor.close();
   
}
   
return 
null
;
}
 
/**
 
* @param uri
 
*            The Uri to check.
 
* @return Whether the Uri authority is ExternalStorageProvider.
 
*/
public 
static 
boolean 
isExternalStorageDocument(Uri uri) {
   
return 
"com.android.externalstorage.documents"
.equals(uri
         
.getAuthority());
}
 
/**
 
* @param uri
 
*            The Uri to check.
 
* @return Whether the Uri authority is DownloadsProvider.
 
*/
public 
static 
boolean 
isDownloadsDocument(Uri uri) {
   
return 
"com.android.providers.downloads.documents"
.equals(uri
         
.getAuthority());
}
 
/**
 
* @param uri
 
*            The Uri to check.
 
* @return Whether the Uri authority is MediaProvider.
 
*/
public 
static 
boolean 
isMediaDocument(Uri uri) {
   
return 
"com.android.providers.media.documents"
.equals(uri
         
.getAuthority());
}
 
/**
 
* @param uri
 
*            The Uri to check.
 
* @return Whether the Uri authority is Google Photos.
 
*/
public 
static 
boolean 
isGooglePhotosUri(Uri uri) {
   
return 
"com.google.android.apps.photos.content"
.equals(uri
         
.getAuthority());
}

本文转自 glblong 51CTO博客,原文链接:http://blog.51cto.com/glblong/1726034,如需转载请自行联系原作者
你可能感兴趣的文章
zyqn7000上启动linux
查看>>
FileReader在ios上面的坑(图片转base64)
查看>>
微软浏览器再曝新漏洞 最新版IE8未能幸免
查看>>
一起谈.NET技术,从数据到代码—通过代码生成机制实现强类型编程[上篇]
查看>>
udp回显客户端发送的数据
查看>>
三生零基础大白菜自动重装系统教程
查看>>
阿里云ECS部署ES
查看>>
第二冲刺阶段第十四天
查看>>
mongodb指南
查看>>
JBPM (四) 浅析JBPM中的实例变量和任务变量
查看>>
tensorflow 卷积层
查看>>
Jmeter基础之---jmeter基础概念
查看>>
hello Kotlin!
查看>>
restful api php设计
查看>>
python中sys模块的argv
查看>>
C/S架构ClickOnce发布的程序,外部启动程序并传递参数
查看>>
day43-2 UDP协议套接字变成,socketserver实现高并发
查看>>
Debug输出mybatis语句
查看>>
Grub4dos boot
查看>>
ADT升级到最新v20后键盘和模拟键盘均失效解决办法
查看>>