1

Столкнулся с проблемой с запуском камеры в Webview-приложении на Android.

На странице есть input type="file" с атрибутами: capture="camera" accept="image/*"

При работе через браузер - все ок. Однако в Webview, естественно, это не работает. Использовал клиент webChrhome. При клике на поле ввода открывается проводник файлов без предложения выбора камеры. В логах вижу ошибку, но в manifest указано все, что требуется.

E/Webview: Image file creation failed java.io.IOException: Permission denied
    at java.io.UnixFileSystem.createFileExclusively0(Native Method)
    at java.io.UnixFileSystem.createFileExclusively(UnixFileSystem.java:281)
    at java.io.File.createTempFile(File.java:2001)
    at com.payou.app.MainActivity.createImageFile(MainActivity.java:178)
    at com.payou.app.MainActivity.access$200(MainActivity.java:28)
    at com.payou.app.MainActivity$2.onShowFileChooser(MainActivity.java:84)
    at Ii4.e(chromium-Monochrome.aab-stable-561513523:31)
    at Hs.runFileChooser(chromium-Monochrome.aab-stable-561513523:28)
    at android.os.MessageQueue.nativePollOnce(Native Method)
    at android.os.MessageQueue.next(MessageQueue.java:379)
    at android.os.Looper.loop(Looper.java:144)
    at android.app.ActivityThread.main(ActivityThread.java:7529)

Ниже привожу часть manifest и код моей Activiy. Подскажите, в чем может быть еще проблема? Или чего-то не хватает?

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.CAMERA2" />
            public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
                if (mUMA != null) {
                    mUMA.onReceiveValue(null);
                }
                mUMA = filePathCallback;
                Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                if (takePictureIntent.resolveActivity(MainActivity.this.getPackageManager()) != null) {
                    File photoFile = null;
                    try {
                        photoFile = createImageFile();
                        takePictureIntent.putExtra("PhotoPath", mCM);
                    } catch (IOException ex) {
                        Log.e("Webview", "Image file creation failed", ex);
                    }
                    if (photoFile != null) {
                        mCM = "file:" + photoFile.getAbsolutePath();
                        takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photoFile));
                    } else {
                        takePictureIntent = null;
                    }
                }
            Intent contentSelectionIntent = new Intent(Intent.ACTION_GET_CONTENT);
            contentSelectionIntent.addCategory(Intent.CATEGORY_OPENABLE);
            contentSelectionIntent.setType(&quot;*/*&quot;);
            Intent[] intentArray;
            if (takePictureIntent != null) {
                intentArray = new Intent[]{takePictureIntent};
            } else {
                intentArray = new Intent[0];
            }

            Intent chooserIntent = new Intent(Intent.ACTION_CHOOSER);
            chooserIntent.putExtra(Intent.EXTRA_INTENT, contentSelectionIntent);
            chooserIntent.putExtra(Intent.EXTRA_TITLE, &quot;Image Chooser&quot;);
            chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentArray);
            startActivityForResult(chooserIntent, FCR);
            return true;
        }

public void openFileChooser(ValueCallback<Uri> uploadMsg) {
        this.openFileChooser(uploadMsg, "*/*");
    }

    public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType) {
        this.openFileChooser(uploadMsg, acceptType, null);
    }

    public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
        Intent i = new Intent(Intent.ACTION_GET_CONTENT);
        i.addCategory(Intent.CATEGORY_OPENABLE);
        i.setType("*/*");
        MainActivity.this.startActivityForResult(Intent.createChooser(i, "File Browser"), FILECHOOSER_RESULTCODE);
    }

@Override
    protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
        super.onActivityResult(requestCode, resultCode, intent);
        if (Build.VERSION.SDK_INT >= 21) {
            Uri[] results = null;
            //Check if response is positive
            if (resultCode == Activity.RESULT_OK) {
                if (requestCode == FCR) {
                    if (null == mUMA) {
                        return;
                    }
                    if (intent == null) {
                        //Capture Photo if no image available
                        if (mCM != null) {
                            results = new Uri[]{Uri.parse(mCM)};
                        }
                    } else {
                        String dataString = intent.getDataString();
                        if (dataString != null) {
                            results = new Uri[]{Uri.parse(dataString)};
                        }
                    }
                }
            }
            mUMA.onReceiveValue(results);
            mUMA = null;
        } else {
            if (requestCode == FCR) {
                if (null == mUM) return;
                Uri result = intent == null || resultCode != RESULT_OK ? null : intent.getData();
                mUM.onReceiveValue(result);
                mUM = null;
            }
        }
    }

    // Create an image file
    private File createImageFile() throws IOException {
        @SuppressLint("SimpleDateFormat") String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
        String imageFileName = "img_" + timeStamp + "_";
        File storageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
        return File.createTempFile(imageFileName, ".jpg", storageDir);


    }

  • Предполагаю, что у вас Android 10 или выше. Метод getExternalStoragePublicDirectory устарел, нужно использовать Storage Access Framework. Приведите полный текст ошибки вместе со стектрейсом, чтобы разобраться, в чем конкретно проблема. – Vadik Sirekanyan May 07 '23 at 08:04
  • @VadikSirekanyan Попробовал использовать Storage Access Framework. Но при нажатии на поле для загрузки файла открывается просто файловый менеджер (а необходимо, чтобы камера запускалась или хотя бы выбор "файлы" или "камера"). Привел стектрейс ошибок в посте (дополнил)... – kryuchkov_kv May 07 '23 at 15:34
  • E/Webview: Image file creation failed java.io.IOException: Permission denied at java.io.UnixFileSystem.createFileExclusively0(Native Method) at java.io.UnixFileSystem.createFileExclusively(UnixFileSystem.java:281) at java.io.File.createTempFile(File.java:2001) at com.payou.app.MainActivity.createImageFile(MainActivity.java:178) at com.payou.app.MainActivity.access$200(MainActivity.java:28) – kryuchkov_kv May 07 '23 at 15:43
  • at com.payou.app.MainActivity$2.onShowFileChooser(MainActivity.java:84) at Ii4.e(chromium-Monochrome.aab-stable-561513523:31) at Hs.runFileChooser(chromium-Monochrome.aab-stable-561513523:28) at android.os.MessageQueue.nativePollOnce(Native Method) at android.os.MessageQueue.next(MessageQueue.java:379) at android.os.Looper.loop(Looper.java:144) at android.app.ActivityThread.main(ActivityThread.java:7529) – kryuchkov_kv May 07 '23 at 15:43
  • 1
    Ошибка в строчке номер 178 файла MainActivity.java. Файл не удалось создать по той причине, о которой я написал в первом комментарии. На новых версиях Андроида getExternalStoragePublicDirectory использовать не нужно. Если вы уже обсуждаете новый код, который написали, то создайте новый вопрос и покажите этот код. – Vadik Sirekanyan May 07 '23 at 17:48
  • 2
  • незачем временный файл создавать в публичной директории - для этого лучше использовать приватную. 2) Uri со схемой file шарить между приложениями запрещено, приложение камеры не сможет в него сохранить фото. Собственно пример запроса с пояснениями есть в гайде: https://developer.android.com/training/camera-deprecated/photobasics#TaskPath
  • – woesss May 07 '23 at 18:27