Tengo una página simple con un botón que, cuando se presiona, usa la API del portapapeles asíncrono para escribir en el portapapeles.
<body> <button type="button" onclick="testClipboard();"> Test Clipboard </button> </body> function testClipboard() { navigator.clipboard.writeText("Clipboard API Test").then( v => alert("Success"), e => alert("Fail\n" + e)); }Esto funciona tanto en Chrome como en Firefox, escritorio y móvil. Sin embargo, en Android Webview arroja el siguiente error:
NotAllowError: Write permission denied.
Pensé que necesitaba anular WebChromeClient.onPermissionRequest() para otorgar el permiso, pero extrañamente onPermissionRequest() no parece haber sido invocado, y todavía se arroja el mismo error.
public class WebChromeController extends WebChromeClient { @Override public void onPermissionRequest(PermissionRequest request) { Log.d("myTag", "Permission request"); Log.d("myTag", request.getResources().toString()); request.grant(request.getResources()); } } protected void initWebView() { // ... myWebView.setWebChromeClient(new WebChromeController()); }Sigo teniendo el mismo error:
NotAllowError: Write permission denied.
También Logcat no registró nada.
Sospeché que tal vez mi aplicación de Android requiere permisos adicionales para acceder al portapapeles, pero según https://developer.android.com/about/versions/10/privacy/changes#clipboard-data , mi aplicación debería tener permiso cuando tiene foco . De hecho, el siguiente código funciona:
ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE); ClipData clip = ClipData.newPlainText("MyLbl", "I have permission"); clipboard.setPrimaryClip(clip); También declaré lo siguiente en AndroidManifest.xml en caso de que la acción de solicitar permiso requiera permiso:
<uses-permission android:name="android.webkit.PermissionRequest" />Esto no hizo nada.
Por lo tanto, probablemente no sea un problema con el permiso de nivel de la aplicación.
¿Qué está pasando?
¿Cómo puedo hacer que las llamadas a la API del portapapeles asíncrono funcionen en Webview?
Sistema operativo: Android 10 Q
Vista web: versión 81.0.4044.111
Los documentos del método writeText de la API del portapapeles dicen que necesitamos obtener el permiso clipboard-write usando la API de permisos, pero navigator.permission no está definido en WebView, tal vez porque no quieren mezclar los permisos web con los permisos del sistema operativo Android.
Hay una forma más en la que podemos copiar texto al portapapeles desde Android WebView: llamando al método Java nativo desde el código JavaScript (JS) de WebView.
Habilite JS en WebView:
myWebView.getSettings().setJavaScriptEnabled(true);Agregar interfaz JS:
myWebView.addJavascriptInterface(new WebAppInterface(), "NativeAndroid"); Crea un método para copiar el texto al portapapeles usando android.content.ClipboardManager :
public class WebAppInterface { @JavascriptInterface public void copyToClipboard(String text) { ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE); ClipData clip = ClipData.newPlainText("demo", text); clipboard.setPrimaryClip(clip); } } Luego llame al método anterior usando testClipboard :
function testClipboard() { navigator.clipboard.writeText("Clipboard API Test").then( v => alert("Success"), e => alert("Fail\n" + e)); NativeAndroid.copyToClipboard("Clipboard API Test"); }