webview input說(shuō)明
安卓webview禁用input,網(wǎng)上查看各種方案,都存在弊端。
經(jīng)過(guò)實(shí)踐,完整可用調(diào)研了支持拍照和圖片選擇上傳。
1、webview支持input標(biāo)簽
2、安卓拍照支持適配7.0 takePhoto
1、webview 初始化和銷(xiāo)毀
//webview初始化
@SuppressLint("SetJavaScriptEnabled")
public static void initX5Web(WebView x5Webview) {
Context context = x5Webview.getContext();
WebSettings webSetting = x5Webview.getSettings();
webSetting.setJavaScriptEnabled( true );
webSetting.setAllowFileAccess( true );
webSetting.setLayoutAlgorithm( WebSettings.LayoutAlgorithm.NARROW_COLUMNS );
webSetting.setSupportZoom( false );
webSetting.setBuiltInZoomControls( false );
webSetting.setDisplayZoomControls(false); //不顯示webview縮放按鈕
webSetting.setUseWideViewPort( true );
//多窗口問(wèn)題
webSetting.setSupportMultipleWindows( false );
webSetting.setJavaScriptCanOpenWindowsAutomatically( true );
//h5數(shù)據(jù)存儲(chǔ)
webSetting.setAppCacheEnabled( true );
webSetting.setDomStorageEnabled( true );
webSetting.setDatabaseEnabled(true);
webSetting.setAppCachePath(context.getDir("appcache", 0).getPath());
webSetting.setGeolocationEnabled( true );
webSetting.setAppCacheMaxSize( Long.MAX_VALUE );
webSetting.setDatabasePath(context.getDir("databases", 0).getPath());
webSetting.setGeolocationDatabasePath(context.getDir("geolocation", 0).getPath());
webSetting.setPluginState( WebSettings.PluginState.ON_DEMAND );
webSetting.setRenderPriority( WebSettings.RenderPriority.HIGH );
webSetting.setCacheMode( WebSettings.LOAD_NO_CACHE );
//sonic
x5Webview.removeJavascriptInterface("searchBoxJavaBridge_");
webSetting.setAllowContentAccess(true);
webSetting.setSavePassword(false);
webSetting.setSaveFormData(false);
webSetting.setLoadWithOverviewMode(true);
webSetting.setDefaultTextEncodingName("utf-8");
webSetting.setLoadsImagesAutomatically(true);
}
//webview銷(xiāo)毀方法
public static void onDestroy(WebView mWebView){
if (mWebView != null) {
mWebView.clearHistory();
((ViewGroup) mWebView.getParent()).removeView(mWebView);
mWebView.loadUrl("about:blank");
mWebView.stopLoading();
mWebView.setWebChromeClient(null);
mWebView.setWebViewClient(null);
mWebView.loadDataWithBaseURL(null, "", "text/html", "utf-8", null);
mWebView.clearHistory();
mWebView.destroy();
}
}
2、webchrome特別支持
- 1、 initWebChrome
//webview input 特別支持幫助類(lèi)
private WebViewUploadFileHelper helper = new WebViewUploadFileHelper(this);
private void initWebChrome() {
webview.setWebChromeClient( new InputFileWebChromeClient() );
}
public class InputFileWebChromeClient extends WebChromeClient {
//設(shè)置 進(jìn)度條
@Override
public void onProgressChanged(WebView view, int newProgress) {
super.onProgressChanged( view, newProgress );
}
// For Android < 3.0
public void openFileChooser(ValueCallback<Uri> uploadMsg) {
helper.setUploadMessage( uploadMsg );
permission( () -> {
helper.openImageActivity();
} );
}
// For Android 3.0+
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType) {
helper.setUploadMessage( uploadMsg );
permission( () -> {
helper.openImageActivity( acceptType );
} );
}
// For Android > 4.1.1
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
helper.setUploadMessage( uploadMsg );
permission( () -> {
helper.openImageActivity( acceptType, capture );
} );
}
// For Android >= 5.0
public boolean onShowFileChooser(com.tencent.smtt.sdk.WebView webView,
ValueCallback<Uri[]> filePathCallback,
WebChromeClient.FileChooserParams fileChooserParams) {
helper.setUploadMessageAboveL( filePathCallback );
permission( () -> {
helper.openImageActivity( fileChooserParams.getAcceptTypes(), fileChooserParams.isCaptureEnabled() );
} );
return true;
}
//==多窗口的問(wèn)題
@Override
public boolean onCreateWindow(WebView view, boolean isDialog,
boolean isUserGesture, Message resultMsg) {
WebView.WebViewTransport transport = (WebView.WebViewTransport) resultMsg.obj;
transport.setWebView( view );
resultMsg.sendToTarget();
return true;
}
}
- 2 、回調(diào)
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
//回調(diào)支持
super.onActivityResult(requestCode, resultCode, data);
helper.onActivityResult(requestCode, resultCode, data);
}
- 3 、權(quán)限
@SuppressLint("CheckResult")
public void permission(CallBack callBack){
// 權(quán)限支持
RxPermissions rxPermissions = new RxPermissions( this );
rxPermissions.request(Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE)
.subscribe(grant -> {
if (grant) {
//全部通過(guò)
try {
if (callBack!=null){
callBack.onSucess();
}
} catch (Throwable throwable) {
throwable.printStackTrace();
}
} else {
ToastUtils.show("請(qǐng)同意權(quán)限");
}
});
}
public interface CallBack{
void onSucess();
}
3、WebViewUploadFileHelper 幫助類(lèi)
將input相關(guān)方法封裝在一個(gè)幫助類(lèi)中,便于多處復(fù)用
public class WebViewUploadFileHelper {
private ValueCallback<Uri> uploadMessage;
private ValueCallback<Uri[]> uploadMessageAboveL;
private final static int FILE_CHOOSER_RESULT_CODE = 10011;//文件選擇
private Uri imageUri;
private Activity activity;
private WebViewUploadFileHelper() {
}
public WebViewUploadFileHelper(Activity activity) {
this.activity = activity;
}
public void setUploadMessage(ValueCallback<Uri> uploadMessage) {
this.uploadMessage = uploadMessage;
}
public void setUploadMessageAboveL(ValueCallback<Uri[]> uploadMessageAboveL) {
this.uploadMessageAboveL = uploadMessageAboveL;
}
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode != FILE_CHOOSER_RESULT_CODE) return;
// 經(jīng)過(guò)上邊(1)、(2)兩個(gè)賦值操作,此處即可根據(jù)其值是否為空來(lái)決定采用哪種處理方法
if (uploadMessage != null) {
chooseBelow( resultCode, data );
} else if (uploadMessageAboveL != null) {
chooseAbove( resultCode, data );
}
}
public void openImageActivity() {
chooseImage( "image/*" );
}
public void openImageActivity(String acceptType) {
chooseImage( acceptType );
}
public void openImageActivity(String acceptType, String capture) {
if (StringUtils.equals( capture, "camera" )) {
takePhoto();
} else {
chooseImage( acceptType );
}
}
public void openImageActivity(String[] acceptType, boolean isCaptureEnabled) {
if (isCaptureEnabled) {
takePhoto();
} else {
chooseImage( acceptType );
}
}
private void chooseBelow(int resultCode, Intent data) {
if (RESULT_OK == resultCode) {
updatePhotos();
if (data != null) {
// 這里是針對(duì)文件路徑處理
Uri uri = data.getData();
if (uri != null) {
uploadMessage.onReceiveValue( uri );
} else {
uploadMessage.onReceiveValue( null );
}
} else {
// 以指定圖像存儲(chǔ)路徑的方式調(diào)起相機(jī),成功后返回data為空
uploadMessage.onReceiveValue( imageUri );
}
} else {
uploadMessage.onReceiveValue( null );
}
uploadMessage = null;
}
private void chooseAbove(int resultCode, Intent data) {
if (RESULT_OK == resultCode) {
updatePhotos();
if (data != null) {
// 這里是針對(duì)從文件中選圖片的處理
Uri[] results;
Uri uriData = data.getData();
if (uriData != null) {
results = new Uri[]{uriData};
uploadMessageAboveL.onReceiveValue( results );
} else {
uploadMessageAboveL.onReceiveValue( null );
}
} else {
uploadMessageAboveL.onReceiveValue( new Uri[]{imageUri} );
}
} else {
uploadMessageAboveL.onReceiveValue( null );
}
uploadMessageAboveL = null;
}
private void updatePhotos() {
// 該廣播即使多發(fā)(即選取照片成功時(shí)也發(fā)送)也沒(méi)有關(guān)系,只是喚醒系統(tǒng)刷新媒體文件
Intent intent = new Intent( Intent.ACTION_MEDIA_SCANNER_SCAN_FILE );
intent.setData( imageUri );
activity.sendBroadcast( intent );
}
//調(diào)用相機(jī)
private void takePhoto() {
String fileName = "IMG_" + DateFormat.format( "yyyyMMdd_hhmmss", Calendar.getInstance( Locale.CHINA ) ) + ".jpg";
// 步驟一:創(chuàng)建存儲(chǔ)照片的文件
String imagePath = activity.getFilesDir() + File.separator + "images" + File.separator + fileName;
File file = new File( imagePath );
//創(chuàng)建文件夾
if (!file.getParentFile().exists())
file.getParentFile().mkdirs();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
//步驟二:Android 7.0及以上獲取文件 Uri
imageUri = FileProvider.getUriForFile( activity, activity.getPackageName() + ".fileprovider", file );
} else {
//步驟三:獲取文件Uri
imageUri = Uri.fromFile( file );
}
Intent intent = new Intent();
intent.addFlags( Intent.FLAG_GRANT_READ_URI_PERMISSION );
intent.setAction( MediaStore.ACTION_IMAGE_CAPTURE );//設(shè)置Action為拍照
intent.putExtra( MediaStore.EXTRA_OUTPUT, imageUri );//將拍取的照片保存到指定URI
activity.startActivityForResult( intent, FILE_CHOOSER_RESULT_CODE );
}
//圖片選擇器
private void chooseImage(String[] acceptType) {
Intent i = new Intent( Intent.ACTION_GET_CONTENT );
i.addCategory( Intent.CATEGORY_OPENABLE );
i.setType( "*/*" );
i.putExtra( Intent.EXTRA_MIME_TYPES, acceptType );
activity.startActivityForResult( i, FILE_CHOOSER_RESULT_CODE );
}
//圖片選擇器
private void chooseImage(String acceptType) {
Intent i = new Intent( Intent.ACTION_GET_CONTENT );
i.addCategory( Intent.CATEGORY_OPENABLE );
if (TextUtils.isEmpty( acceptType )) {
i.setType( "*/*" );
} else {
i.setType( acceptType );
}
activity.startActivityForResult( Intent.createChooser( i, "Image Chooser" ), FILE_CHOOSER_RESULT_CODE );
}
}