.Net MAUI Webview 文件上传不起作用

huangapple go评论147阅读模式
英文:

.Net MAUI Webview file upload not working

问题

我在.Net MAUI中非常新手。正在处理一个具有文件上传选项的webview。我已经在AndroidManifest.xml中添加了读/写权限。权限弹窗显示并已授予。但是,没有文件上传器显示出来。

在AndroidManifest.xml中添加了以下内容:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

权限弹窗已授予。但是,没有任何东西显示出来。

我通过Google搜索找到了一些Xamarin代码,但无法实现。是否可以请任何人提供一个适用于.Net MAUI的工作中的webview文件上传代码。

提前感谢。

英文:

I'm very new in .Net MAUI. Working on a webview that have file upload option. I added read/write permissions to AndroidManifest.xml. Permission popup shows and it granted. But, no file uploader shows up.

Added in AndroidManifest.xml
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

Permission popup granted. But, nothing show up.

I found some xamarin code via google search, but can't able to implement. Can anyone please give a .Net MAUI working code for webview file uploder.

Thanks in advance.

答案1

得分: 0

首先,在 \Platforms\Android 文件夹中,您可以声明自定义的 WebViewClient 类和自定义的 WebChromeClient 类:

MyWebClient.cs:

namespace MauiApp1.Platforms.Android
{
    public class MyWebClient : WebViewClient
    {
        public override bool ShouldOverrideUrlLoading(global::Android.Webkit.WebView view, IWebResourceRequest request)
        {
            view.LoadUrl((string)request.Url);
            return true;
        }
    }
}

MyWebChromeClient.cs:

namespace MauiApp1.Platforms.Android
{
    public class MyWebChromeClient : WebChromeClient
    {
        public static int filechooser = 1;
        public static IValueCallback message;

        public override bool OnShowFileChooser(global::Android.Webkit.WebView webView, IValueCallback filePathCallback, FileChooserParams fileChooserParams)
        {
            message = filePathCallback;
            Intent chooserIntent = new Intent(Intent.ActionGetContent);
            chooserIntent.AddCategory(Intent.CategoryOpenable);
            chooserIntent.SetType("*/*");
            Microsoft.Maui.ApplicationModel.Platform.CurrentActivity.StartActivityForResult(Intent.CreateChooser(chooserIntent, "File Chooser"), filechooser);
            return true;
        }
    }
}

然后,在 \Patforms\Android\MainActivity.cs 中添加以下代码:

protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
    base.OnActivityResult(requestCode, resultCode, data);
    if (data != null)
    {
        if (requestCode == MyWebChromeClient.filechooser)
        {
            if (MyWebChromeClient.message != null)
            {
                MyWebChromeClient.message.OnReceiveValue(WebChromeClient.FileChooserParams.ParseResult((int)resultCode, data));
                MyWebChromeClient.message = null;
            }
        }
    }
}

在 XAML 中使用 WebView,例如:

<WebView x:Name="webview" HeightRequest="500"/>

在 page.cs 中为 WebView 设置自定义的 WebViewClient 类和自定义的 WebChromeClient 类:

protected override void OnHandlerChanged()
{
    base.OnHandlerChanged();
#if ANDROID
    var web = webview.Handler.PlatformView as Android.Webkit.WebView;
    web.Settings.JavaScriptEnabled = true;
    web.SetWebViewClient(new Platforms.Android.MyWebClient());
    web.SetWebChromeClient(new Platforms.Android.MyWebChromeClient());
#endif
}
英文:

First of all, you can declare the custom webviewclient class and the custom webchromeclient class in the \Platforms\Android folder:

MyWebClient.cs:

namespace MauiApp1.Platforms.Android
{
    public class MyWebClient : WebViewClient
    {
        public override bool ShouldOverrideUrlLoading(global::Android.Webkit.WebView view, IWebResourceRequest request)
        {
            view.LoadUrl((string)request.Url);
            return true;
        }
    }
}

MyWebChromeClient.cs:

namespace MauiApp1.Platforms.Android
{
    public class MyWebChromeClient : WebChromeClient
    {
        public static int filechooser = 1;
        public static IValueCallback message;


        public override bool OnShowFileChooser(global::Android.Webkit.WebView webView, IValueCallback filePathCallback, FileChooserParams fileChooserParams)
        {
            message = filePathCallback;
            Intent chooserIntent = new Intent(Intent.ActionGetContent);
            chooserIntent.AddCategory(Intent.CategoryOpenable);
            chooserIntent.SetType(&quot;*/*&quot;);
            Microsoft.Maui.ApplicationModel.Platform.CurrentActivity.StartActivityForResult(Intent.CreateChooser(chooserIntent, &quot;File Chooser&quot;), filechooser);
            return true;
        }
    }
}

And then add the following code in the \Patforms\Android\MainActivity.cs:

protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
    {
        base.OnActivityResult(requestCode, resultCode, data);
        if(data !=null)
        {
            if (requestCode == MyWebChromeClient.filechooser)
            {
                if(MyWebChromeClient.message !=null)
                {
                    MyWebChromeClient.message.OnReceiveValue(WebChromeClient.FileChooserParams.ParseResult((int)resultCode, data));
                    MyWebChromeClient.message = null;
                }
            }
        }
    }

Use the webview in the xaml such as:

&lt;WebView x:Name=&quot;webview&quot; HeightRequest=&quot;500&quot;/&gt;

And set the the custom webviewclient class and the custom webchromeclient class for the webview in the page.cs:

protected override void OnHandlerChanged()
    {
        base.OnHandlerChanged();
#if ANDROID
        var web = webview.Handler.PlatformView as Android.Webkit.WebView;
        web.Settings.JavaScriptEnabled = true;
        web.SetWebViewClient( new Platforms.Android.MyWebClient());
        web.SetWebChromeClient(new Platforms.Android.MyWebChromeClient());
#endif
    }

答案2

得分: 0

以下是翻译好的内容:

Step 1. 在 Platfrom/Android 文件夹下修改 MainActivity。

public class MainActivity : MauiAppCompatActivity
{
    public static IValueCallback mUploadCallbackAboveL;
    public static Android.Net.Uri imageUri;
    public static MainActivity Instance;
    public static int PHOTO_REQUEST = 10023;

    protected override void OnCreate(Bundle bundle)
    {
        base.OnCreate(bundle);
        HandleIntent(Intent);
        Instance = this;

        if (ContextCompat.CheckSelfPermission(this, Manifest.Permission.Camera) != (int)Permission.Granted)
        {

        }
    }

    protected override void OnActivityResult(int requestCode, Result resultCode, Android.Content.Intent intent)
    {
        if (resultCode == Result.Ok)
        {
            if (intent != null &amp;&amp; intent.Data != null) // Camera photo
            {
                if (null == mUploadCallbackAboveL) return;
                Android.Net.Uri result = intent == null || resultCode != Result.Ok ? null : intent.Data;
                mUploadCallbackAboveL.OnReceiveValue(new Android.Net.Uri[] { result });
                mUploadCallbackAboveL = null;
            }
            else if (requestCode == PHOTO_REQUEST)
            {
                if (mUploadCallbackAboveL != null)
                {
                    onActivityResultAboveL(requestCode, resultCode, intent);
                }
            }
        }
        else
        {
            if (resultCode != Result.Ok)
            {
                mUploadCallbackAboveL.OnReceiveValue(null);
                mUploadCallbackAboveL = null;
                return;
            }
        }
    }

    private void onActivityResultAboveL(int requestCode, Result resultCode, Android.Content.Intent data)
    {

        if (requestCode != PHOTO_REQUEST || mUploadCallbackAboveL == null)
        {
            return;
        }

        Android.Net.Uri[] results = null;
        if (resultCode == Result.Ok)
        {
            results = new Android.Net.Uri[] { imageUri };
            results[0] = MainActivity.imageUri;
        }

        mUploadCallbackAboveL.OnReceiveValue(results);
        mUploadCallbackAboveL = null;
    }
}

Step 2. 在 Platfrom/Android 文件夹下实现自定义 WebChromeClient。

internal class MyWebChromeClient : WebChromeClient
{
    private MainActivity activity = null;

    public MyWebChromeClient(MainActivity context)
    {
        this.activity = context;
    }

    public override void OnPermissionRequest(PermissionRequest request)
    {
        foreach (var resource in request.GetResources())
        {
            if (resource.Equals(PermissionRequest.ResourceVideoCapture, StringComparison.OrdinalIgnoreCase))
            {
                PermissionStatus status = Permissions.CheckStatusAsync<Permissions.Camera>().Result;

                if (status != PermissionStatus.Granted)
                    request.Deny();
                else
                    request.Grant(request.GetResources());

                return;
            }
        }

        base.OnPermissionRequest(request);
    }

    public override bool OnShowFileChooser(WebView webView, IValueCallback filePathCallback, FileChooserParams fileChooserParams)
    {
        MainActivity.mUploadCallbackAboveL = filePathCallback;

        var imageStorageDir = FileSystem.Current.CacheDirectory;

        var file = new Java.IO.File(imageStorageDir + Java.IO.File.Separator + "IMG_" + DateTime.Now.Ticks + ".jpg");

        MainActivity.imageUri = FileProvider.GetUriForFile(activity, activity.PackageName + ".fileprovider", file);

        var captureIntent = new Intent(MediaStore.ActionImageCapture);
        captureIntent.PutExtra(MediaStore.ExtraOutput, MainActivity.imageUri);

        var i = new Intent(Intent.ActionGetContent);
        i.AddCategory(Intent.CategoryOpenable);
        i.SetType("image/*");

        var chooserIntent = Intent.CreateChooser(i, "Choose Image");
        chooserIntent.PutExtra(Intent.ExtraInitialIntents, new Intent[] { captureIntent });

        MainActivity.Instance.StartActivityForResult(chooserIntent, MainActivity.PHOTO_REQUEST);

        return true;
    }
}

Step 3. 在 Platfrom/Android 文件夹下修改 AndroidManifest.xml。

<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
<uses-feature android:name="android.hardware.camera"/>
<uses-sdk android:minSdkVersion="23" android:targetSdkVersion="33" />
<queries>
    <intent>
        <action android:name="android.media.action.IMAGE_CAPTURE" />
    </intent>
</queries>

Step 4. MainPage.Xaml 如下所示。

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="UPloadFile.MainPage"
             Title="Uplodad file webview">

    <WebView Loaded="WebView_Loaded"
             x:Name="myWebView"
             Source="Source link">
    </WebView>
</ContentPage>

Step 5. MainPage.Xaml.cs 如下所示。

public partial class MainPage : ContentPage
{
    public Dashboard()
    {
        InitializeComponent();
    }

    protected override void OnHandlerChanged()
    {
        base.OnHandlerChanged();

#if ANDROID
        var webview = myWebView.Handler.PlatformView as Android.Webkit.WebView;
        webview.SetWebChromeClient(new STC_Delivery_App.Platforms.Android.MyWebChromeClient(MainActivity.Instance));
        if (webview is not null)
        {
            webview.Settings.MediaPlaybackRequiresUserGesture = false;
            webview.Settings.SetGeolocationEnabled(true);
            webview.Settings.JavaScriptEnabled = true;
        }
#endif
    }

    private async void WebView_Loaded(object sender, EventArgs e)
    {

        PermissionStatus status = await Permissions.CheckStatusAsync<Permissions.Camera>();

        if (status != PermissionStatus.Granted)
        {
            if (Permissions.ShouldShowRationale<Permissions.Camera>()) { }
            await Permissions.RequestAsync<Permissions.Camera>();
        }

        status = await Permissions.CheckStatusAsync<Permissions.StorageRead>();

        if (status != PermissionStatus.Granted)
        {
            if (Permissions.ShouldShowRationale<Permissions.StorageRead>()) { }
            await Permissions.RequestAsync<Permissions.StorageRead>();
        }

        status = await Permissions.CheckStatusAsync<Permissions.StorageWrite>();

        if (status != PermissionStatus.Granted)
        {
            if (Permissions.ShouldShowRationale<Permissions.StorageWrite>()) { }
            await Permissions.RequestAsync<Permissions.StorageWrite>();
        }
    }
}

希望对你有所帮助。

英文:

After lots of back and forth trying, able to solve the issue. Below is my complete solution. Hope it will help other who needs it in future.

Thank you Liyun Zhang - MSFT for your code, it will not solve my purpose.

Step 1. Modify the MainActivity under the Platfrom/Android folder.

public class MainActivity : MauiAppCompatActivity
{
	public static IValueCallback mUploadCallbackAboveL;     
	public static Android.Net.Uri imageUri;     
	public static MainActivity Instance;     
	public static int PHOTO_REQUEST = 10023;

	 protected override void OnCreate(Bundle bundle)     {                   
		base.OnCreate(bundle);         
		HandleIntent(Intent);         
		Instance = this;          

		if (ContextCompat.CheckSelfPermission(this, Manifest.Permission.Camera) != (int)Permission.Granted){          	  

		}     
	}

	protected override void OnActivityResult(int requestCode, Result resultCode, Android.Content.Intent intent)	
	{
		if (resultCode == Result.Ok){             
			if (intent != null &amp;&amp; intent.Data !=null) // Camera photo   {                 
				if (null == mUploadCallbackAboveL) return;                
				Android.Net.Uri result = intent == null || resultCode != Result.Ok ? null : intent.Data;                 	
				//mUploadMessage.OnReceiveValue(result);                 	
				mUploadCallbackAboveL.OnReceiveValue(new Android.Net.Uri[] { result });                 	
				mUploadCallbackAboveL = null;             
			}             
			else if (requestCode == PHOTO_REQUEST){                 
				if (mUploadCallbackAboveL != null){                     	
					onActivityResultAboveL(requestCode, resultCode, intent);                 
				}                             	
			}         
		}         
		else {             
			if (resultCode != Result.Ok){                 
				mUploadCallbackAboveL.OnReceiveValue(null);                 
				mUploadCallbackAboveL = null;                 
				return;             
			}         
		}
	}

	private void onActivityResultAboveL(int requestCode, Result resultCode, Android.Content.Intent data){
	
		if (requestCode != PHOTO_REQUEST || mUploadCallbackAboveL == null){
			return;
		}

		Android.Net.Uri[] results = null;         
		if (resultCode == Result.Ok){             
			results = new Android.Net.Uri[] { imageUri };             
			results[0] = MainActivity.imageUri;         
		}         

		mUploadCallbackAboveL.OnReceiveValue(results);         
		mUploadCallbackAboveL = null;
	}

}

Step 2. Implement a custom WebChromeClient under the Platfrom/Android folder.

internal class MyWebChromeClient : WebChromeClient{

	private MainActivity activity = null;

	public MyWebChromeClient(MainActivity context){             
		this.activity = context;         
	}

	public override void OnPermissionRequest(PermissionRequest request){
		foreach (var resource in request.GetResources()) {                 
			if (resource.Equals(PermissionRequest.ResourceVideoCapture, StringComparison.OrdinalIgnoreCase))                 		
			{	
				// Get the status of the .NET MAUI app&#39;s access to the camera                     
				PermissionStatus status = Permissions.CheckStatusAsync&lt;Permissions.Camera&gt;().Result;                      			
				
				// Deny the web page&#39;s request if the app&#39;s access to the camera is not &quot;Granted&quot;                     
				if (status != PermissionStatus.Granted)                         
					request.Deny();                     
				else                         
					request.Grant(request.GetResources());
                      
				return;                 
			}             
		}            
             
		base.OnPermissionRequest(request);
	}

	public override bool OnShowFileChooser(WebView webView, IValueCallback filePathCallback, FileChooserParams fileChooserParams){
		MainActivity.mUploadCallbackAboveL = filePathCallback;

		//PickPhoto;              
		var imageStorageDir = FileSystem.Current.CacheDirectory;

		// Create picked image file path and name, add ticks to make it unique               
		var file = new Java.IO.File(imageStorageDir + Java.IO.File.Separator + &quot;IMG_&quot; + DateTime.Now.Ticks + &quot;.jpg&quot;);

		//MainActivity.imageUri = Uri.FromFile(file);             
		MainActivity.imageUri = FileProvider.GetUriForFile(activity, activity.PackageName + &quot;.fileprovider&quot;, file);

		//Create camera capture image intent and add it to the chooser               
		var captureIntent = new Intent(MediaStore.ActionImageCapture);             			
		captureIntent.PutExtra(MediaStore.ExtraOutput, MainActivity.imageUri);

		var i = new Intent(Intent.ActionGetContent);             
		i.AddCategory(Intent.CategoryOpenable);             
		i.SetType(&quot;image/*&quot;);

		var chooserIntent = Intent.CreateChooser(i, &quot;Choose Image&quot;);             		
		chooserIntent.PutExtra(Intent.ExtraInitialIntents, new Intent[] { captureIntent });

		MainActivity.Instance.StartActivityForResult(chooserIntent, MainActivity.PHOTO_REQUEST);

		return true;
	}
}    

Step 3. Modify the AndroidManifest.xml under the Platfrom/Android folder.

&lt;uses-permission android:name=&quot;android.permission.CAMERA&quot; /&gt;   
&lt;!--&lt;uses-permission android:name=&quot;android.permission.READ_EXTERNAL_STORAGE&quot; android:maxSdkVersion=&quot;32&quot; /&gt;   &lt;uses-permission android:name=&quot;android.permission.WRITE_EXTERNAL_STORAGE&quot; android:maxSdkVersion=&quot;32&quot; /&gt;--&gt;   &lt;uses-permission android:name=&quot;android.permission.READ_EXTERNAL_STORAGE&quot;/&gt;   
&lt;uses-permission android:name=&quot;android.permission.WRITE_EXTERNAL_STORAGE&quot; /&gt;   
   
&lt;!-- Required only if your app needs to access images or photos that other apps created --&gt;   
&lt;uses-permission android:name=&quot;android.permission.READ_MEDIA_IMAGES&quot; /&gt;   

&lt;!-- Required only if your app needs to access videos that other apps created --&gt;   
&lt;uses-permission android:name=&quot;android.permission.READ_MEDIA_VIDEO&quot; /&gt;   

&lt;!-- Required only if your app needs to access audio files that other apps created --&gt;   
&lt;uses-permission android:name=&quot;android.permission.READ_MEDIA_AUDIO&quot; /&gt;    	
&lt;uses-feature android:name=&quot;android.hardware.camera&quot;/&gt; 	

&lt;uses-sdk android:minSdkVersion=&quot;23&quot; android:targetSdkVersion=&quot;33&quot; /&gt;    
&lt;queries&gt;     
	&lt;intent&gt;       
		&lt;action android:name=&quot;android.media.action.IMAGE_CAPTURE&quot; /&gt;     
	&lt;/intent&gt;  
&lt;/queries&gt;

Step 4. MainPage.Xaml looks like below.

&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot; ?&gt; 
&lt;ContentPage xmlns=&quot;http://schemas.microsoft.com/dotnet/2021/maui&quot;              	
	xmlns:x=&quot;http://schemas.microsoft.com/winfx/2009/xaml&quot;              
	x:Class=&quot;UPloadFile.MainPage&quot;              
	Title=&quot;Uplodad file webview&quot;&gt;              

	&lt;WebView Loaded=&quot;WebView_Loaded&quot;              
		x:Name=&quot;myWebView&quot; 
		Source=&quot;Source link&quot;&gt;         
	&lt;/WebView&gt;  
&lt;/ContentPage&gt;

Step 5. MainPage.Xaml.cs looks like below.
public partial class MainPage : ContentPage
{
public Dashboard(){
InitializeComponent();
}

	protected override void OnHandlerChanged(){
		base.OnHandlerChanged();

		#if ANDROID
			var webview = myWebView.Handler.PlatformView as Android.Webkit.WebView;         
			webview.SetWebChromeClient(new STC_Delivery_App.Platforms.Android.MyWebChromeClient(MainActivity.Instance));          
			if (webview is not null){             
				webview.Settings.MediaPlaybackRequiresUserGesture = false;             	
				webview.Settings.SetGeolocationEnabled(true);             
				webview.Settings.JavaScriptEnabled = true;         
			}
		#endif
	}

	private async void WebView_Loaded(object sender, EventArgs e){
		
		PermissionStatus status = await Permissions.CheckStatusAsync&lt;Permissions.Camera&gt;();

		if (status != PermissionStatus.Granted){             
			if (Permissions.ShouldShowRationale&lt;Permissions.Camera&gt;()) { }              
			await Permissions.RequestAsync&lt;Permissions.Camera&gt;();         
		}

		status = await Permissions.CheckStatusAsync&lt;Permissions.StorageRead&gt;();
		
		if (status != PermissionStatus.Granted){             
			if (Permissions.ShouldShowRationale&lt;Permissions.StorageRead&gt;()) { }              
			await Permissions.RequestAsync&lt;Permissions.StorageRead&gt;();         
		}

		status = await Permissions.CheckStatusAsync&lt;Permissions.StorageWrite&gt;();

		if (status != PermissionStatus.Granted){             
			if (Permissions.ShouldShowRationale&lt;Permissions.StorageWrite&gt;()) { }              
			await Permissions.RequestAsync&lt;Permissions.StorageWrite&gt;();         
		}
	}
}

huangapple
  • 本文由 发表于 2023年8月10日 19:49:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/76875480.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定