65

I have a simple page with a button, that when pressed, uses the Async Clipboard API to write to the clipboard.

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

This works on both Chrome and Firefox, desktop and mobile. However on Android Webview it throws the following error:

NotAllowError: Write permission denied.


I figured I need to override WebChromeClient.onPermissionRequest() to grant the permission, but strangely onPermissionRequest() does not seem to have been invoked, and the same error is still thrown.

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

I still get the same error:

NotAllowError: Write permission denied.

Also Logcat logged nothing.


I suspected maybe my Android App requires additional permissions to access the clipboard, but according to https://developer.android.com/about/versions/10/privacy/changes#clipboard-data, my App should have permission when it has focus. Indeed, the following code works:

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

I also declared the following in AndroidManifest.xml in case the action of requesting permission requires permission:

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

This did nothing.

So it is probably not an issue with App level permission.


What is happening?

How can I get Async Clipboard API calls to work in Webview?


OS: Android 10 Q

Webview: v. 81.0.4044.111

cyqsimon
  • 1,466
  • 10
  • 27
  • Similar question, also no answer: https://stackoverflow.com/questions/61429649/copy-to-clipboard-using-navigator-clipboard-writetext-not-working-in-android-web – BDL Apr 26 '20 at 09:36
  • I know nothing about Android, but [this article from Google refers to using the Permissions API (of the browser)](https://developers.google.com/web/updates/2018/03/clipboardapi#security_and_permissions). – Heretic Monkey Apr 27 '20 at 12:55
  • Could be a bug. – Travis J Apr 28 '20 at 02:42
  • @hereticMonkey thx for the link but I don't think it changes anything. It states "attempting to read or write clipboard data will automatically prompt the user for permission if it hasn't already been granted", implying there is no explicit way to request this permission in JS other than just trying to use the clipboard, which I believe is true. As mentioned in the question, when I do that in a Webview environment, `onPermissionRequest()` has in fact never been invoked. – cyqsimon Apr 28 '20 at 09:30

1 Answers1

51

Clipboard API's writeText method docs says, we need to obtain clipboard-write permission using Permissions API but navigator.permission is undefined in WebView, maybe because they don't want to mix web permissions with Android OS permissions.

There is one more way by which we can copy text to clipboard from Android WebView: by calling native Java method from WebView JavaScript (JS) code.

Enable JS in WebView:

myWebView.getSettings().setJavaScriptEnabled(true);

Add JS interface:

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

Create a method to copy the text to clipboard using 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);
    }
}

Then call the above method using testClipboard:

function testClipboard() {
  navigator.clipboard.writeText("Clipboard API Test").then(
    v => alert("Success"),
    e => alert("Fail\n" + e));
    
  NativeAndroid.copyToClipboard("Clipboard API Test");
}
xlm
  • 4,594
  • 13
  • 42
  • 47
Ankit Makwana
  • 1,613
  • 10
  • 12
  • 2
    I'm surprised that `Android Webview` didn't implement `navigator.permission`. Well, that's a shame. I'll use your workaround for the time being. Thank you. – cyqsimon May 07 '20 at 05:10
  • 6
    Yes, it is surprising, because other permissions like camera, microphone are working through `PermissionRequest` inside webview. – Ankit Makwana May 07 '20 at 05:51
  • @NihthiyaAlthaf In your webpage html/js file, where you want to copy text to the clipboard. – Ankit Makwana Nov 10 '20 at 12:08
  • @AnkitMakwana i got that copy button from sdk in my webpage – Nihthiya Althaf Nov 11 '20 at 13:02
  • Clipboard is one of the permissions that are not implemented in Android WebView, see [this line](https://chromium.googlesource.com/chromium/src/+/refs/heads/master/android_webview/browser/aw_permission_manager.cc#:~:text=case%20PermissionType::CLIPBOARD_READ_WRITE:) and its surroundings in the Chromium source code for details. – DenverCoder9 Dec 16 '20 at 13:08