La llamada a la API del portapapeles arroja NotAllowedError sin invocar onPermissionRequest ()

10

Tengo una página simple con un botón que, cuando se presiona, usa la API Async Clipboard 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, computadoras de escritorio y dispositivos móviles. 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 produce 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());
}

Todavía recibo 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 de acuerdo con https://developer.android.com/about/versions/10/privacy/changes#clipboard-data , mi aplicación debe tener permiso cuando se enfoca . 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.xmlcaso 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 aplicación.


¿Qué está pasando?

¿Cómo puedo hacer que las llamadas a la API del Portapapeles asíncrono funcionen en Webview?


SO: Android 10 Q

Vista web: v. 81.0.4044.111

cyqsimon
fuente
Pregunta similar, sin respuesta: stackoverflow.com/questions/61429649/…
BDL
Podría ser un error.
Travis J
@hereticMonkey thx para el enlace pero no creo que cambie nada. Establece que "intentar leer o escribir datos del portapapeles solicitará automáticamente permiso al usuario si aún no se le ha otorgado", lo que implica que no hay una forma explícita de solicitar este permiso en JS que no sea simplemente intentar usar el portapapeles, lo cual creer es verdad. Como se menciona en la pregunta, cuando hago eso en un entorno de Webview, onPermissionRequest()de hecho nunca se ha invocado.
cyqsimon

Respuestas:

2

Los writeTextdocumentos del método de la API del portapapeles dicen que necesitamos obtener clipboard-writepermiso usando la API de permisos. pero navigator.permissionno está definido en la vista web, tal vez porque no quieren mezclar los permisos web con los permisos del sistema operativo Android.

Hay una forma más por la cual podemos copiar texto al portapapeles desde la vista web de Android (llamando al método nativo de Java desde el código javascript de la vista web).

En primer lugar, habilite javascript en webview:

myWebView.getSettings().setJavaScriptEnabled(true);

Luego agregue la interfaz de JavaScript:

myWebView.addJavascriptInterface(new WebAppInterface(), "NativeAndroid");

Crear método que 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);
    }
}

Ahora puede llamar al método anterior desde el testClipboardmétodo:

function testClipboard() {
  navigator.clipboard.writeText("Clipboard API Test").then(
    v => alert("Success"),
    e => alert("Fail\n" + e));

  NativeAndroid.copyToClipboard("Clipboard API Test");
}
Ankit Makwana
fuente