[英]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
來覆蓋WebChromeClient
的OnPermissionRequest
方法。
PCL 中的MyWebView
類:
public class MyWebView: WebView
{
}
MyWebViewRenderer
和MyWebClient
類:
[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.