Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
È Xamarin.FormsWebView una visualizzazione che visualizza il contenuto Web e HTML nell'app. Questo articolo illustra come creare un renderer personalizzato che estende per WebView consentire la chiamata del codice C# da JavaScript.
Ogni Xamarin.Forms visualizzazione ha un renderer a discesa per ogni piattaforma che crea un'istanza di un controllo nativo. WebView Quando un oggetto viene sottoposto a rendering da un'applicazione Xamarin.Forms in iOS, viene creata un'istanza della WkWebViewRenderer classe , che a sua volta crea un'istanza di un controllo nativoWkWebView. Nella piattaforma Android la classe WebViewRenderer crea un'istanza di un controllo WebView nativo. Nella piattaforma UWP (Universal Windows Platform) la classe WebViewRenderer crea un'istanza di un controllo WebView nativo. Per altre informazioni sulle classi di controllo native e del renderer a cui Xamarin.Forms viene eseguito il mapping dei controlli, vedere Classi di base del renderer e controlli nativi.
Il diagramma seguente illustra la relazione tra la classe View e i controlli nativi corrispondenti che la implementano:

Il processo di rendering può essere usato per implementare le personalizzazioni della piattaforma creando un renderer personalizzato per un oggetto WebView in ogni piattaforma. Il processo per eseguire questa operazione è il seguente:
- Creare il controllo personalizzato
HybridWebView. - Utilizzare da
HybridWebViewXamarin.Forms. - Creare il renderer personalizzato per
HybridWebViewin ogni piattaforma.
Ogni elemento verrà ora illustrato a sua volta per implementare un HybridWebView renderer che migliora per Xamarin.FormsWebView consentire la chiamata del codice C# da JavaScript. L'istanza di HybridWebView verrà usata per visualizzare una pagina HTML in cui viene chiesto all'utente di immettere il proprio nome. Quindi, quando l'utente fa clic su un pulsante HTML, una funzione JavaScript richiama un elemento Action di C# che visualizza una finestra popup contenente il nome dell'utente.
Per altre informazioni sul processo per richiamare C# da JavaScript, vedere Richiamare C# da JavaScript. Per altre informazioni sulla pagina HTML, vedere Creare la pagina Web.
Nota
Un WebView oggetto può richiamare una funzione JavaScript da C# e restituire qualsiasi risultato al codice C# chiamante. Per altre informazioni, vedere Richiamo di JavaScript.
Creare HybridWebView
Il HybridWebView controllo personalizzato può essere creato sottoclassando la WebView classe :
public class HybridWebView : WebView
{
Action<string> action;
public static readonly BindableProperty UriProperty = BindableProperty.Create(
propertyName: "Uri",
returnType: typeof(string),
declaringType: typeof(HybridWebView),
defaultValue: default(string));
public string Uri
{
get { return (string)GetValue(UriProperty); }
set { SetValue(UriProperty, value); }
}
public void RegisterAction(Action<string> callback)
{
action = callback;
}
public void Cleanup()
{
action = null;
}
public void InvokeAction(string data)
{
if (action == null || data == null)
{
return;
}
action.Invoke(data);
}
}
Il controllo personalizzato HybridWebView viene creato nel progetto di libreria .NET Standard e definisce l'API seguente per il controllo:
- Una proprietà
Uriche specifica l'indirizzo della pagina Web da caricare. - Un metodo
RegisterActionche registra un elementoActioncon il controllo. L'azione registrata verrà richiamata da JavaScript all'interno del file HTML a cui si fa riferimento attraverso la proprietàUri. - Un metodo
CleanUpche rimuove il riferimento all'elementoActionregistrato. - Un metodo
InvokeActionche richiama l'elementoActionregistrato. Questo metodo verrà chiamato da un renderer personalizzato in ogni progetto di piattaforma.
Usare HybridWebView
Per fare riferimento al controllo personalizzato HybridWebView in XAML nel progetto di libreria .NET Standard, è possibile dichiarare uno spazio dei nomi per il percorso e usare il prefisso dello spazio dei nomi nel controllo personalizzato. Nell'esempio di codice riportato di seguito viene illustrato come il controllo personalizzato HybridWebView può essere usato da una pagina XAML:
<ContentPage ...
xmlns:local="clr-namespace:CustomRenderer;assembly=CustomRenderer"
x:Class="CustomRenderer.HybridWebViewPage"
Padding="0,40,0,0">
<local:HybridWebView x:Name="hybridWebView"
Uri="index.html" />
</ContentPage>
Il prefisso dello spazio dei nomi local può avere qualsiasi nome. I valori clr-namespace e assembly devono tuttavia corrispondere ai dettagli del controllo personalizzato. Dopo aver dichiarato lo spazio dei nomi, il prefisso viene usato per fare riferimento al controllo personalizzato.
Nell'esempio di codice riportato di seguito viene illustrato come il controllo personalizzato HybridWebView può essere usato da una pagina C#:
public HybridWebViewPageCS()
{
var hybridWebView = new HybridWebView
{
Uri = "index.html"
};
// ...
Padding = new Thickness(0, 40, 0, 0);
Content = hybridWebView;
}
L'istanza di HybridWebView verrà usata per visualizzare un controllo Web nativo in ogni piattaforma. La proprietà è Uri impostata su un file HTML archiviato in ogni progetto di piattaforma e che verrà visualizzato dal controllo Web nativo. Il codice HTML sottoposto a rendering chiede all'utente di immettere il proprio nome, con una funzione JavaScript che richiama un elemento Action di C# in risposta al clic su un pulsante HTML.
HybridWebViewPage registra l'azione da richiamare da JavaScript, come illustra l'esempio di codice seguente:
public partial class HybridWebViewPage : ContentPage
{
public HybridWebViewPage()
{
// ...
hybridWebView.RegisterAction(data => DisplayAlert("Alert", "Hello " + data, "OK"));
}
}
Questa azione chiama il metodo DisplayAlert per visualizzare un popup modale che presenta il nome immesso nella pagina HTML visualizzata dall'istanza di HybridWebView.
È ora possibile aggiungere un renderer personalizzato a ogni progetto di applicazione per migliorare i controlli Web della piattaforma consentendo di richiamare il codice C# da JavaScript.
Creare il renderer personalizzato in ogni piattaforma
Il processo di creazione della classe di renderer personalizzato è il seguente:
- Creare una sottoclasse della
WkWebViewRendererclasse in iOS e laWebViewRendererclasse in Android e UWP, che esegue il rendering del controllo personalizzato. - Eseguire l'override del metodo che esegue il
OnElementChangedrendering dellaWebViewlogica e scrivere per personalizzarla. Questo metodo viene chiamato quando viene creato unHybridWebViewoggetto . - Aggiungere un
ExportRendererattributo alla classe o AssemblyInfo.cs del renderer personalizzato per specificare che verrà usato per eseguire il rendering del Xamarin.Forms controllo personalizzato. Questo attributo viene usato per registrare il renderer personalizzato con Xamarin.Forms.
Nota
Per la maggior parte degli Xamarin.Forms elementi, è facoltativo fornire un renderer personalizzato in ogni progetto di piattaforma. Se un renderer personalizzato non è registrato, verrà usato il renderer predefinito per la classe di base del controllo. I renderer personalizzati sono tuttavia necessari in ogni progetto della piattaforma quando si esegue il rendering di un elemento View.
Il diagramma seguente illustra le responsabilità di ogni progetto nell'applicazione di esempio, insieme alle relazioni tra di essi:

Il rendering del HybridWebView controllo personalizzato viene eseguito dalle classi renderer della piattaforma, che derivano dalla WkWebViewRenderer classe in iOS e dalla WebViewRenderer classe in Android e UWP. In questo modo viene eseguito il rendering di ogni HybridWebView controllo personalizzato con controlli Web nativi, come illustrato negli screenshot seguenti:

Le WkWebViewRenderer classi e WebViewRenderer espongono il OnElementChanged metodo , che viene chiamato quando viene creato il controllo personalizzato per eseguire il Xamarin.Forms rendering del controllo Web nativo corrispondente. Questo metodo accetta un VisualElementChangedEventArgs parametro che contiene OldElement le proprietà e NewElement . Queste proprietà rappresentano l'elemento Xamarin.Forms a cui è stato associato il renderer e l'elemento Xamarin.Forms a cui è associato il renderer. Nell'applicazione di esempio la proprietà OldElement sarà null e la proprietà NewElement conterrà un riferimento all'istanza di HybridWebView.
Una versione sottoposta a override del OnElementChanged metodo, in ogni classe renderer della piattaforma, è la posizione in cui eseguire la personalizzazione del controllo Web nativo. È possibile ottenere un riferimento al controllo di cui viene eseguito il Xamarin.Forms rendering tramite la Element proprietà .
Ogni classe renderer personalizzata è decorata con un ExportRenderer attributo che registra il renderer con Xamarin.Forms. L'attributo accetta due parametri, ovvero il nome del tipo del controllo personalizzato di cui viene eseguito il Xamarin.Forms rendering e il nome del tipo del renderer personalizzato. Il prefisso assembly dell'attributo specifica che l'attributo viene applicato all'intero assembly.
Le sezioni seguenti illustrano la struttura della pagina Web caricata da ogni controllo Web nativo, il processo per richiamare C# da JavaScript e l'implementazione di questa funzionalità in ogni classe renderer personalizzata della piattaforma.
Creare la pagina Web
L'esempio di codice seguente illustra la pagina Web che verrà visualizzata dal controllo personalizzato HybridWebView:
<html>
<body>
<script src="http://code.jquery.com/jquery-2.1.4.min.js"></script>
<h1>HybridWebView Test</h1>
<br />
Enter name: <input type="text" id="name">
<br />
<br />
<button type="button" onclick="javascript: invokeCSCode($('#name').val());">Invoke C# Code</button>
<br />
<p id="result">Result:</p>
<script type="text/javascript">function log(str) {
$('#result').text($('#result').text() + " " + str);
}
function invokeCSCode(data) {
try {
log("Sending Data:" + data);
invokeCSharpAction(data);
}
catch (err) {
log(err);
}
}</script>
</body>
</html>
La pagina Web consente all'utente di immettere il proprio nome in un elemento input e indica un elemento button che richiama il codice C# quando viene selezionato. Il processo per eseguire questa operazione è il seguente:
- Quando l'utente fa clic sull'elemento
button, viene chiamata la funzione JavaScriptinvokeCSCode, con il valore dell'elementoinputpassato alla funzione. - La funzione
invokeCSCodechiama la funzionelogper visualizzare i dati inviati all'elementoActiondi C#. Chiama quindi il metodoinvokeCSharpActionper richiamare l'elementoActiondi C#, passando il parametro ricevuto dall'elementoinput.
La funzione JavaScript invokeCSharpAction non è definita nella pagina Web e verrà inserita al suo interno da ogni renderer personalizzato.
In iOS questo file HTML si trova nella cartella del contenuto del progetto della piattaforma, con l'azione di compilazione BundleResource. In Android questo file HTML si trova nella cartella degli asset/del contenuto del progetto della piattaforma, con l'azione di compilazione AndroidAsset.
Richiamare C# da JavaScript
Il processo per richiamare C# da JavaScript è identico in ogni piattaforma:
- Il renderer personalizzato crea un controllo Web nativo e carica il file HTML specificato dalla proprietà
HybridWebView.Uri. - Dopo che la pagina Web è stata caricata, il renderer personalizzato inserisce la funzione JavaScript
invokeCSharpActionnella pagina Web. - Quando l'utente immette il proprio nome e fa clic sull'elemento HTML
button, viene richiamata la funzioneinvokeCSCode, che a sua volta richiama la funzioneinvokeCSharpAction. - La funzione
invokeCSharpActionrichiama un metodo nel renderer personalizzato, che a sua volta richiama il metodoHybridWebView.InvokeAction. - Il metodo
HybridWebView.InvokeActionrichiama l'elementoActionregistrato.
Le sezioni seguenti spiegano come viene implementato questo processo in ogni piattaforma.
Creare il renderer personalizzato in iOS
L'esempio di codice seguente illustra il renderer personalizzato per la piattaforma iOS:
[assembly: ExportRenderer(typeof(HybridWebView), typeof(HybridWebViewRenderer))]
namespace CustomRenderer.iOS
{
public class HybridWebViewRenderer : WkWebViewRenderer, IWKScriptMessageHandler
{
const string JavaScriptFunction = "function invokeCSharpAction(data){window.webkit.messageHandlers.invokeAction.postMessage(data);}";
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);
if (e.OldElement != null)
{
userController.RemoveAllUserScripts();
userController.RemoveScriptMessageHandler("invokeAction");
HybridWebView hybridWebView = e.OldElement as HybridWebView;
hybridWebView.Cleanup();
}
if (e.NewElement != null)
{
string filename = Path.Combine(NSBundle.MainBundle.BundlePath, $"Content/{((HybridWebView)Element).Uri}");
LoadRequest(new NSUrlRequest(new NSUrl(filename, false)));
}
}
public void DidReceiveScriptMessage(WKUserContentController userContentController, WKScriptMessage message)
{
((HybridWebView)Element).InvokeAction(message.Body.ToString());
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
((HybridWebView)Element).Cleanup();
}
base.Dispose(disposing);
}
}
}
La classe HybridWebViewRenderer carica la pagina Web specificata nella proprietà HybridWebView.Uri in un controllo WKWebView nativo e la funzione JavaScript invokeCSharpAction viene inserita nella pagina Web. Dopo che l'utente immette il proprio nome e fa clic sull'elemento HTML button, la funzione JavaScript invokeCSharpAction viene eseguita, con il metodo DidReceiveScriptMessage chiamato dopo che viene ricevuto un messaggio dalla pagina Web. A sua volta, questo metodo richiama il metodo HybridWebView.InvokeAction, che richiama l'azione registrata per visualizzare l'elemento popup.
Questa funzionalità si rende disponibile come indicato di seguito:
- Il costruttore del renderer crea un
WkWebViewConfigurationoggetto e recupera il relativoWKUserContentControlleroggetto. L'oggettoWkUserContentControllerconsente la pubblicazione di messaggi e l'inserimento di script utente in una pagina Web. - Il costruttore renderer crea un
WKUserScriptoggetto che inserisce lainvokeCSharpActionfunzione JavaScript nella pagina Web dopo il caricamento della pagina Web. - Il costruttore renderer chiama il
WKUserContentController.AddUserScriptmetodo per aggiungere l'oggettoWKUserScriptal controller del contenuto. - Il costruttore renderer chiama il
WKUserContentController.AddScriptMessageHandlermetodo per aggiungere un gestore di messaggi di script denominatoinvokeActionall'oggettoWKUserContentController, che causerà la definizione della funzionewindow.webkit.messageHandlers.invokeAction.postMessage(data)JavaScript in tutti i frame in tutte leWebViewistanze che usano l'oggettoWKUserContentController. - A condizione che il renderer personalizzato sia associato a un nuovo Xamarin.Forms elemento:
- Il metodo
WKWebView.LoadRequestcarica il file HTML specificato dalla proprietàHybridWebView.Uri. Il codice specifica che il file è archiviato nella cartellaContentdel progetto. Quando viene visualizzata la pagina Web, la funzione JavaScriptinvokeCSharpActionviene inserita nella pagina Web.
- Il metodo
- Le risorse vengono rilasciate quando l'elemento a cui è associato il renderer.
- L'elemento Xamarin.Forms viene pulito quando il renderer viene eliminato.
Nota
La classe WKWebView è supportata solo in iOS 8 e versioni successive.
È anche necessario aggiornare Info.plist in modo da includere i valori seguenti:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
Creare il renderer personalizzato in Android
L'esempio di codice seguente illustra il renderer personalizzato per la piattaforma Android:
[assembly: ExportRenderer(typeof(HybridWebView), typeof(HybridWebViewRenderer))]
namespace CustomRenderer.Droid
{
public class HybridWebViewRenderer : WebViewRenderer
{
const string JavascriptFunction = "function invokeCSharpAction(data){jsBridge.invokeAction(data);}";
Context _context;
public HybridWebViewRenderer(Context context) : base(context)
{
_context = context;
}
protected override void OnElementChanged(ElementChangedEventArgs<WebView> e)
{
base.OnElementChanged(e);
if (e.OldElement != null)
{
Control.RemoveJavascriptInterface("jsBridge");
((HybridWebView)Element).Cleanup();
}
if (e.NewElement != null)
{
Control.SetWebViewClient(new JavascriptWebViewClient(this, $"javascript: {JavascriptFunction}"));
Control.AddJavascriptInterface(new JSBridge(this), "jsBridge");
Control.LoadUrl($"file:///android_asset/Content/{((HybridWebView)Element).Uri}");
}
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
((HybridWebView)Element).Cleanup();
}
base.Dispose(disposing);
}
}
}
La classe HybridWebViewRenderer carica la pagina Web specificata nella proprietà HybridWebView.Uri in un controllo WebView nativo e la funzione JavaScript invokeCSharpAction viene inserita nella pagina Web, al termine del caricamento della pagina Web, con override di OnPageFinished nella classe JavascriptWebViewClient:
public class JavascriptWebViewClient : FormsWebViewClient
{
string _javascript;
public JavascriptWebViewClient(HybridWebViewRenderer renderer, string javascript) : base(renderer)
{
_javascript = javascript;
}
public override void OnPageFinished(WebView view, string url)
{
base.OnPageFinished(view, url);
view.EvaluateJavascript(_javascript, null);
}
}
Dopo che l'utente immette il proprio nome e fa clic sull'elemento HTML button, viene eseguita la funzione JavaScript invokeCSharpAction. Questa funzionalità si rende disponibile come indicato di seguito:
- A condizione che il renderer personalizzato sia associato a un nuovo Xamarin.Forms elemento:
- Il
SetWebViewClientmetodo imposta un nuovoJavascriptWebViewClientoggetto come implementazione diWebViewClient. - Il metodo
WebView.AddJavascriptInterfaceinserisce una nuova istanza diJSBridgenel frame principale del contesto JavaScript di WebView, denominandolajsBridge. In questo modo è possibile accedere ai metodi presenti nella classeJSBridgeda JavaScript. - Il metodo
WebView.LoadUrlcarica il file HTML specificato dalla proprietàHybridWebView.Uri. Il codice specifica che il file è archiviato nella cartellaContentdel progetto. - Nella classe
JavascriptWebViewClientla funzione JavaScriptinvokeCSharpActionviene inserita nella pagina Web al termine del caricamento della pagina.
- Il
- Le risorse vengono rilasciate quando l'elemento a cui è associato il renderer.
- L'elemento Xamarin.Forms viene pulito quando il renderer viene eliminato.
Quando viene eseguita, la funzione JavaScript invokeCSharpAction a sua volta richiama il metodo JSBridge.InvokeAction, come illustra l'esempio di codice seguente:
public class JSBridge : Java.Lang.Object
{
readonly WeakReference<HybridWebViewRenderer> hybridWebViewRenderer;
public JSBridge(HybridWebViewRenderer hybridRenderer)
{
hybridWebViewRenderer = new WeakReference<HybridWebViewRenderer>(hybridRenderer);
}
[JavascriptInterface]
[Export("invokeAction")]
public void InvokeAction(string data)
{
HybridWebViewRenderer hybridRenderer;
if (hybridWebViewRenderer != null && hybridWebViewRenderer.TryGetTarget(out hybridRenderer))
{
((HybridWebView)hybridRenderer.Element).InvokeAction(data);
}
}
}
La classe deve derivare da Java.Lang.Object e i metodi esposti a JavaScript devono essere decorati con gli attributi [JavascriptInterface] e [Export]. Di conseguenza, quando la funzione JavaScript invokeCSharpAction viene inserita nella pagina Web ed eseguita, chiama il metodo JSBridge.InvokeAction poiché è decorata con gli attributi [JavascriptInterface] e [Export("invokeAction")]. A sua volta, il InvokeAction metodo richiama il HybridWebView.InvokeAction metodo , che richiama l'azione registrata per visualizzare il popup.
Importante
I progetti Android che usano l'attributo [Export] devono includere un riferimento a Mono.Android.Exportoppure verrà generato un errore del compilatore.
Si noti che la classe JSBridge mantiene un elemento WeakReference per la classe HybridWebViewRenderer, per evitare la creazione di un riferimento circolare tra le due classi. Per altre informazioni, vedere Riferimenti deboli.
Creare il renderer personalizzato in UWP
L'esempio di codice seguente illustra il renderer personalizzato per la piattaforma UWP:
[assembly: ExportRenderer(typeof(HybridWebView), typeof(HybridWebViewRenderer))]
namespace CustomRenderer.UWP
{
public class HybridWebViewRenderer : WebViewRenderer
{
const string JavaScriptFunction = "function invokeCSharpAction(data){window.external.notify(data);}";
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.WebView> e)
{
base.OnElementChanged(e);
if (e.OldElement != null)
{
Control.NavigationCompleted -= OnWebViewNavigationCompleted;
Control.ScriptNotify -= OnWebViewScriptNotify;
}
if (e.NewElement != null)
{
Control.NavigationCompleted += OnWebViewNavigationCompleted;
Control.ScriptNotify += OnWebViewScriptNotify;
Control.Source = new Uri($"ms-appx-web:///Content//{((HybridWebView)Element).Uri}");
}
}
async void OnWebViewNavigationCompleted(Windows.UI.Xaml.Controls.WebView sender, WebViewNavigationCompletedEventArgs args)
{
if (args.IsSuccess)
{
// Inject JS script
await Control.InvokeScriptAsync("eval", new[] { JavaScriptFunction });
}
}
void OnWebViewScriptNotify(object sender, NotifyEventArgs e)
{
((HybridWebView)Element).InvokeAction(e.Value);
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
((HybridWebView)Element).Cleanup();
}
base.Dispose(disposing);
}
}
}
La classe HybridWebViewRenderer carica la pagina Web specificata nella proprietà HybridWebView.Uri in un controllo WebView nativo e la funzione JavaScript invokeCSharpAction viene inserita nella pagina Web, al termine del caricamento della pagina, con il metodo WebView.InvokeScriptAsync. Dopo che l'utente immette il proprio nome e fa clic sull'elemento HTML button, la funzione JavaScript invokeCSharpAction viene eseguita, con il metodo OnWebViewScriptNotify chiamato dopo che viene ricevuta una notifica dalla pagina Web. A sua volta, questo metodo richiama il metodo HybridWebView.InvokeAction, che richiama l'azione registrata per visualizzare l'elemento popup.
Questa funzionalità si rende disponibile come indicato di seguito:
- A condizione che il renderer personalizzato sia associato a un nuovo Xamarin.Forms elemento:
- I gestori eventi per gli eventi
NavigationCompletedeScriptNotifysono registrati. L'eventoNavigationCompletedviene attivato quando il controllo nativoWebViewha completato il caricamento del contenuto corrente o se la navigazione ha avuto esito negativo. L'eventoScriptNotifyviene attivato quando il contenuto nel controllo nativoWebViewusa JavaScript per passare una stringa all'applicazione. La pagina Web genera l'eventoScriptNotifychiamandowindow.external.notifymentre passa un parametrostring. - La proprietà
WebView.Sourceviene impostata sull'URI del file HTML specificato dalla proprietàHybridWebView.Uri. Il codice presuppone che il file sia archiviato nella cartellaContentdel progetto. Dopo che è stata visualizzata la pagina Web, viene attivato l'eventoNavigationCompletede viene richiamato il metodoOnWebViewNavigationCompleted. La funzione JavaScriptinvokeCSharpActionviene quindi inserita nella pagina Web con il metodoWebView.InvokeScriptAsync, a condizione che la navigazione sia stata completata correttamente.
- I gestori eventi per gli eventi
- L'evento viene annullato quando l'elemento a cui è associato il renderer.
- L'elemento Xamarin.Forms viene pulito quando il renderer viene eliminato.