Maui Blazor uses camera implementation


# Maui Blazor uses the camera to achieve

Since the interface in Maui Blazor is rendered by WebView, it cannot be obtained when using the Android camera. Because the native camera needs to be bound to interface components, I found other implementation methods. Using js to call the device camera through WebView supports multi-platform
compatibility At present, Android and PC have been tested. Since there is no ioc and mac, it is impossible to test. There is a high probability that it is compatible and may need to dynamically apply for permissions.

## 1. Add js method
We create a `helper.js` file in wwwroot and add the following two js functions
and add `<script src="helper.js"></script> in `index.html` `Introduce js

```js

/**
 * Set the src of the element
 * @param {any} canvasId canvasId dom id
 * @param {any} videoId video dom id
 * @param {any} srcId img dom id
 * @param {any} widht set screenshot Width
 * @param {any} height Set screenshot height
 */
function setImgSrc(dest,videoId, srcId, width, height) {     let video = document.getElementById(videoId);     let canvas = document.getElementById(canvasId);     console.log (video.clientHeight, video.clientWidth);     canvas.getContext('2d').drawImage(video, 0, 0, width, 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)";
        });
    }
}
```

Then the compatibility of each platform

android:

Platforms/Android/AndroidManifest.xml file content

```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" />
    <!--Camera feature-->

    <!--音频录制权限-->
    <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 file content

```c#
[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);         // apply for         ActivityCompat.RequestPermissions(this, new[] { Manifest.Permission.Camera, Manifest.Permission.RecordAudio, Manifest.Permission.ModifyAudioSettings }, 0);     } } ```








MauiWebChromeClient.cs file content

```c#
#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
```

Add the following code in `MauiProgram.cs`; if there is no following code, there will be no camera permission,
which is reflected in this [issue](https://github.com/dotnet/maui/issues/3694)

```c#

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

The above is the adaptation code for android. PC does not need to set additional code. Ios and mac are not clear.

Then write the interface

```razor
@page "/" @*interface routing*@

@inject IJSRuntime JSRuntime @*inject jsRuntime*@

@if(OpenCameraStatus) @*Do not display video when the camera is not opened*@
{     <video id="@VideoId" width="@widht" height="@height" />     <canvas class="d-none " id="@CanvasId" width="@widht" height="@height" /> } < button @οnclick="" style="margin:8px">Open camera</button>  @*Because the camera must be a user Manual trigger If the interface is sliding to enter, you cannot directly call the method to open the camera, so add a button to trigger *@ <button style="margin:8px">Screenshot</button> @*Take a picture of the video stream*@





<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)         {             // Since the condition for opening the camera must be manually triggered by the user, if the user slides to switch to the interface, it cannot be triggered             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);
    }
}
```

Then you can run the program to see our effect

Sample code: [gitee](https://gitee.com/hejiale010426/main-sample) [github](https://github.com/239573049/main-sample)

Come share with token

Technical exchange group: 737776595

Guess you like

Origin blog.csdn.net/xiaohucxy/article/details/128654918