簡體   English   中英

Xamarin WebView 上的攝像頭

[英]Camera on Xamarin WebView

我有一個簡單的 Xamarin 頁面,帶有一個調用 WebRTC 測試頁面的 WebView:

        _webView = new WebView
        {
            Source = "https://test.webrtc.org/",
            WidthRequest = 1000,
            HeightRequest = 1000
        };

        var stackLayout = new StackLayout()
        {
            Orientation = StackOrientation.Vertical,
            Padding = new Thickness(5, 20, 5, 10),
            Children = { _webView }
        };

        Content = new StackLayout { Children = { stackLayout } };

https://test.webrtc.org/頁面在同一個 Android Emulator 上的 Chrome 上運行良好,但在 WebView 上顯示“NotAllowedError”時不起作用。

該應用程序具有所需的權限。 以下代碼(使用 Plugin.Permissions)返回 true:

var statusCamera = await CrossPermissions.Current.CheckPermissionStatusAsync(Permission.Camera);
var statusMicrophone = await CrossPermissions.Current.CheckPermissionStatusAsync(Permission.Microphone);
return statusCamera == PermissionStatus.Granted && statusMicrophone == PermissionStatus.Granted;

怎么了?

謝謝

關於NotAllowedError ,從這里

用戶已指定不允許當前瀏覽實例訪問設備; 或者用戶拒絕訪問當前會話; 或者用戶在全局范圍內拒絕了對用戶媒體設備的所有訪問。


您需要自定義一個WebView來覆蓋WebChromeClientOnPermissionRequest方法。

PCL 中的MyWebView類:

public class MyWebView: WebView
{
}

MyWebViewRendererMyWebClient類:

[assembly: ExportRenderer(typeof(App45.MyWebView), typeof(MyWebViewRenderer))]
namespace App45.Droid
{
    public class MyWebViewRenderer : WebViewRenderer
    {
        Activity mContext;
        public MyWebViewRenderer(Context context) : base(context)
        {
            this.mContext = context as Activity;
        }
            protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.WebView> e)
        {
            base.OnElementChanged(e);
            Control.Settings.JavaScriptEnabled = true;
            Control.ClearCache(true);
            Control.SetWebChromeClient(new MyWebClient(mContext));
        }
        public class MyWebClient : WebChromeClient
        {
            Activity mContext;
            public MyWebClient(Activity context) {
                this.mContext = context;
            }
            [TargetApi(Value = 21)]
            public override void OnPermissionRequest(PermissionRequest request)
            {
                mContext.RunOnUiThread(() => {
                        request.Grant(request.GetResources());

                        });

            }
        }

    }

}

在這里,我提供了一個演示供您測試。 相機應該適合你。

默認情況下,Android 的 WebChromeClient 為文件選擇器提供了一個 Intent。 此默認選擇器意圖提供的內容因 Android 操作系統版本而異。 在 Android 6 和 7 上,當您選擇圖庫時,有一個打開相機的選項,但在更高的 Android 操作系統版本上,沒有圖庫,也沒有可用的相機選項。

按照上FileChooserParams,其被提供給所述的方法OnShowFileChooser Android的文檔WebChromeClient ,所述CreateIntent()方法:

創建將啟動文件選擇器以進行文件選擇的意圖。 Intent 支持從設備上可用的簡單文件源中選擇文件。 某些高級源(例如,實時媒體捕獲)可能不受支持,希望支持這些源或更高級文件操作的應用程序應構建自己的 Intent。

因此,盡管您的應用程序需要其他答案中注明的權限(讀取和寫入外部存儲以及相機權限),但如果您想提供相機作為選項,則必須自己構建它。

對於 Xamarin.Forms,您可以利用 Xamarin.Essentials.MediaPicker API 來避免直接處理 Android Intent、設置 ContentProviders 等。

這是您可以添加到自定義 Xamarin.Forms WebViewRenderer 的解決方案(使用MediaPicker 文檔中的代碼):

[assembly: ExportRenderer(typeof(WebView), typeof(MyWebViewRenderer))]
namespace YourAppNameSpace.Droid 
{
    public class MyWebViewRenderer: WebViewRenderer
    {

        public MyWebViewRenderer(Context context) : base(context) { }

        protected override FormsWebChromeClient GetFormsWebChromeClient()
        {
            return new CameraFormsWebChromeClient();
        }
    }
}

和 CameraFormsWebChromeClient 類:

    public class CameraFormsWebChromeClient : FormsWebChromeClient
    {
        string _photoPath;
        public override bool OnShowFileChooser(Android.Webkit.WebView webView, Android.Webkit.IValueCallback filePathCallback, FileChooserParams fileChooserParams)
        {

            AlertDialog.Builder alertDialog = new AlertDialog.Builder(MainActivity.Instance);
            alertDialog.SetTitle("Take picture or choose a file");
            alertDialog.SetNeutralButton("Take picture", async (sender, alertArgs) =>
            {
                try
                {
                    var photo = await MediaPicker.CapturePhotoAsync();
                    var uri = await LoadPhotoAsync(photo);
                    filePathCallback.OnReceiveValue(uri);
                }
                catch (System.Exception ex)
                {
                    System.Console.WriteLine($"CapturePhotoAsync THREW: {ex.Message}");
                }
            });
            alertDialog.SetNegativeButton("Choose picture", async (sender, alertArgs) =>
            {
                try
                {
                    var photo = await MediaPicker.PickPhotoAsync();
                    var uri = await LoadPhotoAsync(photo);
                    filePathCallback.OnReceiveValue(uri);
                }
                catch (System.Exception ex)
                {
                    System.Console.WriteLine($"PickPhotoAsync THREW: {ex.Message}");
                }
            });
            alertDialog.SetPositiveButton("Cancel", (sender, alertArgs) =>
            {
                filePathCallback.OnReceiveValue(null);
            });
            Dialog dialog = alertDialog.Create();
            dialog.Show();
            return true;
        }

        async Task<Android.Net.Uri[]> LoadPhotoAsync(FileResult photo)
        {
            // cancelled
            if (photo == null)
            {
                _photoPath = null;
                return null;
            }
            // save the file into local storage
            var newFile = Path.Combine(FileSystem.CacheDirectory, photo.FileName);
            using (var stream = await photo.OpenReadAsync())
            using (var newStream = System.IO.File.OpenWrite(newFile))
                await stream.CopyToAsync(newStream);
            _photoPath = newFile;
            Android.Net.Uri uri = Android.Net.Uri.FromFile(new Java.IO.File(_photoPath));
            return new Android.Net.Uri[] { uri };
        }
    }

我只是使用原生 Android Dialog 進行選擇或拍照選擇。 當然,您可以創建自己的 UI。 最重要的是,您必須從 OnShowFileChooser 方法返回“true”,讓 WebChromeClient 知道您將調用 filePathCallback 並提供結果。 如果您返回false ,您將收到本機異常,因為 WebChromeClient 被告知此方法不會提供結果,因此它提供自己的 null 結果,我們會收到“重復的 showFileChooser 結果”錯誤。 您還需要保存拍攝的圖片,然后向 filePathCallback.OnReceiveValue 方法提供 Android.Net.Uri[] 。 如果從 OnShowFileChooser 返回true則必須調用此回調,因此如果用戶取消,則需要調用 filePathCallback.OnReceiveValue(null);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM