ndroid笔记:Webview 支持 input type=file选择上传图片

简介:

在一个带有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,如需转载请自行联系原作者

目录
相关文章
|
Android开发 JavaScript 语音技术
|
Android开发
android笔记之在WebView中显示ProgressBar的两种方法
http://blog.csdn.net/liuzhidong123/article/details/6450334 本文基于Creative Commons Attribution 2.5 China Mainland License发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名http://www.cnblogs.com/luminji(包含链接)。
850 0
|
6月前
|
API Android开发 数据安全/隐私保护
解决android webview 加载http url 失败 net::ERR_CLEARTEXT_NOT_PERMITTED 错误
解决android webview 加载http url 失败 net::ERR_CLEARTEXT_NOT_PERMITTED 错误
235 0
|
4月前
|
JavaScript 前端开发 Android开发
android开发,使用kotlin学习WebView(详细)
android开发,使用kotlin学习WebView(详细)
127 0
|
5月前
|
定位技术 Android开发
[√]Android webview的url scheme
[√]Android webview的url scheme
408 0
|
12月前
|
Android开发 iOS开发 UED
Android webView 实现阻尼回弹效果
iOS webView默认滑动到顶部或者底部的时候,还可以继续通过手指拉扯滑动,松手后回弹;而Android webView默认是不行的,要实现跟iOS一样的效果,就需要自定义webView。
358 0
|
6月前
|
JavaScript 前端开发 Android开发
Android AgentWeb WebView 与js交互总结
Android AgentWeb WebView 与js交互总结
182 0
|
8月前
|
JavaScript 前端开发 Android开发
Android 中WebView的使用详解
Android 中WebView的使用详解
235 0
|
10月前
|
前端开发 API 定位技术
Android webview加载https链接错误或无响应
Android webview加载https链接错误或无响应
|
11月前
|
XML 移动开发 数据可视化
每日记录自己的Android项目(二)—Viewbinding,WebView,Navigation
今天是想把做一个跳转页面的时候调到H5页面去,但是这个页面我用app来承载,不要调到浏览器去。
141 0
每日记录自己的Android项目(二)—Viewbinding,WebView,Navigation