<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      MAUI Blazor 調用相機掃碼(Android)

      MAUI Blazor 與原生 MAUI 存在核心差異:其基于 WebView 嵌套實現,頁面由 Razor 組件構成,無法直接復用原生 MAUI 的二維碼掃描能力。為此,針對 Android 平臺,采用以下方案實現二維碼掃描功能。

      技術選型:基于 ZXing.Net.Maui 組件構建掃描核心,結合 Android 原生 API(如 Context、Vibrator)實現平臺適配,確保相機調用、二維碼識別與觸覺反饋功能正常運行;

      文件組織:在 Platforms/Android 目錄下創建 QrCodeScanner.cs,實現 IQrCodeScanner 接口,封裝平臺專屬掃描邏輯;

      功能實現:從基礎能力到交互體驗分層開發,包括:

      • 權限管理:通過 Permissions 接口檢查并請求相機權限,處理權限拒絕場景;

      • 視圖構建:初始化 CameraBarcodeReaderView(相機預覽與識別)、掃描線(視覺引導)、提示文本與取消按鈕,采用 AbsoluteLayout 實現元素精確定位;

      • 流程控制:封裝掃描啟動(頁面跳轉、動畫觸發)、結果處理(震動反饋、響應返回)、資源清理(相機停止、頁面關閉)全流程,同時通過 CustomScanPage 重寫返回鍵事件,確保取消邏輯統一;

      異常處理:針對上下文為空、屏幕尺寸獲取失敗、導航容器未初始化等場景,定義專屬錯誤提示與響應對象,保障功能穩定性。

      一、NuGet 包管理器:安裝 ZXing.Net.Maui、 ZXing.Net.Maui.Controls 包

      image

      二、修改 AndroidManifest.xml 添加相機、震動權限

      點擊查看代碼
      <?xml version="1.0" encoding="utf-8"?>
      <manifest xmlns:android="http://schemas.android.com/apk/res/android">
          <application android:allowBackup="true" android:icon="@mipmap/appicon" android:supportsRtl="true" android:usesCleartextTraffic="true" android:label="xx">
              <provider
                  android:name="androidx.core.content.FileProvider"
                  android:authorities="com.jiajing.iotplatform.fileprovider"
                  android:exported="false"
                  android:grantUriPermissions="true">
                  <meta-data
                      android:name="android.support.FILE_PROVIDER_PATHS"
                      android:resource="@xml/provider_paths" />
              </provider>
          </application>
          <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
          <uses-permission android:name="android.permission.INTERNET" />   
          <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />  
       
          <!-- 震動權限 -->
          <uses-permission android:name="android.permission.VIBRATE" />
          <!-- 相機權限 -->
          <uses-permission android:name="android.permission.CAMERA" />
      </manifest> 
      

      三、自定義 IQrCodeScanner.cs 接口

      點擊查看代碼
          /// <summary>
          /// 二維碼掃描接口類
          /// </summary>
          public interface IQrCodeScanner
          {
              /// <summary>
              /// 啟動相機掃描二維碼
              /// </summary>
              /// <returns>掃描到的二維碼內容</returns>
              Task<QrScannerResponse> ScanQrCodeAsync();
          }
      

      四、在 Platforms/Android 目錄下創建 QrCodeScanner.cs 文件,實現 IQrCodeScanner 接口

      點擊查看代碼
          /// <summary>
          /// Android平臺二維碼掃描器實現
          /// 提供二維碼掃描功能,包括相機權限管理、掃描界面展示和掃描結果處理
          /// </summary>
          public class QrCodeScanner : IQrCodeScanner
          {
      
              #region 私有字段
      
              /// <summary>
              /// 安卓上下文對象,用于訪問系統功能
              /// </summary>
              private readonly Context _androidContext;
      
              /// <summary>
              /// 掃描視圖,負責相機預覽和二維碼識別
              /// </summary>
              private CameraBarcodeReaderView _barcodeReaderView;
      
              /// <summary>
              /// 掃描線控件,提供視覺引導
              /// </summary>
              private BoxView _scanLine;
      
              /// <summary>
              /// 掃描提示文字控件,顯示操作指引
              /// </summary>
              private Label _scanLabel;
      
              /// <summary>
              /// 掃描狀態標識,控制掃描動畫的運行與停止
              /// </summary>
              private bool _isScanning = false;
      
              /// <summary>
              /// 當前掃描頁面引用
              /// </summary>
              private ContentPage _currentScanPage;
      
              /// <summary>
              /// 掃描結果任務完成源
              /// </summary>
              private TaskCompletionSource<QrScannerResponse> _resultTcs;
      
              /// <summary>
              /// 震動管理器,用于掃描成功后的觸覺反饋
              /// </summary>
              private Vibrator _vibrator;
      
              #endregion
      
      
              #region 常量定義
      
              /// <summary>
              /// 掃描框大小(像素)
              /// </summary>
              private const int ScanAreaSize = 300;
      
              /// <summary>
              /// 掃描線最大高度(中間部分)
              /// </summary>
              private const int ScanLineMaxHeight = 2;
      
              /// <summary>
              /// 掃描提示文字與掃描框的間距
              /// </summary>
              private const int LabelMarginTop = 35;
      
              #endregion
      
      
              #region 錯誤提示文本
      
              private const string PermissionDeniedTip = "需要相機權限才能掃描二維碼,請在系統設置中開啟";
              private const string NavigationNullTip = "導航容器未初始化,無法顯示掃描頁面";
              private const string ViewInitFailedTip = "掃描視圖初始化失敗";
              private const string ContextNullTip = "安卓上下文不能為空";
              private const string ScreenSizeErrorTip = "無法獲取屏幕尺寸,掃描功能無法使用";
              private const string CancelTip = "未識別,已取消掃描";
      
              #endregion
      
      
      
              /// <summary>
              /// 初始化二維碼掃描器
              /// </summary>
              /// <param name="context">安卓上下文</param>
              public QrCodeScanner(Context context)
              {
                  _androidContext = context;
                  if (_androidContext != null)
                  {
                      // 初始化震動管理器
                      InitializeVibrator();
                  }
              }
      
              /// <summary>
              /// 啟動二維碼掃描流程
              /// </summary>
              /// <returns>掃描結果響應對象</returns>
              public async Task<QrScannerResponse> ScanQrCodeAsync()
              {
                  // 基礎校驗
                  if (_androidContext == null)
                      return CreateErrorResponse(ApiCode.Exception, ContextNullTip);
      
                  // 檢查相機權限
                  var permissionResult = await CheckCameraPermission();
                  if (!string.IsNullOrEmpty(permissionResult))
                      return CreateErrorResponse(ApiCode.Exception, permissionResult);
      
                  // 創建任務完成源,用于異步返回掃描結果
                  _resultTcs = new TaskCompletionSource<QrScannerResponse>();
      
                  try
                  {
                      // 初始化掃描相關視圖
                      InitializeScannerViews();
      
                      // 創建掃描頁面布局
                      _currentScanPage = CreateScanPage(_resultTcs);
      
                      // 顯示掃描頁面
                      var showPageResult = await ShowScanPageAsync(_currentScanPage);
                      if (!string.IsNullOrEmpty(showPageResult))
                      {
                          await StopScanning();
                          return CreateErrorResponse(ApiCode.Exception, showPageResult);
                      }
      
                      // 等待頁面渲染完成后再定位掃描元素和啟動動畫
                      await Task.Delay(300);
      
                      // 定位掃描元素
                      var positionResult = PositionScanElements();
                      if (!string.IsNullOrEmpty(positionResult))
                      {
                          await StopScanning();
                          return CreateErrorResponse(ApiCode.Exception, positionResult);
                      }
      
                      // 啟動掃描動畫
                      StartScanLineAnimation();
      
                      // 返回掃描結果
                      return await _resultTcs.Task;
                  }
                  catch (Exception ex)
                  {
                      await StopScanning();
                      return CreateErrorResponse(ApiCode.Exception, $"掃描初始化失敗:{ex.Message}");
                  }
                  finally
                  {
                      // 清理引用
                      _currentScanPage = null;
                      _resultTcs = null;
                  }
              }
      
      
              #region 初始化掃描相關視圖組件  private void InitializeScannerViews()
      
              /// <summary>
              /// 初始化掃描相關視圖組件
              /// </summary>
              private void InitializeScannerViews()
              {
                  // 初始化條形碼掃描視圖
                  _barcodeReaderView = new CameraBarcodeReaderView
                  {
                      Options = new BarcodeReaderOptions
                      {
                          Formats = ZXing.Net.Maui.BarcodeFormat.QrCode,  // 只識別二維碼
                          AutoRotate = true,               // 自動旋轉
                          TryHarder = true                 // 提高識別準確率
                      },
                      IsEnabled = true,
                      IsDetecting = true
                  };
      
                  // 初始化掃描線(白色)
                  _scanLine = new BoxView
                  {
                      Color = Colors.White,
                      HeightRequest = ScanLineMaxHeight,
                      HorizontalOptions = LayoutOptions.Fill
                  };
      
                  // 初始化掃描提示文字
                  _scanLabel = new Label
                  {
                      Text = "請將設備二維碼對準掃描框",
                      TextColor = Colors.White,
                      FontSize = 16,
                      HorizontalTextAlignment = TextAlignment.Center,
                      VerticalTextAlignment = TextAlignment.Center,
                      Opacity = 0.85  // 稍微降低不透明度,避免過于刺眼
                  };
              }
      
              /// <summary>
              /// 創建掃描頁面及其布局
              /// </summary>
              /// <param name="resultTcs">用于返回掃描結果的任務完成源</param>
              /// <returns>構建好的掃描頁面</returns>
              private CustomScanPage CreateScanPage(TaskCompletionSource<QrScannerResponse> resultTcs)
              {
                  // 創建主布局容器(絕對布局,用于精確定位掃描線和提示文字)
                  var mainLayout = new AbsoluteLayout
                  {
                      VerticalOptions = LayoutOptions.FillAndExpand,
                      HorizontalOptions = LayoutOptions.FillAndExpand
                  };
      
                  // 添加相機視圖到主布局
                  AbsoluteLayout.SetLayoutBounds(_barcodeReaderView, new Rect(0, 0, 1, 1));
                  AbsoluteLayout.SetLayoutFlags(_barcodeReaderView, AbsoluteLayoutFlags.All);
                  mainLayout.Children.Add(_barcodeReaderView);
      
                  // 創建取消按鈕
                  var cancelButton = CreateCancelButton(resultTcs);
      
                  // 綁定掃描結果事件
                  _barcodeReaderView.BarcodesDetected += async (sender, args) =>
                  {
                      // 確保只處理一次結果
                      if (args.Results.Any() && !resultTcs.Task.IsCompleted)
                      {
                          var result = args.Results[0].Value;
      
                          // 掃描成功后震動手機
                          VibrateOnSuccess();
      
                          await StopScanning();
                          resultTcs.SetResult(CreateSuccessResponse(result));
                      }
                  };
      
                  // 構建自定義掃描頁面
                  var scanPage = new CustomScanPage(resultTcs)
                  {
                      BackgroundColor = Colors.Black,
                      Content = new Grid
                      {
                          Children = {
                              mainLayout,   // 掃碼區域
                              cancelButton  // 取消按鈕
                          }
                      }
                  };
      
                  // 設置取消操作的委托
                  scanPage.CancelAction = () => CancelScan(resultTcs);
      
                  return scanPage;
              }
      
              /// <summary>
              /// 創建取消按鈕并綁定事件
              /// </summary>
              /// <param name="resultTcs">用于返回掃描結果的任務完成源</param>
              /// <returns>構建好的取消按鈕</returns>
              private Button CreateCancelButton(TaskCompletionSource<QrScannerResponse> resultTcs)
              {
                  var cancelButton = new Button
                  {
                      Text = "×",
                      TextColor = Colors.White,
                      BackgroundColor = Color.FromArgb("#80000000"),  // 半透明黑色 
                      CornerRadius = 22,  // 圓形按鈕
                      WidthRequest = 44,
                      HeightRequest = 44,
                      FontSize = 24,      // 文字大小
                      FontAttributes = FontAttributes.Bold,
                      HorizontalOptions = LayoutOptions.Start,
                      VerticalOptions = LayoutOptions.Start,
                      Margin = new Thickness(20, 30, 0, 0),
                      Padding = new Thickness(0),  // 移除內邊距,確保符號居中
                      MinimumWidthRequest = 44,    // 設置按鈕點擊區域
                      MinimumHeightRequest = 44
                  };
      
                  // 綁定取消按鈕點擊事件
                  cancelButton.Clicked += (s, e) => CancelScan(resultTcs);
      
                  return cancelButton;
              }
      
              #endregion
      
      
              #region 頁面顯示與控制  private async Task<string> ShowScanPageAsync(ContentPage scanPage)
      
              /// <summary>
              /// 顯示掃描頁面
              /// </summary>
              private async Task<string> ShowScanPageAsync(ContentPage scanPage)
              {
                  try
                  {
                      await MainThread.InvokeOnMainThreadAsync(async () =>
                      {
                          if (Application.Current?.MainPage?.Navigation == null)
                          {
                              throw new Exception(NavigationNullTip);
                          }
                          await Application.Current.MainPage.Navigation.PushModalAsync(scanPage, false);
                      });
                      return null;
                  }
                  catch (Exception ex)
                  {
                      return ex.Message;
                  }
              }
      
              /// <summary>
              /// 準確定位掃描線和提示文字位置
              /// 掃描線位于掃描框內,提示文字位于掃描框下方居中
              /// </summary>
              private string PositionScanElements()
              {
                  try
                  {
                      MainThread.BeginInvokeOnMainThread(() =>
                      {
                          // 獲取屏幕尺寸
                          var mainPage = Application.Current?.MainPage;
                          if (mainPage == null)
                              throw new Exception(ViewInitFailedTip);
      
                          double screenWidth = GetScreenDimension(mainPage.Width, DeviceDisplay.MainDisplayInfo.Width);
                          double screenHeight = GetScreenDimension(mainPage.Height, DeviceDisplay.MainDisplayInfo.Height);
      
                          if (screenWidth <= 0 || screenHeight <= 0)
                              throw new Exception(ScreenSizeErrorTip);
      
                          // 計算掃描框位置(屏幕中央)
                          var scanAreaX = (screenWidth - ScanAreaSize) / 2;
                          var scanAreaY = (screenHeight - ScanAreaSize) / 2;
      
                          // 設置掃描線初始位置(掃描框內偏上位置)
                          SetElementLayout(_scanLine, scanAreaX, scanAreaY + 60, ScanAreaSize, ScanLineMaxHeight);
      
                          // 設置提示文字位置(掃描框下方居中)
                          SetElementLayout(_scanLabel, scanAreaX,
                                         scanAreaY + ScanAreaSize + LabelMarginTop,
                                         ScanAreaSize, 30);
      
                          // 將掃描線和提示文字添加到主布局(確保只添加一次)
                          if (_barcodeReaderView.Parent is AbsoluteLayout mainLayout)
                          {
                              AddElementToLayout(mainLayout, _scanLine);
                              AddElementToLayout(mainLayout, _scanLabel);
                          }
                      });
                      return null;
                  }
                  catch (Exception ex)
                  {
                      return $"掃描元素定位失敗:{ex.Message}";
                  }
              }
      
              /// <summary>
              /// 獲取屏幕尺寸(處理可能的空值和0值)
              /// </summary>
              /// <param name="pageDimension">頁面尺寸</param>
              /// <param name="displayDimension">顯示信息尺寸</param>
              /// <returns>計算后的屏幕尺寸</returns>
              private double GetScreenDimension(double pageDimension, double displayDimension)
              {
                  return pageDimension > 0
                      ? pageDimension
                      : displayDimension / DeviceDisplay.MainDisplayInfo.Density;
              }
      
              /// <summary>
              /// 設置元素在絕對布局中的位置和大小
              /// </summary>
              private void SetElementLayout(View element, double x, double y, double width, double height)
              {
                  AbsoluteLayout.SetLayoutBounds(element, new Rect(x, y, width, height));
                  AbsoluteLayout.SetLayoutFlags(element, AbsoluteLayoutFlags.None);
              }
      
              /// <summary>
              /// 將元素添加到布局中(確保只添加一次)
              /// </summary>
              private void AddElementToLayout(AbsoluteLayout layout, View element)
              {
                  if (element.Parent != layout)
                  {
                      if (element.Parent is Layout parentLayout)
                          parentLayout.Children.Remove(element);
      
                      layout.Children.Add(element);
                  }
              }
      
              #endregion
      
      
              #region 掃描動畫控制  private void StartScanLineAnimation()
      
              /// <summary>
              /// 啟動掃描線動畫
              /// 實現掃描線在掃描區域內上下移動的效果
              /// </summary>
              private void StartScanLineAnimation()
              {
                  _isScanning = true;
      
                  MainThread.BeginInvokeOnMainThread(async () =>
                  {
                      try
                      {
                          // 獲取屏幕尺寸和掃描區域參數
                          var (scanAreaX, scanAreaY, endY) = CalculateScanAreaParameters();
                          if (scanAreaX < 0 || scanAreaY < 0 || endY < 0)
                              return;
      
                          // 初始化掃描線位置和移動方向(從偏下位置開始)
                          var currentY = scanAreaY + 50;  // 初始位置偏下
                          var direction = 1;  // 1 向下移動, -1 向上移動
                          const int speed = 1; // 移動速度(像素/幀)
      
                          // 動畫循環
                          while (_isScanning)
                          {
                              // 更新掃描線位置
                              currentY += direction * speed;
      
                              // 到達邊界時反向移動
                              if (currentY >= endY)
                              {
                                  currentY = endY;
                                  direction = -1;
                              }
                              else if (currentY <= scanAreaY)
                              {
                                  currentY = scanAreaY;
                                  direction = 1;
                              }
      
                              // 應用新位置到掃描線
                              AbsoluteLayout.SetLayoutBounds(_scanLine, new Rect(
                                  scanAreaX,
                                  currentY,
                                  ScanAreaSize,
                                  ScanLineMaxHeight
                              ));
      
                              // 控制動畫幀率(約60fps)
                              await Task.Delay(16);
                          }
                      }
                      catch
                      {
                          // 動畫異常時停止掃描,不拋出異常
                          _isScanning = false;
                      }
                  });
              }
      
              /// <summary>
              /// 計算掃描區域參數
              /// </summary>
              /// <returns>掃描區域的X坐標、Y坐標和結束Y坐標</returns>
              private (double scanAreaX, double scanAreaY, double endY) CalculateScanAreaParameters()
              {
                  var mainPage = Application.Current?.MainPage;
                  if (mainPage == null)
                      return (-1, -1, -1);
      
                  double screenWidth = GetScreenDimension(mainPage.Width, DeviceDisplay.MainDisplayInfo.Width);
                  double screenHeight = GetScreenDimension(mainPage.Height, DeviceDisplay.MainDisplayInfo.Height);
      
                  if (screenWidth <= 0 || screenHeight <= 0)
                      return (-1, -1, -1);
      
                  // 計算掃描區域位置和范圍
                  var scanAreaX = (screenWidth - ScanAreaSize) / 2;
                  var scanAreaY = (screenHeight - ScanAreaSize) / 2;
                  var endY = scanAreaY + ScanAreaSize - ScanLineMaxHeight;
      
                  return (scanAreaX, scanAreaY, endY);
              }
      
              #endregion
      
      
              #region 停止掃描并清理資源  private async Task StopScanning()
      
              /// <summary>
              /// 停止掃描并清理資源
              /// </summary>
              private async Task StopScanning()
              {
                  // 停止掃描動畫
                  _isScanning = false;
      
                  // 停止相機檢測
                  if (_barcodeReaderView != null)
                  {
                      _barcodeReaderView.IsDetecting = false;
                      _barcodeReaderView.IsEnabled = false;
                  }
      
                  // 關閉掃描頁面
                  try
                  {
                      await MainThread.InvokeOnMainThreadAsync(async () =>
                      {
                          if (Application.Current?.MainPage?.Navigation != null)
                          {
                              await Application.Current.MainPage.Navigation.PopModalAsync(false);
                          }
                      });
                  }
                  catch
                  {
                      // 頁面關閉異常不處理,避免影響主流程
                  }
              }
      
              #endregion
      
      
              #region 權限管理  private async Task<string> CheckCameraPermission()
      
              /// <summary>
              /// 檢查并請求相機權限
              /// </summary>
              /// <returns>權限正常返回null,異常返回提示文本</returns>
              private async Task<string> CheckCameraPermission()
              {
                  try
                  {
                      // 檢查相機權限狀態
                      var status = await Permissions.CheckStatusAsync<Permissions.Camera>();
      
                      // 已授權則直接返回
                      if (status == PermissionStatus.Granted)
                          return null;
      
                      // 未授權則請求權限
                      status = await Permissions.RequestAsync<Permissions.Camera>();
                      return status == PermissionStatus.Granted ? null : PermissionDeniedTip;
                  }
                  catch (Exception ex)
                  {
                      return $"相機權限請求失敗:{ex.Message}";
                  }
              }
      
              #endregion
      
      
              #region 取消掃描處理 private async void CancelScan(TaskCompletionSource<QrScannerResponse> resultTcs)
      
              /// <summary>
              /// 統一處理取消掃描的邏輯
              /// 無論是點擊取消按鈕還是按返回鍵都調用此方法
              /// </summary> 
              private async void CancelScan(TaskCompletionSource<QrScannerResponse> resultTcs)
              {
                  if (resultTcs.Task.IsCompleted)
                      return;
      
                  await StopScanning();
                  resultTcs.SetResult(CreateCancelResponse());
              }
      
              #endregion
      
      
              #region 震動功能初始化  private void InitializeVibrator()
      
              /// <summary>
              /// 安全初始化震動管理器
              /// </summary>
              private void InitializeVibrator()
              {
                  try
                  {
      #if ANDROID
                      if (_androidContext != null)
                      {
                          var vibratorService = _androidContext.GetSystemService(Context.VibratorService);
                          if (vibratorService is Vibrator vibrator)
                          {
                              _vibrator = vibrator;
                          }
                      }
      #endif
                  }
                  catch (Exception ex)
                  {
                      System.Diagnostics.Debug.WriteLine($"震動服務初始化失敗: {ex.Message}");
                      _vibrator = null;
                  }
              }
      
              /// <summary>
              /// 掃描成功時震動手機
              /// </summary>
              private void VibrateOnSuccess()
              {
                  try
                  {
      #if ANDROID
                      if (_vibrator != null && HasVibrator())
                      {
                          // 震動100毫秒
                          if (Build.VERSION.SdkInt >= BuildVersionCodes.O)
                          {
                              _vibrator.Vibrate(VibrationEffect.CreateOneShot(100, VibrationEffect.DefaultAmplitude));
                          }
                          else
                          {
                              _vibrator.Vibrate(100);
                          }
                      }
      #endif
                  }
                  catch (Exception ex)
                  {
                      System.Diagnostics.Debug.WriteLine($"震動失敗: {ex.Message}");
                      // 震動失敗不影響主要功能,靜默處理
                  }
              }
      
              /// <summary>
              /// 檢查設備是否支持震動
              /// </summary>
              private bool HasVibrator()
              {
      #if ANDROID
                  return _vibrator?.HasVibrator == true;
      #else
                      return false;
      #endif
              }
      
              #endregion
      
      
              #region 響應對象創建方法 private QrScannerResponse CreateSuccessResponse(string data)
      
              /// <summary>
              /// 創建成功響應
              /// </summary>
              /// <param name="data">二維碼數據</param>
              /// <returns>成功響應對象</returns>
              private QrScannerResponse CreateSuccessResponse(string data)
              {
                  return new QrScannerResponse
                  {
                      Code = ApiCode.Success,
                      Msg = "掃描成功",
                      Data = data
                  };
              }
      
              /// <summary>
              /// 創建取消響應
              /// </summary>
              /// <returns>取消響應對象</returns>
              private QrScannerResponse CreateCancelResponse()
              {
                  return new QrScannerResponse
                  {
                      Code = ApiCode.Exception,
                      Msg = CancelTip,
                      Data = CancelTip
                  };
              }
      
              /// <summary>
              /// 創建錯誤響應
              /// </summary>
              /// <param name="code">錯誤代碼</param>
              /// <param name="message">錯誤信息</param>
              /// <returns>錯誤響應對象</returns>
              private QrScannerResponse CreateErrorResponse(ApiCode code, string message)
              {
                  return new QrScannerResponse
                  {
                      Code = code,
                      Msg = message,
                      Data = null
                  };
              }
      
              #endregion
      
          }
      
      
          /// <summary>
          /// 自定義掃描頁面
          /// </summary>
          public class CustomScanPage : ContentPage
          {
              private readonly TaskCompletionSource<QrScannerResponse> _resultTcs;
      
              public CustomScanPage(TaskCompletionSource<QrScannerResponse> resultTcs)
              {
                  _resultTcs = resultTcs;
              }
      
              protected override bool OnBackButtonPressed()
              {
                  // 調用取消掃描的邏輯
                  CancelAction?.Invoke();
                  return true; // 表示已處理返回鍵事件,不執行默認行為
              }
      
              public Action CancelAction { get; set; }
          }
      

      QrScannerResponse.cs 識別結果返回類

          /// <summary>
          /// 識別結果,返回類
          /// </summary>
          public class QrScannerResponse
          {
              /// <summary>
              /// 狀態碼
              /// </summary>
              public ApiCode Code { get; set; }
      
              /// <summary>
              /// 提示信息
              /// </summary>
              public string Msg { get; set; }
      
              /// <summary>
              /// 識別數據
              /// </summary>
              public string Data { get; set; }
          }
           
          /// <summary>
          /// 狀態碼,枚舉類
          /// </summary>
          public enum ApiCode : int
          {
              /// <summary>
              /// 成功
              /// </summary>
              Success = 10001, 
              /// <summary>
              /// 異常
              /// </summary>
              Exception = 10002, 
              /// <summary>
              /// 無效
              /// </summary>
              InValidData = 10003, 
          }
      

      五、修改 MauiProgram.cs 文件,注冊相關服務

      #if ANDROID 是必不可少的,該條件編譯指令能確保相關邏輯只在 Android 環境中執行.

      點擊查看代碼
      // Add the using to the top
      using ZXing.Net.Maui.Controls;
       
      public static class MauiProgram
      {
          public static MauiApp CreateMauiApp()
          {
              var builder = MauiApp.CreateBuilder();
              builder
                      .UseMauiApp<App>()
                      .UseBarcodeReader(); // Make sure to add this line
      
          #if ANDROID    
              // 注冊Android掃描服務(注入上下文)
              builder.Services.AddSingleton<IQrCodeScanner>(sp =>
                  new Platforms.Android.QrCodeScanner(
                      Android.App.Application.Context // 應用級上下文,避免內存泄漏
                  )
              );
          #endif 
      
              return builder.Build();
          } 
      }
      

      六、通過調用 QrCodeScanner.ScanQrCodeAsync() 方法識別二維碼

      點擊查看代碼
      // 注入QR識別組件服務
      [Inject] private IQrCodeScanner QrCodeScanner { get; set; }
       
       
      
      #region 調用ScanQrCodeAsync實現QR碼識別功能
      /// <summary>
      /// 調用二維碼掃描器
      /// </summary>
      public void OnQrCodeScanner()
      { 
          // 掃描QR碼并處理結果
          QrCodeScanner.ScanQrCodeAsync()
              .ContinueWith(async task =>
              {
                  // 檢查任務是否成功完成
                  if (!task.IsCompletedSuccessfully || task.Result == null)
                      return;
      
                  QrScannerResponse result = task.Result;
      
                  // 檢查掃描結果是否成功
                  if (result.Code != ApiCode.Success)
                  {
                      await dialogService.InfoSnackbarAsync($"掃碼失敗:{result.Msg}")
                          .ConfigureAwait(false);
                      return;
                  }
      
                  try
                  {
                      // 解析二維碼數據為JObject
                      if (string.IsNullOrEmpty(result.Data))
                      {
                          await dialogService.ErrorSnackbarAsync("二維碼數據為空")
                              .ConfigureAwait(false);
                          return;
                      }
                      // 添加數據處理邏輯
                      JObject jObject = JObject.Parse(result.Data);
                      string xx= jObject["xx"]?.ToString() ?? string.Empty; 
                  }
                  catch (Exception)
                  {
                      // 解析失敗時顯示原始內容
                      await dialogService.InfoSnackbarAsync($"識別內容:{result.Data}")
                          .ConfigureAwait(false);
                  }
              }, TaskScheduler.FromCurrentSynchronizationContext());
      }
      #endregion
      

      七、效果圖演示

      image

      posted @ 2025-09-19 12:31  箋上知微  閱讀(64)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 国产又爽又黄又爽又刺激| 男女无遮挡激情视频| 国产精品一区二区麻豆蜜桃| 免费黄色大全一区二区三区| 桃花岛亚洲成在人线AV| 蜜桃臀av一区二区三区| 久久综合干| 亚洲国产日韩一区三区| 日韩一本不卡一区二区三区| 国产偷自视频区视频| 三级国产在线观看| 激情亚洲内射一区二区三区| 色噜噜狠狠成人综合| 免费极品av一视觉盛宴| 97成人碰碰久久人人超级碰oo| 免费全部高h视频无码| av鲁丝一区鲁丝二区鲁丝三区 | 中文人妻av高清一区二区| 久久精品一区二区东京热| 欧美亚洲日本国产综合在线美利坚| 国产一区二区三区av在线无码观看 | 日韩av色一区二区三区| 亚洲国产成人久久77| 亚洲男人电影天堂无码| 国产精品免费看久久久| 青草内射中出高潮| 中文激情一区二区三区四区| 国产高跟黑色丝袜在线| 亚洲真人无码永久在线| 亚洲中文字幕人妻系列| 国产成人综合欧美精品久久| 国产在线中文字幕精品| 人人做人人澡人人人爽| 中文字幕在线永久免费视频| 午夜免费福利小电影| 国产精品论一区二区三区| 国产精品免费AⅤ片在线观看 | 天堂www在线中文| 亚洲色大成网站www看下面| 99在线 | 亚洲| 亚洲第一成人网站|