L'appel de l'API Clipboard lève NotAllowedError sans invoquer onPermissionRequest ()

10

J'ai une page simple avec un bouton qui, lorsqu'elle est enfoncée, utilise l'API Async Clipboard pour écrire dans le presse-papiers.

<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));
}

Cela fonctionne à la fois sur Chrome et Firefox, sur ordinateur et sur mobile. Cependant, sur Android Webview, il génère l'erreur suivante:

NotAllowError: Write permission denied.


J'ai pensé que je devais remplacer WebChromeClient.onPermissionRequest()pour accorder l'autorisation, mais étrangement, onPermissionRequest()il ne semble pas avoir été invoqué, et la même erreur est toujours lancée.

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());
}

Je reçois toujours la même erreur:

NotAllowError: Write permission denied.

Logcat n'a rien enregistré non plus.


Je soupçonnais peut-être que mon application Android nécessite des autorisations supplémentaires pour accéder au presse-papiers, mais selon https://developer.android.com/about/versions/10/privacy/changes#clipboard-data , mon application devrait avoir l'autorisation lorsqu'elle est concentrée . En effet, le code suivant fonctionne:

ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText("MyLbl", "I have permission");
clipboard.setPrimaryClip(clip);

J'ai également déclaré ce qui suit dans AndroidManifest.xml cas où l'action de demander une autorisation nécessite une autorisation:

<uses-permission android:name="android.webkit.PermissionRequest" />

Cela n'a rien fait.

Ce n'est donc probablement pas un problème avec l'autorisation au niveau de l'application.


Qu'est-ce qui se passe?

Comment puis-je faire fonctionner les appels d'API Async Clipboard dans Webview?


Système d'exploitation: Android 10 Q

Webview: v. 81.0.4044.111

cyqsimon
la source
Question similaire, également pas de réponse: stackoverflow.com/questions/61429649/…
BDL
Cela pourrait être un bug.
Travis J
@hereticMonkey thx pour le lien mais je ne pense pas que cela change quoi que ce soit. Il déclare "tenter de lire ou d'écrire des données du presse-papiers demandera automatiquement à l'utilisateur l'autorisation s'il n'a pas déjà été accordé", ce qui implique qu'il n'y a aucun moyen explicite de demander cette autorisation dans JS autre que d'essayer simplement d'utiliser le presse-papiers, ce que je croire est vrai. Comme mentionné dans la question, lorsque je fais cela dans un environnement Webview, cela onPermissionRequest()n'a en fait jamais été invoqué.
cyqsimon

Réponses:

2

Les writeTextdocuments de méthode de l'API Clipboard indiquent que nous devons obtenir une clipboard-writeautorisation à l'aide de l'API Permissions. maisnavigator.permission n'est pas défini dans la vue Web, peut-être parce qu'ils ne veulent pas mélanger les autorisations Web avec les autorisations OS Android.

Il existe un autre moyen par lequel nous pouvons copier du texte dans le presse-papiers à partir de la vue Web Android (en appelant la méthode Java native à partir du code JavaScript Webview).

Tout d'abord, activez javascript sur la vue Web:

myWebView.getSettings().setJavaScriptEnabled(true);

Ajoutez ensuite l'interface javascript:

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

Créer une méthode qui copiera le texte dans le presse-papiers en utilisant 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);
    }
}

Maintenant, vous pouvez simplement appeler la méthode ci-dessus à partir de la testClipboardméthode:

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

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