Xamarin - 在WebView中请求相机权限

5
我想为我的Web应用程序制作一个容器应用,我决定使用Xamarin进行开发,因为项目的其余部分也是.NET。最初,我从Xamarin示例页面下载和设置了项目:https://learn.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/webview?tabs=windows。我只是在WebPage.cs中更改了一些变量:https://github.com/xamarin/xamarin-forms-samples/blob/master/WorkingWithWebview/WorkingWithWebview/WebPage.cs
using Xamarin.Forms;

namespace WorkingWithWebview
{
    public class WebPage : ContentPage
    {
        public WebPage()
        {
            var browser = new WebView();
            browser.Source = "https://xamarin.swappsdev.net";
            Content = browser;
        }
    }
}

其次,我根据自己的需求更新了App.cs:https://github.com/xamarin/xamarin-forms-samples/blob/master/WorkingWithWebview/WorkingWithWebview/App

using Xamarin.Forms;

namespace WorkingWithWebview
{
    public class App : Application
    {
        public App ()
        {
            MainPage = new WebPage();
        }
    }
}

然后,轰隆一声!我有了一个应用程序。

接下来是真正的挑战。在Web应用程序中,当我在浏览器中打开网站(https://xamarin.swappsdev.net)并单击按钮请求设备权限,然后在同一窗口中显示摄像头反馈。

但是在应用程序中执行相同的操作时,没有任何反应。

我开始搜索答案,但实际上找到的并不多。而且我发现的答案似乎是Xamarin的旧版本?因为我无法将答案中的文件和结构与Xamarin示例页面中的文件和结构进行比较。 https://dev59.com/pavka4cB1Zd3GeqPxbQy#50560855

我尝试了Robbit的答案。经过长时间的挣扎,我成功编译并安装了它到我的设备上,但它实际上并没有请求权限。

我感到很困惑,需要一些帮助和指导。


希望这可以帮到你,https://github.com/jamesmontemagno/PermissionsPlugin - MrLu
3个回答

9

更新:

在我之前的回答中,展示了如何在webview上添加相机权限。

您提供的链接现在可以使用:https://xamarin.swappsdev.net/。它似乎提供了相机预览功能,需要在API 23+上检查权限。

在Xamarin.Forms中,您可以使用Permissions插件:https://github.com/jamesmontemagno/PermissionsPlugin

首先,在Android清单文件中添加相机权限:在Your Project.Android> Properties> Android Manifest> Required permissions> Camera中进行添加。然后,它将在AndroidManifest.xml中生成用户权限。

  <uses-permission android:name="android.permission.CAMERA" />

创建一个 Utils.cs 文件。
public static class Utils
{
    public static async Task<PermissionStatus> CheckPermissions(Permission permission)
    {
        var permissionStatus = await CrossPermissions.Current.CheckPermissionStatusAsync(permission);
        bool request = false;
        if (permissionStatus == PermissionStatus.Denied)
        {
            if (Device.RuntimePlatform == Device.iOS)
            {

                var title = $"{permission} Permission";
                var question = $"To use this plugin the {permission} permission is required. Please go into Settings and turn on {permission} for the app.";
                var positive = "Settings";
                var negative = "Maybe Later";
                var task = Application.Current?.MainPage?.DisplayAlert(title, question, positive, negative);
                if (task == null)
                    return permissionStatus;

                var result = await task;
                if (result)
                {
                    CrossPermissions.Current.OpenAppSettings();
                }

                return permissionStatus;
            }

            request = true;

        }

        if (request || permissionStatus != PermissionStatus.Granted)
        {
            var newStatus = await CrossPermissions.Current.RequestPermissionsAsync(permission);

            if (!newStatus.ContainsKey(permission))
            {
                return permissionStatus;
            }

            permissionStatus = newStatus[permission];

            if (newStatus[permission] != PermissionStatus.Granted)
            {
                permissionStatus = newStatus[permission];
                var title = $"{permission} Permission";
                var question = $"To use the plugin the {permission} permission is required.";
                var positive = "Settings";
                var negative = "Maybe Later";
                var task = Application.Current?.MainPage?.DisplayAlert(title, question, positive, negative);
                if (task == null)
                    return permissionStatus;

                var result = await task;
                if (result)
                {
                    CrossPermissions.Current.OpenAppSettings();
                }
                return permissionStatus;
            }
        }

        return permissionStatus;
    }
}

在MainActivity.cs中,在OnCreate方法中添加以下代码。
 Plugin.CurrentActivity.CrossCurrentActivity.Current.Init(this, savedInstanceState);

需要在MainActivity.cs中添加OnRequestPermissionsResult方法。
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, 
[GeneratedEnum] Android.Content.PM.Permission[] grantResults)
{
    PermissionsImplementation.Current.OnRequestPermissionsResult(requestCode, permissions, grantResults);
    base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}

然后实现它。

private async void _button_Clicked(object sender, EventArgs e)
    {
        webView.Source = "https://xamarin.swappsdev.net/";//"https://test.webrtc.org/";

        var status = PermissionStatus.Unknown;

        status = await CrossPermissions.Current.CheckPermissionStatusAsync(Permission.Camera);

        if (status != PermissionStatus.Granted)
        {

            status = await Utils.CheckPermissions(Permission.Camera);
        }

    }

在此输入图片描述

我已经将它上传到我的GitHub。请检查文件夹Test/CameraRuntimePermission_WebView/RuntimePermission。

https://github.com/WendyZang/Test.git

编辑:

如果您不想在按钮单击事件中调用它,您可以删除MainPage.xaml中的按钮。

MainPage.xaml.cs

 public MainPage()
    {
        InitializeComponent();
        webView.Source = "https://xamarin.swappsdev.net/";
    }

    protected override void OnAppearing()
    {
        base.OnAppearing();
        RunTimePermission();
    }

    public async void RunTimePermission()
    {
        var status = PermissionStatus.Unknown;

        status = await CrossPermissions.Current.CheckPermissionStatusAsync(Permission.Camera);

        if (status != PermissionStatus.Granted)
        {

            status = await Utils.CheckPermissions(Permission.Camera);
        }

    }

enter image description here


温迪,这太棒了!非常感谢。最后一个问题,按按钮是否必要,还是可以在启动应用程序时触发权限请求或使用某种闪屏界面? - Hans
不,你可以在没有按钮的情况下加载,但是需要在页面加载后请求运行时权限。我在我的编辑中提供了代码。 - Wendy Zang - MSFT
我并不自豪地承认,我错过了你将 webView.Source = "https://xamarin.swappsdev.net/"; 移动到构造函数中的部分。这让我花了一些时间弄清楚为什么我只看到一个白屏,但除此之外,它完美运行。非常感谢你的帮助和时间!! - Hans

4

在跟随几个指南来启用WebView的照相机之后,我终于成功了。

我按照以上所有步骤操作,尽管弹出窗口询问是否允许使用照相机,但我不能去掉权限错误(即使调试显示已授权)。然后,我用如下代码(Wendy给出的MyWebViewRenderer代码见上文)替换MyWebViewRenderer代码,并用以下代码(来源于https://forums.xamarin.com/discussion/183988/how-to-give-camera-and-microphone-permission-to-webview-with-xamarin-forms-on-android):

[assembly: ExportRenderer(typeof(CustomWebView), typeof(CustomWebViewRenderer))]
namespace App19F_8.Droid
{
    public class CustomWebViewRenderer : WebViewRenderer
    {
        public CustomWebViewRenderer(Context context) : base(context)
        {
        }
        protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.WebView> e)
        {
            base.OnElementChanged(e);

            if (e.NewElement != null)
            {
                Control.SetWebChromeClient(new MyWebChromeClient(MainActivity.Instance));
                Control.Settings.JavaScriptEnabled = true;
            }
        }
    }

    public class MyWebChromeClient : WebChromeClient
    {
        Activity mActivity = null;
        public MyWebChromeClient(Activity activity)
        {
            mActivity = activity;
        }
        public override void OnPermissionRequest(PermissionRequest request)
        {
            mActivity.RunOnUiThread(() => {
                request.Grant(request.GetResources());
            });
        }
    }
}

如果上面的链接失效了,我应该提到在Android的MainActivity中你需要插入以下内容:
 public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
    {
        public static MainActivity Instance { get; private set; }
        protected override void OnCreate(Bundle savedInstanceState)
        {
            ...
            base.OnCreate(savedInstanceState);

            Instance = this;
            global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
            LoadApplication(new App());
        }
}

现在相机终于可以工作了 :-) 我不是很确定之前代码的问题所在。非常感谢Wendy,Yelinzh和所有人的详尽回复。


2
感谢您的输入!您永远不知道这些信息何时会变得相关,因此我很感激您花时间编写这个答案。 - Hans
1
它按预期工作了。谢谢您抽出宝贵的时间撰写这个答案。请问在iOS中是否需要类似的过程? - Thameem
@Thameem - 很抱歉回复晚了 - 不幸的是我还没有在iOS上测试过这个功能 - 只在Android上测试过。希望你已经解决了问题... - Daniël J.M. Hoffman
1
它可以工作了!值得一提的是,需要创建一个CustomWebView并像这里提到的那样使用它:https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/custom-renderer/hybridwebview - Daniel
1
对于IOS,您只需要为您的应用程序授予相机权限,在我的情况下,我没有改变任何其他内容。 - Flying light
显示剩余2条评论

2
我尝试着实现了Robbit在这里提供的答案。经过长时间的努力,我成功编译并安装到我的设备上,但它实际上没有请求权限。
我尝试了Robbit在链接中提供的代码。
Camera on Xamarin WebView 实际上,它很好用。为了更好的理解,您可以使用下面的链接进行检查。https://test.webrtc.org/ 如果我直接使用webview来加载url,它会抛出以下错误。 enter image description here 如果我使用Robbit的自定义渲染器,则会使用MyWebViewRenderer中的代码请求权限。
public override void OnPermissionRequest(PermissionRequest request)
        {
            mContext.RunOnUiThread(() =>
            {
                request.Grant(request.GetResources());

            });

        }

enter image description here

我也检查了你使用的链接,没有任何反应。该链接无法在Android设备上打开相机。

enter image description here

使用Robbit的代码。

enter image description here

在您的项目中创建MyWebView。

public class MyWebView : WebView
{

}

在您的项目的Android部分中创建MyWebViewRenderer.cs文件。
[assembly: ExportRenderer(typeof(MyWebView), typeof(MyWebViewRenderer))]
namespace WebViewDemo.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());

            });

        }
    }
    }
}

Usage:

MainPage.xaml

 <StackLayout>
    <Button x:Name="_button" Clicked="_button_Clicked" />
    <local:MyWebView
        x:Name="webView"
        HeightRequest="500"
        WidthRequest="500" />
</StackLayout>

MainPage.xaml.cs

private void _button_Clicked(object sender, EventArgs e)
    {
        webView.Source = "https://test.webrtc.org/";//"https://xamarin.swappsdev.net/";
    }

您可以从GitHub文件夹CameraRuntimePermission_WebView下载整个项目。 Page1用于测试与webview的链接。 MainPage用于使用自定义渲染器进行测试。 https://github.com/WendyZang/Test.git

嗨Wendy,非常感谢您详细的回复。然而,我仍然遇到了同样的权限问题。我加载了您的“CameraRuntimePermission_WebView”项目,并尝试在没有任何修改的情况下运行它。它编译得很好,并像您在gif中显示的那样向我显示空白按钮,但它也告诉我它无法访问webrtc测试所需的硬件。 之后,我尝试使用自己的链接:这是我在自己的链接上运行时的日志。 https://pastebin.com/3c9nKsTd这就是我通常会撞到的墙。它从来不会要求权限。 - Hans
我已经修复了错误,需要一些时间来编辑我的回复。请稍等片刻。 - Wendy Zang - MSFT
感谢您抽出宝贵的时间撰写这个答案,非常感激!它按预期工作了。 - Thameem

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接