(Transferir) Los escollos encontrados al cargar imágenes en WebView de Android 5.0 y sistemas superiores

Dirección original: las trampas encontradas al cargar imágenes en WebView de Android 5.0 y superior Systems_fuzhongbin's Blog-CSDN Blog

En el proyecto anterior, había una operación de carga de archivos en WebView (llamando al álbum del sistema para seleccionar fotos para cargar), cuando hacemos clic en el control para seleccionar archivos en la página web

(<input type="file">), devolverá la llamada a openFileChoose() en WebChromeClient; (los sistemas 5.0 y superiores aparecerán en ShowFileChooser()). este

Cuando usamos el Intent para abrir el álbum del sistema o la aplicación de terceros que admite el Intent para seleccionar la imagen en estos dos métodos. El siguiente código:
 

public void openFileChooser(ValueCallback<Uri> valueCallback, String acceptType, String capture) {
    uploadMessage = valueCallback;
    openImageChooserActivity();
}
 
private void openImageChooserActivity() {
    Intent i = new Intent(Intent.ACTION_GET_CONTENT);
    i.addCategory(Intent.CATEGORY_OPENABLE);
    i.setType("image/*");
    startActivityForResult(Intent.createChooser(i, 
                "Image Chooser"), FILE_CHOOSER_RESULT_CODE);
}

Finalmente, devolvemos el contenido de la imagen seleccionada a WebView a través del método onReceiveValue de ValueCallback en onActivityForResult(), y luego pasamos Js

subir. el código se muestra a continuación:,

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == FILE_CHOOSER_RESULT_CODE) {
        Uri result = data == null || resultCode != RESULT_OK ? null : data.getData();
        if (uploadMessage != null) {
            uploadMessage.onReceiveValue(result);
            uploadMessage = null;
        }
    }
}

El componente WebView nos proporciona VauleCallback a través de openFileChooser() o onShowFileChooser(), que contiene uno o un conjunto de
Uri, y luego pasamos el Uri al método onReceiveValue() de ValueCallback en onActivityResult(), para que WebView sepa lo que elegimos

documento.

Muchos sistemas por encima de 5.0 no pueden usar el método openFileChooser() para invocar el álbum del sistema o la aplicación de terceros para seleccionar imágenes, por lo que debe reescribirse por encima de 5.0

onShowFileChooser(), por lo que para resolver este problema y ser compatible con varias versiones, necesitamos sobrecargar openFileChooser(), y al mismo tiempo para los sistemas 5.0 y superiores

Proporcione el método onShowFileChooser():


 

webview.setWebChromeClient(new WebChromeClient() {
 
        // For Android < 3.0
        public void openFileChooser(ValueCallback<Uri> valueCallback) {
            ***
        }
 
        // For Android  >= 3.0
        public void openFileChooser(ValueCallback valueCallback, String acceptType) {
            ***
        }
 
        //For Android  >= 4.1
        public void openFileChooser(ValueCallback<Uri> valueCallback, 
                String acceptType, String capture) {
            ***
        }
 
        // For Android >= 5.0
        @Override
        public boolean onShowFileChooser(WebView webView, 
                ValueCallback<Uri[]> filePathCallback, 
                WebChromeClient.FileChooserParams fileChooserParams) {
            ***
            return true;
        }
    });

El *** anterior significa que desea abrir el álbum del sistema y almacenar en caché valueCallback o filePathCallback;


Debería notar que ValueCallback en onShowfileChooser() contiene un conjunto de Uri (Uri[]), por lo que para sistemas superiores a 5.0 también necesitamos

Realice un pequeño procesamiento en onActivityForResult(), vea el código completo a continuación.

Después de procesar esto, hay un paso más con el que lidiar, que es confundir openFileChooser() en el archivo de ofuscación. Si el pozo de procesamiento no se realiza en el archivo de ofuscación, conducirá al empaquetado.

El apk instalado en el dispositivo real no puede seleccionar la imagen.La solución es la siguiente:
 

-keepclassmembers class * extends android.webkit.WebChromeClient{
    public void openFileChooser(...);
}

El código fuente completo se publica a continuación:

public class MainActivity extends AppCompatActivity {
 
    private ValueCallback<Uri> uploadMessage;
    private ValueCallback<Uri[]> uploadMessageAboveL;
    private final static int FILE_CHOOSER_RESULT_CODE = 10000;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        WebView webview = (WebView) findViewById(R.id.web_view);
        assert webview != null;
        WebSettings settings = webview.getSettings();
        settings.setUseWideViewPort(true);
        settings.setLoadWithOverviewMode(true);
        settings.setJavaScriptEnabled(true);
        webview.setWebChromeClient(new WebChromeClient() {
 
            // For Android < 3.0
            public void openFileChooser(ValueCallback<Uri> valueCallback) {
                uploadMessage = valueCallback;
                openImageChooserActivity();
            }
 
            // For Android  >= 3.0
            public void openFileChooser(ValueCallback valueCallback, String acceptType) {
                uploadMessage = valueCallback;
                openImageChooserActivity();
            }
 
            //For Android  >= 4.1
            public void openFileChooser(ValueCallback<Uri> valueCallback, String acceptType, String capture) {
                uploadMessage = valueCallback;
                openImageChooserActivity();
            }
 
            // For Android >= 5.0
            @Override
            public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, WebChromeClient.FileChooserParams fileChooserParams) {
                uploadMessageAboveL = filePathCallback;
                openImageChooserActivity();
                return true;
            }
        });
        String targetUrl = "file:///android_asset/up.html";
        webview.loadUrl(targetUrl);
    }
 
    private void openImageChooserActivity() {
        Intent i = new Intent(Intent.ACTION_GET_CONTENT);
        i.addCategory(Intent.CATEGORY_OPENABLE);
        i.setType("image/*");
        startActivityForResult(Intent.createChooser(i, "Image Chooser"), FILE_CHOOSER_RESULT_CODE);
    }
 
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == FILE_CHOOSER_RESULT_CODE) {
            if (null == uploadMessage && null == uploadMessageAboveL) return;
            Uri result = data == null || resultCode != RESULT_OK ? null : data.getData();
            if (uploadMessageAboveL != null) {
                onActivityResultAboveL(requestCode, resultCode, data);
            } else if (uploadMessage != null) {
                uploadMessage.onReceiveValue(result);
                uploadMessage = null;
            }
        }
    }
 
    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    private void onActivityResultAboveL(int requestCode, int resultCode, Intent intent) {
        if (requestCode != FILE_CHOOSER_RESULT_CODE || uploadMessageAboveL == null)
            return;
        Uri[] results = null;
        if (resultCode == Activity.RESULT_OK) {
            if (intent != null) {
                String dataString = intent.getDataString();
                ClipData clipData = intent.getClipData();
                if (clipData != null) {
                    results = new Uri[clipData.getItemCount()];
                    for (int i = 0; i < clipData.getItemCount(); i++) {
                        ClipData.Item item = clipData.getItemAt(i);
                        results[i] = item.getUri();
                    }
                }
                if (dataString != null)
                    results = new Uri[]{Uri.parse(dataString)};
            }
        }
        uploadMessageAboveL.onReceiveValue(results);
        uploadMessageAboveL = null;
    }
}

Nota: no hay ningún problema en llamar al álbum del sistema después de hacer estas cosas, pero si escribe una página para seleccionar imágenes, generalmente devolvemos una List<String> con la ruta absoluta de la imagen seleccionada
en onActivityForResult()

Por ejemplo, he probado personalmente teléfonos móviles Huawei con sistemas 6.0 y 7.0. Debido a que la ruta de retorno predeterminada del álbum del sistema Android es una ruta relativa, se puede cargar normalmente, así que supongo que no.

El motivo de la visualización está relacionado con la ruta. En este caso, necesitamos convertir la ruta absoluta en una ruta relativa en el código de procesamiento del sistema de 5.0 y superior en onActivityForResult()

ruta, el código para convertir una ruta absoluta en una ruta relativa es el siguiente:
 

public static Uri getImageContentUri(Context context, String filePath) {//File imageFile
        //String filePath = imageFile.getAbsolutePath();//根据文件来获取路径
        Cursor cursor = context.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                new String[] { MediaStore.Images.Media._ID }, MediaStore.Images.Media.DATA + "=? ",
                new String[] { filePath }, null);
        if (cursor != null && cursor.moveToFirst()) {
            int id = cursor.getInt(cursor.getColumnIndex(MediaStore.MediaColumns._ID));
            Uri baseUri = Uri.parse("content://media/external/images/media");
            return Uri.withAppendedPath(baseUri, "" + id);
        } else {
            if (StringUtil.isNotEmpty(filePath)) {//imageFile.exists()判断文件存不存在
                ContentValues values = new ContentValues();
                values.put(MediaStore.Images.Media.DATA, filePath);
                return context.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
            } else {
                return null;
            }
        }
    }

Sugiero que en el método onActivityForResult(), el imageFile se puede devolver para facilitar el procesamiento. Si se pasa una ruta absoluta, convierta la ruta absoluta en una ruta relativa y luego pase la ruta a través de ValueCallback (resultados)
.

Si no se puede mostrar en el sistema Huawei 6.0 o 7.0 después de la carga, primero asegúrese de que las siguientes dos configuraciones estén en su lugar:
 

        mWebview.getSettings().setJavaScriptEnabled(true);//启用js
        mWebview.getSettings().setBlockNetworkImage(false);//解决图片不显示

Si ambos están configurados, es posible que la imagen que obtuvo con https se refiera a http, porque Android WebView no permite el modo mixto de forma predeterminada a partir de Lollipop, y los recursos HTTP no se pueden cargar en https, que debe habilitarse.

Debe agregar el siguiente código en WebSetting para configurar:

if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){//
            webSettings.setMixedContentMode(android.webkit.WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
        }

Supongo que te gusta

Origin blog.csdn.net/duyiqun/article/details/121929784
Recomendado
Clasificación