Вызов API буфера обмена генерирует NotAllowedError без вызова onPermissionRequest ()

10

У меня есть простая страница с кнопкой, которая при нажатии использует API-интерфейс Async 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));
}

Это работает как на Chrome, так и на Firefox, на настольных и мобильных устройствах. Однако в Android Webview выдает следующую ошибку:

NotAllowError: Write permission denied.


Я решил, что мне нужно переопределить, WebChromeClient.onPermissionRequest()чтобы предоставить разрешение, но, как ни странно onPermissionRequest(), похоже, что он не был вызван, и та же ошибка все еще выдается.

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

Я все еще получаю ту же ошибку:

NotAllowError: Write permission denied.

Также Logcat ничего не вошел.


Я подозревал, что моему Android-приложению требуются дополнительные разрешения для доступа к буферу обмена, но согласно https://developer.android.com/about/versions/10/privacy/changes#clipboard-data , мое приложение должно иметь разрешение, когда оно имеет фокус , Действительно, следующий код работает:

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

Я также заявил следующее в AndroidManifest.xmlслучае, если действие запроса разрешения требует разрешения:

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

Это ничего не сделало.

Так что это, вероятно, не проблема с разрешением уровня приложения.


Что происходит?

Как я могу получить вызовы API Async Clipboard для работы в Webview?


ОС: Android 10 Q

Webview: v. 81.0.4044.111

cyqsimon
источник
Аналогичный вопрос, также нет ответа: stackoverflow.com/questions/61429649/…
BDL
Я ничего не знаю об Android, но эта статья от Google относится к использованию Permissions API (браузера) .
Еретик Обезьяна
Может быть ошибка.
Трэвис Дж
@hereticMonkey спасибо за ссылку, но я не думаю, что это что-то меняет. В нем говорится, что «попытка чтения или записи данных буфера обмена автоматически запросит у пользователя разрешение, если оно еще не было предоставлено», подразумевая, что не существует явного способа запросить это разрешение в JS, кроме простой попытки использовать буфер обмена, который я верю это правда. Как уже упоминалось в вопросе, когда я делаю это в среде Webview, onPermissionRequest()фактически никогда не вызывался.
Cyqsimon

Ответы:

2

В writeTextдокументе API метода буфера обмена говорится, что нам нужно получить clipboard-writeразрешение с помощью Permissions api. но navigator.permissionне определено в веб-просмотре, возможно, потому что они не хотят смешивать веб-разрешения с разрешениями Android OS.

Есть еще один способ, с помощью которого мы можем скопировать текст в буфер обмена из веб-просмотра Android (вызвав нативный метод Java из кода JavaScript веб-просмотра).

Прежде всего включите JavaScript на веб-сайте:

myWebView.getSettings().setJavaScriptEnabled(true);

Затем добавьте интерфейс javascript:

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

Создать метод, который будет копировать текст в буфер обмена, используя 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);
    }
}

Теперь вы можете просто вызвать вышеуказанный метод из testClipboardметода:

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

  NativeAndroid.copyToClipboard("Clipboard API Test");
}
Анкит Маквана
источник