A chamada da API da área de transferência lança NotAllowedError sem chamar onPermissionRequest ()

10

Eu tenho uma página simples com um botão que, quando pressionada, usa a API do Async Clipboard para gravar na área de transferência.

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

Isso funciona no Chrome e Firefox, desktop e móvel. No entanto, no Android Webview, ele lança o seguinte erro:

NotAllowError: Write permission denied.


Achei que precisava substituir WebChromeClient.onPermissionRequest()para conceder a permissão, mas estranhamente onPermissionRequest()não parece ter sido invocado e o mesmo erro ainda é gerado.

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

Ainda obtenho o mesmo erro:

NotAllowError: Write permission denied.

O Logcat também não registrou nada.


Suspeitei que talvez meu aplicativo Android exija permissões adicionais para acessar a área de transferência, mas, de acordo com https://developer.android.com/about/versions/10/privacy/changes#clipboard-data , meu aplicativo deve ter permissão quando estiver focado . De fato, o seguinte código funciona:

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

Também declarei o seguinte AndroidManifest.xmlcaso a ação de solicitar permissão exija permissão:

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

Isso não fez nada.

Portanto, provavelmente não é um problema com a permissão no nível do aplicativo.


O que está acontecendo?

Como faço para que as chamadas da API da área de transferência assíncrona funcionem no Webview?


Sistema operativo: Android 10 Q

Visualização da Web: v. 81.0.4044.111

cyqsimon
fonte
Pergunta semelhante, também não responde: stackoverflow.com/questions/61429649/…
BDL
Não sei nada sobre o Android, mas este artigo do Google se refere ao uso da API de permissões (do navegador) .
Heretic Monkey
Pode ser um bug.
Travis J
@hereticMonkey thx para o link, mas acho que não muda nada. Ele afirma que "a tentativa de ler ou gravar dados da área de transferência solicitará permissão automaticamente ao usuário, se ainda não tiver sido concedida", o que implica que não há maneira explícita de solicitar essa permissão no JS, além de apenas tentar usar a área de transferência. acreditar é verdade. Como mencionado na pergunta, quando faço isso em um ambiente de visualização na Web, onPermissionRequest()na verdade nunca foi invocado.
cyqsimon

Respostas:

2

Os writeTextdocumentos do método da API da área de transferência dizem que precisamos obter clipboard-writepermissão usando a API de permissões. mas navigator.permissioné indefinido na visualização na web, talvez porque não desejem misturar permissões da web com permissões do sistema operacional Android.

Há mais uma maneira pela qual podemos copiar texto para a área de transferência do android webview (chamando o método java nativo do código javascript do webview).

Antes de tudo, ative o javascript no webview:

myWebView.getSettings().setJavaScriptEnabled(true);

Em seguida, adicione a interface javascript:

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

Crie um método que copie o texto para a área de transferência 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);
    }
}

Agora você pode simplesmente chamar o método acima do 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
fonte