Xamarin Webview - вызов диалогового окна выбора файла - PullRequest
0 голосов
/ 06 августа 2020

У меня есть приложение Xamarin.Forms с веб-просмотром, когда я просматриваю веб-страницы и нажимаю на ввод, чтобы открыть «диалоговое окно выбора файла», диалоговое окно не появляется.

Итак, у меня есть создал свой собственный WebViewRenderer, чтобы разрешить некоторые операции, но никак, я не могу найти способ заставить его работать.

Я добавил это, но это не помогает: Control.Settings.AllowFileAccess = true;

У меня вообще нет сообщения об ошибке ... у кого-то есть идея?

PS: Я искал другие сообщения, но, похоже, ничего не помогло.

Вот код WebViewRenderer для Android:

using Foundation;
using SmartPixel.SoCloze.Mobile.Interop;
using SmartPixel.SoCloze.Mobile.iOS.Renderers;
using System.Net;
using WebKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;

[assembly: ExportRenderer(typeof(HybridWebView), typeof(HybridWebViewRenderer))]
namespace SmartPixel.SoCloze.Mobile.iOS.Renderers
{
    public class HybridWebViewRenderer : WkWebViewRenderer, IWKScriptMessageHandler
    {
        private const string JavaScriptFunction = "function invokeCSharpAction(data){window.webkit.messageHandlers.invokeAction.postMessage(data);}";
        private WKUserContentController _userController;

        public HybridWebViewRenderer() : this(new WKWebViewConfiguration())
        {
        }

        public HybridWebViewRenderer(WKWebViewConfiguration config) : base(config)
        {
            _userController = config.UserContentController;
            var script = new WKUserScript(new NSString(JavaScriptFunction), WKUserScriptInjectionTime.AtDocumentEnd, false);
            _userController.AddUserScript(script);
            _userController.AddScriptMessageHandler(this, "invokeAction");
        }

        protected override void OnElementChanged(VisualElementChangedEventArgs e)
        {
            base.OnElementChanged(e);

            //---- Interop
            if (e.OldElement != null)
            {
                _userController.RemoveAllUserScripts();
                _userController.RemoveScriptMessageHandler("invokeAction");
                HybridWebView hybridWebViewMain = e.OldElement as HybridWebView;
                hybridWebViewMain?.Cleanup();
            }

            if (e.NewElement != null)
            {
            }

            //---- Cookies
            if (e.OldElement == null)
            {
                HybridWebView hybridWebViewMain = this.Element as HybridWebView;
                hybridWebViewMain.OnRequestNativeSetCookie += AppCookiesManager_OnSetCookie;
                hybridWebViewMain.OnRequestNativeCookieRead += HybridWebView_OnRequestNativeCookieRead;
                hybridWebViewMain.OnRequestNativeCookieWrite += HybridWebView_OnRequestNativeCookieWrite;
            }
        }

        public void DidReceiveScriptMessage(WKUserContentController userContentController, WKScriptMessage message)
        {
            ((HybridWebView)Element).InvokeAction(message.Body.ToString());
        }

        private async void AppCookiesManager_OnSetCookie(Cookie cookie)
        {
            string js = $"document.cookie = '{cookie.Name}={cookie.Value};Secure;path=/'";
            this.EvaluateJavaScript(js, null);
        }

        private void HybridWebView_OnRequestNativeCookieRead(string url, CookieCollection cookies)
        {
        }

        private void HybridWebView_OnRequestNativeCookieWrite(string url, CookieCollection cookies)
        {
        }
    }
}

1 Ответ

0 голосов
/ 08 августа 2020

Я нашел решение, после нескольких часов исследований, надеюсь, оно поможет другим. Мне пришлось переопределить метод OnShowFileChooser.

Я предоставляю полный код Android HybridWebView:

public class HybridWebViewRenderer : WebViewRenderer
    {
        private const string JavascriptFunction = "function invokeCSharpAction(data){jsBridge.invokeAction(data);}";
        private Context _context;

        public HybridWebViewRenderer(Context context) : base(context)
        {
            _context = context;
            global::Android.Webkit.WebView.SetWebContentsDebuggingEnabled(true);
        }

        protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.WebView> e)
        {
            base.OnElementChanged(e);

            //---- Interop
            if (e.OldElement != null)
            {
                Control.RemoveJavascriptInterface("jsBridge");
                ((HybridWebView)Element).Cleanup();
            }
            if (e.NewElement != null)
            {
                Control.AddJavascriptInterface(new JsBridge(this), "jsBridge");
            }

            //---- Cookies
            if (e.OldElement == null)
            {
                Control.Settings.AllowFileAccess = true;
                Control.Settings.AllowFileAccessFromFileURLs = true;
                Control.Settings.AllowUniversalAccessFromFileURLs = true;
                Control.SetWebViewClient(new CookieWebViewClient(Element as HybridWebView));
                Control.SetWebChromeClient(new HybridWebChromeClient(_context));
            }
        }
    }

    internal class HybridWebChromeClient : WebChromeClient
    {
        private Context _context;
        private MainActivity _mainActivity;

        public HybridWebChromeClient(Context context)
        {
            _context = context;
            _mainActivity = context as MainActivity;
        }

        [TargetApi(Value = 21)]
        public override void OnPermissionRequest(PermissionRequest request)
        {
            ((Android.App.Activity)_context).RunOnUiThread(() =>
            {
                request.Grant(request.GetResources());
            });
        }

        public override bool OnShowFileChooser(Android.Webkit.WebView webView, IValueCallback filePathCallback, FileChooserParams fileChooserParams)
        {
            _mainActivity._uploadMessage = filePathCallback;
            Intent i = new Intent(Intent.ActionGetContent);
            i.AddCategory(Intent.CategoryOpenable);
            i.SetType("*/*");

            // The camera intent
            Intent captureIntent = new Intent(Android.Provider.MediaStore.ActionImageCapture);

            List<IParcelable> targetedShareIntents = new List<IParcelable>();
            targetedShareIntents.Add(captureIntent);
            captureIntent.AddCategory(Intent.ActionCameraButton);

            //add camera intent to the main intent (i)
            i.PutExtra(Intent.ExtraInitialIntents, targetedShareIntents.ToArray());
            _mainActivity.StartActivityForResult(Intent.CreateChooser(i, "File Chooser"), 1);
            return true;
        }

        //public override bool OnShowFileChooser(Android.Webkit.WebView webView, IValueCallback filePathCallback, FileChooserParams fileChooserParams)
        //{
        //    _mainActivity.mUploadMessage = filePathCallback;
        //    Intent Fileintent = new Intent(Intent.ActionGetContent);
        //    Fileintent.AddCategory(Intent.CategoryOpenable);
        //    Fileintent.SetType("/");
        //    var intents = new List<Intent>();
        //    if (_context.PackageManager.HasSystemFeature(PackageManager.FeatureCameraAny))
        //    {
        //        Intent captureIntent = new Intent(Android.Provider.MediaStore.ActionImageCapture);
        //        var resolveinfolist = _context?.PackageManager?.QueryIntentActivities(captureIntent, 0);
        //        if (resolveinfolist != null && resolveinfolist.Count > 0)
        //        {
        //            var item = resolveinfolist[0];
        //            var packagename = item.ActivityInfo?.PackageName;
        //            var intent = new Intent(captureIntent);
        //            intent.SetComponent(new ComponentName(packagename, item.ActivityInfo.Name));
        //            intent.SetPackage(packagename);
        //            intent.AddFlags(ActivityFlags.GrantReadUriPermission);
        //            intent.AddFlags(ActivityFlags.GrantWriteUriPermission);

        //            File storageDir = new File(Environment.ExternalStorageDirectory, "filename");
        //            var file = Android.OS.Environment.GetExternalStoragePublicDirectory(Environment.DirectoryPictures);
        //            _mainActivity.ImageFile = storageDir;

        //            var uri = FileProvider.GetUriForFile(_context, _context.PackageName + ".provider", storageDir);
        //            intent.PutExtra(Android.Provider.MediaStore.ExtraOutput, uri);

        //            intents.Add(intent);
        //        }
        //    }

        //    intents.Add(Fileintent);
        //    var res = Intent.CreateChooser(intents[0], fileChooserParams.Title);
        //    intents?.RemoveAt(0);
        //    res.PutExtra(Intent.ExtraInitialIntents, intents?.ToArray());
        //    _mainActivity.StartActivityForResult(res, 1000);
        //    return true;

        //}

    }

    internal class CookieWebViewClient : WebViewClient
    {
        private readonly HybridWebView _hybridWebView;

        internal CookieWebViewClient(HybridWebView hybridWebView)
        {
            _hybridWebView = hybridWebView;
            _hybridWebView.OnRequestNativeSetCookie += AppCookiesManager_OnSetCookie;
            _hybridWebView.OnRequestNativeCookieRead += HybridWebView_OnRequestNativeCookieRead;
            _hybridWebView.OnRequestNativeCookieWrite += HybridWebView_OnRequestNativeCookieWrite;
        }

        private void HybridWebView_OnRequestNativeCookieWrite(string url, CookieCollection cookies)
        {
            CookieManager.Instance.Flush();
        }

        private void HybridWebView_OnRequestNativeCookieRead(string url, CookieCollection cookies)
        {
        }

        private void AppCookiesManager_OnSetCookie(Cookie cookie)
        {
            string cookieValue = cookie.Value;
            string cookieDomain = cookie.Domain;
            string cookieName = cookie.Name;
            // Path
            // Secure
            // Expires

            string currentCookie = CookieManager.Instance.GetCookie(cookieDomain) ?? "";

            CookieManager.Instance.SetCookie(cookieDomain, cookieName + "=" + cookieValue + ";" + currentCookie);
            CookieManager.Instance.Flush();
        }

        public override void OnPageFinished(global::Android.Webkit.WebView view, string url)
        {
            // Set all the cookies on the view
            if (Build.VERSION.SdkInt < BuildVersionCodes.Lollipop)
                CookieSyncManager.Instance.Sync();

            CookieManager.Instance.Flush();
            CookieManager.AllowFileSchemeCookies();
            CookieManager.SetAcceptFileSchemeCookies(true);
            CookieManager.Instance.AcceptCookie();
            CookieManager.Instance.AcceptThirdPartyCookies(view);
            CookieManager.Instance.SetAcceptCookie(true);
            CookieManager.Instance.SetAcceptThirdPartyCookies(view, true);
        }

    }
...