如何通过Xamarin Forms WebView在ASP.NET网站中调用原生相机并加载照片
我来帮你搞定这个需求!要在Xamarin WebView里让ASP.NET网站直接唤起原生相机,拍完还能把照片无缝传回网页显示,核心是WebView和原生代码的双向交互。下面分平台给你一步步实现:
整体核心逻辑
网页端通过JS调用原生端的相机启动方法 → 原生端唤起系统相机并处理拍照结果 → 把照片转成Base64格式(方便直接传给网页)→ 原生端调用网页的JS回调方法,把Base64数据传回去 → ASP.NET网页加载并显示照片
Android 端实现
1. 配置权限
首先在AndroidManifest.xml里添加相机权限,Android 6.0以上还要动态申请权限:
<uses-permission android:name="android.permission.CAMERA" /> <uses-feature android:name="android.hardware.camera" android:required="true" />
2. 实现JS与原生的交互类
写一个辅助类,把相机操作暴露给JS:
public class CameraJsInterface : Java.Lang.Object { private readonly Activity _activity; private readonly WebView _webView; public static readonly int CameraRequestCode = 1001; public CameraJsInterface(Activity activity, WebView webView) { _activity = activity; _webView = webView; } [JavascriptInterface] // 必须加这个注解,JS才能调用 public void OpenCamera() { // 先检查动态权限 if (ContextCompat.CheckSelfPermission(_activity, Manifest.Permission.Camera) != Permission.Granted) { ActivityCompat.RequestPermissions(_activity, new[] { Manifest.Permission.Camera }, CameraRequestCode); return; } // 启动系统相机 var takePictureIntent = new Intent(MediaStore.ActionImageCapture); if (takePictureIntent.ResolveActivity(_activity.PackageManager) != null) { _activity.StartActivityForResult(takePictureIntent, CameraRequestCode); } } // 处理拍照结果,这个方法要在Activity里调用 public void OnActivityResult(int requestCode, Result resultCode, Intent data) { if (requestCode == CameraRequestCode && resultCode == Result.Ok && data != null) { // 获取拍照的Bitmap var imageBitmap = (Bitmap)data.Extras.Get("data"); // 转成Base64 using (var stream = new MemoryStream()) { imageBitmap.Compress(Bitmap.CompressFormat.Jpeg, 80, stream); byte[] byteArray = stream.ToArray(); string base64String = Convert.ToBase64String(byteArray); // 调用网页的JS回调,把Base64传回去 _webView.Post(() => { _webView.EvaluateJavascript($"window.onCameraPhotoTaken('{base64String}')", null); }); } // 回收Bitmap避免内存泄漏 imageBitmap.Recycle(); } else { // 拍照取消,通知网页 _webView.Post(() => { _webView.EvaluateJavascript("window.onCameraPhotoTaken(null)", null); }); } } }
3. 配置WebView并绑定交互类
在你的WebView所在的Activity里初始化WebView:
private WebView _webView; private CameraJsInterface _cameraJsInterface; protected override void OnCreate(Bundle savedInstanceState) { base.OnCreate(savedInstanceState); SetContentView(Resource.Layout.Main); _webView = FindViewById<WebView>(Resource.Id.webView); _webView.Settings.JavaScriptEnabled = true; // 必须开启JS _cameraJsInterface = new CameraJsInterface(this, _webView); _webView.AddJavascriptInterface(_cameraJsInterface, "NativeCamera"); // 给JS暴露的对象名 // 加载你的ASP.NET网站 _webView.LoadUrl("https://your-aspnet-site.com"); } // 重写OnActivityResult,把结果传给相机辅助类 protected override void OnActivityResult(int requestCode, Result resultCode, Intent data) { base.OnActivityResult(requestCode, resultCode, data); _cameraJsInterface.OnActivityResult(requestCode, resultCode, data); } // 处理权限申请结果 public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults) { if (requestCode == CameraJsInterface.CameraRequestCode) { if (grantResults.Length > 0 && grantResults[0] == Permission.Granted) { _cameraJsInterface.OpenCamera(); } else { // 用户拒绝权限,通知网页 _webView.EvaluateJavascript("window.onCameraPermissionDenied()", null); } } }
iOS 端实现
1. 配置相机权限
在Info.plist里添加相机权限说明(iOS必须要):
<key>NSCameraUsageDescription</key> <string>需要使用相机拍摄照片</string>
2. 实现WKWebView的消息处理
iOS推荐用WKWebView,需要实现WKScriptMessageHandler来接收JS的消息:
public class ViewController : UIViewController, IWKScriptMessageHandler { private WKWebView _webView; private UIImagePickerController _imagePicker; public override void ViewDidLoad() { base.ViewDidLoad(); // 配置WKWebView var config = new WKWebViewConfiguration(); config.UserContentController.AddScriptMessageHandler(this, "openCamera"); // 注册JS消息名 _webView = new WKWebView(View.Bounds, config); View.AddSubview(_webView); // 加载ASP.NET网站 _webView.LoadRequest(new NSUrlRequest(new NSUrl("https://your-aspnet-site.com"))); } // 接收JS发来的openCamera消息 public void DidReceiveScriptMessage(WKUserContentController userContentController, WKScriptMessage message) { if (message.Name == "openCamera") { // 检查相机权限 AVAuthorizationStatus status = AVCaptureDevice.GetAuthorizationStatus(AVMediaType.Video); if (status == AVAuthorizationStatus.Authorized) { OpenCamera(); } else if (status == AVAuthorizationStatus.NotDetermined) { AVCaptureDevice.RequestAccessForMediaTypeAsync(AVMediaType.Video).ContinueWith(t => { if (t.Result) { InvokeOnMainThread(OpenCamera); } else { // 权限被拒,通知网页 _webView.EvaluateJavaScript("window.onCameraPermissionDenied()", null); } }); } else { _webView.EvaluateJavaScript("window.onCameraPermissionDenied()", null); } } } private void OpenCamera() { _imagePicker = new UIImagePickerController(); _imagePicker.SourceType = UIImagePickerControllerSourceType.Camera; _imagePicker.MediaTypes = UIImagePickerController.AvailableMediaTypes(UIImagePickerControllerSourceType.Camera); _imagePicker.FinishedPickingMedia += OnImagePickerFinished; _imagePicker.Canceled += OnImagePickerCanceled; PresentViewController(_imagePicker, true, null); } // 处理拍照完成 private void OnImagePickerFinished(object sender, UIImagePickerMediaPickedEventArgs e) { var image = e.OriginalImage; // 转成Base64 var imageData = image.AsJPEG(0.8f); string base64String = imageData.GetBase64EncodedString(NSDataBase64EncodingOptions.EndLineWithLineFeed); // 调用网页JS回调 _webView.EvaluateJavaScript($"window.onCameraPhotoTaken('{base64String}')", null); _imagePicker.DismissViewController(true, null); _imagePicker.Dispose(); } // 处理拍照取消 private void OnImagePickerCanceled(object sender, EventArgs e) { _webView.EvaluateJavaScript("window.onCameraPhotoTaken(null)", null); _imagePicker.DismissViewController(true, null); _imagePicker.Dispose(); } // 页面销毁时移除消息处理,避免内存泄漏 public override void ViewWillDisappear(bool animated) { base.ViewWillDisappear(animated); _webView.Configuration.UserContentController.RemoveScriptMessageHandler("openCamera"); } }
ASP.NET 网页端配合
在你的ASP.NET页面里添加按钮和图片容器,写JS代码来调用原生相机并处理返回的照片:
<button id="takePhotoBtn">拍摄照片</button> <img id="photoPreview" src="" alt="拍摄的照片" style="max-width: 100%; margin-top: 20px;" /> <script> // 兼容Android和iOS的相机调用函数 function openNativeCamera() { if (typeof NativeCamera !== 'undefined') { // Android端 NativeCamera.OpenCamera(); } else if (typeof webkit !== 'undefined' && webkit.messageHandlers && webkit.messageHandlers.openCamera) { // iOS端 webkit.messageHandlers.openCamera.postMessage(null); } else { alert("当前环境不支持原生相机调用"); } } // 原生端回调的拍照结果处理函数 window.onCameraPhotoTaken = function(base64Data) { const imgElement = document.getElementById('photoPreview'); if (base64Data) { imgElement.src = 'data:image/jpeg;base64,' + base64Data; } else { alert("拍照已取消"); } } // 权限被拒的处理函数 window.onCameraPermissionDenied = function() { alert("请允许相机权限才能拍摄照片"); } // 绑定按钮点击事件 document.getElementById('takePhotoBtn').addEventListener('click', openNativeCamera); </script>
注意事项
- 照片压缩:上面的代码里都设置了压缩质量(Android是80,iOS是0.8),避免Base64字符串过大导致传输卡顿。
- 权限处理:一定要处理用户拒绝权限的情况,给用户友好提示。
- 内存管理:iOS端记得在页面销毁时移除ScriptMessageHandler,防止内存泄漏;Android端的Bitmap要及时回收。
内容的提问来源于stack exchange,提问作者G. Nah
相关产品推荐
相关产品推荐

