Maui Blazor でカメラ機能を実装する方法

Maui Blazor でカメラ機能を実装する方法

Maui Blazor ではインターフェースが WebView でレンダリングされるため、Android のカメラを使用する際に画面コンポーネントにバインドする必要があるため、カメラを取得できません。

最終更新 2023/01/12 20:51
dotnet-simple
読了目安 5 分
カテゴリ
MAUI Blazor
タグ
.NET C# Blazor MAUI

本記事は読者からの投稿です。

作者:dotnet-simple

原文タイトル:Maui Blazor を使用したカメラ実装方法

原文リンク:https://www.cnblogs.com/hejiale010426/p/17045707.html

Maui Blazor ではインターフェースが WebView でレンダリングされるため、Android のカメラを直接使用することができません。ネイティブのカメラは UI コンポーネントにバインドする必要があるからです。そこで別の実装方法を見つけました。WebView を介して js からデバイスのカメラを呼び出す方法で、マルチプラットフォームに対応しています。現在 AndroidPC でテスト済みで、iOSmacOS は未テストですが、おそらく互換性はあるでしょう。動的なパーミッション申請が必要かもしれません。

  1. js メソッドの追加

wwwroothelper.js ファイルを作成し、以下の 2 つの js 関数を追加します。

index.html<script src="helper.js"></script> を追加して js を読み込みます。

/**
 * 要素のsrcを設定する
 * @param {any} canvasId canvasIdのdom id
 * @param {any} videoId videoのdom id
 * @param {any} srcId imgのdom id
 * @param {any} widht スクリーンショットの幅を設定
 * @param {any} height スクリーンショットの高さを設定
 */
function setImgSrc(dest, videoId, srcId, widht, height) {
  let video = document.getElementById(videoId);
  let canvas = document.getElementById(canvasId);
  console.log(video.clientHeight, video.clientWidth);

  canvas.getContext("2d").drawImage(video, 0, 0, widht, height);

  canvas.toBlob(
    function (blob) {
      var src = document.getElementById(srcId);
      src.setAttribute("height", height);
      src.setAttribute("width", widht);
      src.setAttribute("src", URL.createObjectURL(blob));
    },
    "image/jpeg",
    0.95
  );
}

/**
 * カメラを初期化する
 * @param {any} src
 */
function startVideo(src) {
  if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
    navigator.mediaDevices
      .getUserMedia({ video: true })
      .then(function (stream) {
        let video = document.getElementById(src);
        if ("srcObject" in video) {
          video.srcObject = stream;
        } else {
          video.src = window.URL.createObjectURL(stream);
        }
        video.onloadedmetadata = function (e) {
          video.play();
        };
        //mirror image
        video.style.webkitTransform = "scaleX(-1)";
        video.style.transform = "scaleX(-1)";
      });
  }
}

次に各プラットフォームへの対応です。

android:

Platforms/Android/AndroidManifest.xml ファイルの内容

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
	<application android:allowBackup="true" android:supportsRtl="true"></application>
	<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
	<uses-permission android:name="android.permission.INTERNET" />
	<!--カメラ権限-->
	<uses-permission android:name="android.permission.CAMERA" android:required="false"/>
	<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
	<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
	<!--カメラ機能-->
	<uses-feature android:name="android.hardware.camera" />
	<!--音声録音権限-->
	<uses-permission android:name="android.permission.RECORD_AUDIO" />
	<!--位置情報権限-->
	<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

	<!-- Needed only if your app targets Android 5.0 (API level 21) or higher. -->
	<uses-feature android:name="android.hardware.location.gps" />

	<queries>
		<intent>
			<action android:name="android.intent.action.VIEW" />
			<data android:scheme="http"/>
		</intent>
		<intent>
			<action android:name="android.intent.action.VIEW" />
			<data android:scheme="https"/>
		</intent>
	</queries>
</manifest>

Platforms/Android/MainActivity.cs ファイルの内容

[Activity(Theme = "@style/Maui.SplashTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize | ConfigChanges.Density)]
public class MainActivity : MauiAppCompatActivity
{
    protected override void OnCreate(Bundle savedInstanceState)
    {
        base.OnCreate(savedInstanceState);
        Platform.Init(this, savedInstanceState);
        // 必要な権限を申請(使用時に申請することも可能)
        ActivityCompat.RequestPermissions(this, new[] { Manifest.Permission.Camera, Manifest.Permission.RecordAudio, Manifest.Permission.ModifyAudioSettings }, 0);
    }
}

MauiWebChromeClient.cs ファイルの内容

#if ANDROID
using Android.Webkit;
using Microsoft.AspNetCore.Components.WebView.Maui;

namespace MainSample;

public class MauiWebChromeClient : WebChromeClient
{
    public override void OnPermissionRequest(PermissionRequest request)
    {
        request.Grant(request.GetResources());
    }
}

public class MauiBlazorWebViewHandler : BlazorWebViewHandler
{
    protected override void ConnectHandler(Android.Webkit.WebView platformView)
    {
        platformView.SetWebChromeClient(new MauiWebChromeClient());
        base.ConnectHandler(platformView);
    }
}

#endif

MauiProgram.cs に以下のコードを追加します。これを追加しないとカメラ権限が不足します(詳細はこちらの issue を参照)。

#if ANDROID
builder.ConfigureMauiHandlers(handlers =>
{
    handlers.AddHandler<IBlazorWebView, MauiBlazorWebViewHandler>();
});
#endif

以上が android 向けの適応コードです。PC では追加のコードは不要です。iOSmacOS については不明です。

次に UI を作成します。

@page "/" @*ページルーティング*@

@inject IJSRuntime JSRuntime @*jsRuntimeを注入*@

@if(OpenCameraStatus) @*カメラが開かれていない場合、videoを表示しない*@
{
    <video id="@VideoId" width="@widht" height="@height" />
    <canvas class="d-none" id="@CanvasId" width="@widht" height="@height" />
}
<button @onclick="" style="margin:8px">カメラを開く</button>
@*カメラはユーザーの手動操作が必要なため、スライド遷移で画面が表示されただけでは直接起動できません。そのためボタンでトリガーします*@
<button style="margin:8px">スクリーンショット</button> @*ビデオストリームから画像をキャプチャ*@

<img id="@ImgId" />

@code{
    private string CanvasId;
    private string ImgId;
    private string VideoId;
    private bool OpenCameraStatus;
    private int widht = 320;
    private int height = 500;

    private async Task OpenCamera()
    {
        if (!OpenCameraStatus)
        {
            // カメラを開く条件はユーザーの手動操作である必要があります(スライド遷移ではトリガー不可)
            await JSRuntime.InvokeVoidAsync("startVideo", "videoFeed");
            OpenCameraStatus = true;
            StateHasChanged();
        }
    }

    protected override async Task OnInitializedAsync()
    {
        // idを初期化
        ImgId = Guid.NewGuid().ToString("N");
        CanvasId = Guid.NewGuid().ToString("N");
        VideoId = Guid.NewGuid().ToString("N");
        await base.OnInitializedAsync();
    }

    private async Task Screenshot()
    {
        await JSRuntime.InvokeAsync<String>("setImgSrc", CanvasId,VideoId, ImgId, widht, height);
    }
}

その後、プログラムを実行すると以下のように表示されます。

サンプルコード:

  • gitee:https://gitee.com/hejiale010426/main-sample
  • github:https://github.com/239573049/main-sample

token からの共有です。

技術交流グループ:737776595

さらに探索

関連読書

その他の記事
同じカテゴリ / 同じタグ 2022/04/26

MAUIでMasa Blazorを使用する

`.NET MAUI` を使用すると、`Android`、`iOS`、`macOS`、`Windows`、Linux(コミュニティサポート)向けのアプリを単一の共有コードベースから開発でき、1つのコードで複数のプラットフォームで実行できます。

続きを読む