【问题标题】:Why I am not able to open camera from webview in android?为什么我无法从 android 的 webview 打开相机?
【发布时间】:2022-03-01 00:29:57
【问题描述】:

我遇到的问题是我无法从 webview 打开相机,因为我有 php 页面,所以我必须从那里打开画廊和相机,但我无法从这个链接“@987654321 @"。 我可以打开图库但不能打开相机请给我任何解决方案。

【问题讨论】:

    标签: android webview


    【解决方案1】:

    Android 7+ 的 Kotlin 工作示例

    添加相机权限

    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.CAMERA2" />
    

    配置您的WebView

    private fun configureWebViewSettings() {
        binding.webView.settings.javaScriptEnabled = true
        binding.webView.settings.domStorageEnabled = true
        binding.webView.settings.setSupportZoom(false)
        binding.webView.settings.allowFileAccess = true
        binding.webView.settings.allowContentAccess = true
        binding.webView.webChromeClient = getCustomWebChromeClient()
    }
    

    将下面的行添加到您的Activity

    private var imagePathCallback: ValueCallback<Array<Uri>>? = null
    private var cameraImagePath: String? = null
    

    实现WebChromeClient 并将其添加到您的WebView

        private fun getCustomWebChromeClient() = object : WebChromeClient() {
        
            override fun onShowFileChooser(
                view: WebView?,
                filePath: ValueCallback<Array<Uri>>?,
                fileChooserParams: FileChooserParams?
            ): Boolean {
                if (checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED)
                    requestPermissions(arrayOf(Manifest.permission.CAMERA), CAMERA_REQUEST_CODE)
        
                imagePathCallback?.onReceiveValue(null)
                imagePathCallback = null
                imagePathCallback = filePath
        
                val takePictureIntent = createImageCaptureIntent()
        
                val contentSelectionIntent = Intent(Intent.ACTION_GET_CONTENT)
                contentSelectionIntent.addCategory(Intent.CATEGORY_OPENABLE)
                contentSelectionIntent.type = INTENT_FILE_TYPE
        
                val intentArray: Array<Intent?>
                intentArray = takePictureIntent?.let { arrayOf(it) } ?: arrayOfNulls(0)
        
                val chooserIntent = Intent(Intent.ACTION_CHOOSER)
                chooserIntent.putExtra(Intent.EXTRA_INTENT, contentSelectionIntent)
                chooserIntent.putExtra(Intent.EXTRA_TITLE, getString(R.string.file_chooser_title))
                chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentArray)
        
                try {
                    startActivityForResult(chooserIntent, REQUEST_SELECT_FILE)
                } catch (e: ActivityNotFoundException) {
                    imagePathCallback = null
                    cameraImagePath = null
        
                    Toast.makeText(
                        this@MainActivity,
                        getString(R.string.cannot_open_file_chooser_txt),
                        Toast.LENGTH_LONG
                    ).show()
        
                    return false
                }
        
                return true
            }
    
            private fun createImageCaptureIntent(): Intent? {
                var captureImageIntent: Intent? = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
        
                if (captureImageIntent?.resolveActivity(packageManager) != null) {
                    var imageFile: File? = null
        
                    try {
                        imageFile = createImageFile()
                        captureImageIntent.putExtra("CameraImagePath", cameraImagePath)
                    } catch (ex: IOException) {
                        ex.printStackTrace()
                    }
        
                    if (imageFile != null) {
                        cameraImagePath = CAMERA_PHOTO_PATH_POSTFIX + imageFile.absolutePath
                        captureImageIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(imageFile))
                    } else {
                        captureImageIntent = null
                    }
                }
        
                return captureImageIntent
            }
        
            private fun createImageFile(): File? {
                val timeStamp = SimpleDateFormat.getDateInstance().format(Date())
                val imageFileName = PHOTO_NAME_POSTFIX + timeStamp + "_"
                val storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES)
        
                return File.createTempFile(imageFileName, PHOTO_FORMAT, storageDir)
            }
    

    在您的Activity 中实现onRequestPermissionsResult

        override fun onRequestPermissionsResult(
            requestCode: Int,
            permissions: Array<out String>,
            grantResults: IntArray
        ) {
            super.onRequestPermissionsResult(requestCode, permissions, grantResults)
            if (requestCode == CAMERA_REQUEST_CODE) {
                if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    Toast.makeText(
                        this,
                        getString(R.string.amera_permission_granted_txt),
                        Toast.LENGTH_LONG
                    ).show()
                } else {
                    Toast.makeText(
                        this,
                        getString(R.string.camera_permission_denied_txt),
                        Toast.LENGTH_LONG
                    ).show()
                }
            }
        }
    

    在您的Activity 中实现onActivityResult

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
    
        if (requestCode != REQUEST_SELECT_FILE || imagePathCallback == null) return
    
        var results: Array<Uri>? = null
    
        if (resultCode == RESULT_OK) {
            if (data == null) {
                if (cameraImagePath != null) results = arrayOf(Uri.parse(cameraImagePath))
            } else {
                val dataString = data.dataString
                if (dataString != null) results = arrayOf(Uri.parse(dataString))
            }
        }
    
        imagePathCallback?.onReceiveValue(results)
        imagePathCallback = null
    }
    

    常量

    companion object {
        private const val CAMERA_REQUEST_CODE = 113
        private const val REQUEST_SELECT_FILE = 13
        private const val INTENT_FILE_TYPE = "image/*"
        private const val CAMERA_PHOTO_PATH_POSTFIX = "file:"
        private const val PHOTO_NAME_POSTFIX = "JPEG_"
        private const val PHOTO_FORMAT = ".jpg"
    }
    

    试试看,应该可以的。

    【讨论】:

      【解决方案2】:

      您是否向 WebView 的 WebChromeClient 授予相机权限?

      请在您的 AndroidManifest.xml 中添加相机权限。

      <uses-permission android:name="android.permission.CAMERA" />
      <uses-permission android:name="android.permission.CAMERA2" />
      

      将 WebChromeClient 设置到您的 WebView 中。

      webView.setWebChromeClient(new ChromeClient())
      

      定义您的 ChromeClient 类。

      public class ChromeClient extends WebChromeClient {
      
              @Override
              public boolean onShowFileChooser(WebView view, ValueCallback<Uri[]> filePath, WebChromeClient.FileChooserParams fileChooserParams) {
                  if (!hasPermissions(MainActivity.this, PERMISSIONS)) {
                      checkStoragePermission();
                      return false;
                  }
                  // Double check that we don't have any existing callbacks
                  if (mFilePathCallback != null) {
                      mFilePathCallback.onReceiveValue(null);
                  }
                  mFilePathCallback = filePath;
      
                  Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                  if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
                      // Create the File where the photo should go
                      File photoFile = createImageFile();
                      takePictureIntent.putExtra("PhotoPath", mCameraPhotoPath);
      
                      // Continue only if the File was successfully created
                      if (photoFile != null) {
                          mCameraPhotoPath = "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("image/*");
      
                  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, "Select Photo");
                  chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentArray);
      
                  startActivityForResult(chooserIntent, Constant.INPUT_FILE_REQUEST_CODE);
      
                  return true;
      
              }
          }
      

      这里是变量。

      String[] PERMISSIONS = {
              Manifest.permission.CAMERA,
              Manifest.permission.WRITE_EXTERNAL_STORAGE
      };
      
      private ValueCallback<Uri[]> mFilePathCallback;
      private String mCameraPhotoPath;
      

      检查存储和相机权限。

       private void checkStoragePermission() {
              String permission = Manifest.permission.WRITE_EXTERNAL_STORAGE;
              if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
                  ActivityCompat.requestPermissions(MainActivity.this, new String[]{permission}, Constant.REQUEST_STORAGE_PERMISSION);
              } else {
                  checkCameraPermission();
              }
          }
      
          private void checkCameraPermission() {
              String permission = Manifest.permission.CAMERA;
              if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
                  ActivityCompat.requestPermissions(MainActivity.this, new String[]{permission}, Constant.REQUEST_CAMERA_PERMISSION);
              } else {
                  onPermissionGranted();
              }
          }
      

      之后,我可以访问相机和图库。

      希望对您有所帮助。

      【讨论】:

      • 这对我来说效果很好,但之后我无法从相机中取回照片!请问有什么帮助吗?
      【解决方案3】:

      对于 Android 10,SDK 30

      在 manifest 的 application 标签中添加 android:requestLegacyExternalStorage="true"

      https://stackoverflow.com/a/65415381/7775500

      这可能会对你有所帮助..

      【讨论】:

        【解决方案4】:

        你肯定需要权限才能在安卓上打开相机。

        像这样编辑清单:

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

        您可能还需要一个不包括在内的库

        【讨论】:

          【解决方案5】:

          我也有这个问题。我会分享给以后可能遇到这个问题的人。

          您必须在 ma​​nifest 中拥有 相机权限,并在您的 WebChromeClient 中的 onPermissionRequest 方法中授予它,并确保将 setMediaPlaybackRequiresUserGesture 设置为 webView 设置中的strong>false。

          添加此权限:

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

          在 webView 设置中添加这个:

          binding.webView.getSettings().setMediaPlaybackRequiresUserGesture(false);
          

          并在 onPermissionRequest 方法中授予权限:

          @Override
          public void onPermissionRequest(final PermissionRequest request) {
              final String[] requestedResources = request.getResources();
              request.grant(requestedResources);
          }
          

          有关更多信息,请参阅此链接:

          StackOverFlow solution

          【讨论】:

          • 虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接答案可能会失效。 - From Review
          猜你喜欢
          • 2017-05-24
          • 1970-01-01
          • 1970-01-01
          • 2010-12-14
          • 1970-01-01
          • 1970-01-01
          • 2018-01-24
          • 2022-07-21
          • 2018-01-12
          相关资源
          最近更新 更多