Remarque
L’accès à cette page requiert une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page requiert une autorisation. Vous pouvez essayer de modifier des répertoires.
Il Xamarin.FormsWebView s’agit d’une vue qui affiche du contenu web et HTML dans votre application. Cet article explique comment créer un renderer personnalisé qui étend le WebView code C# à appeler à partir de JavaScript.
Chaque Xamarin.Forms vue a un renderer associé pour chaque plateforme qui crée une instance d’un contrôle natif. Lorsqu’une WebView Xamarin.Forms application est rendue sur iOS, la WkWebViewRenderer classe est instanciée, qui instancie à son tour un contrôle natif WkWebView . Sur la plateforme Android, la classe WebViewRenderer instancie un contrôle WebView natif. Sur la plateforme Windows universelle (UWP), la classe WebViewRenderer instancie un contrôle WebView natif. Pour plus d’informations sur les classes de renderer et de contrôle natives qui contrôlent Xamarin.Forms la correspondance, consultez Les classes de base du renderer et les contrôles natifs.
Le diagramme suivant illustre la relation entre View et les contrôles natifs correspondants qui l’implémentent :

Le processus de rendu peut être utilisé pour implémenter des personnalisations de plateforme en créant un renderer personnalisé pour une WebView plateforme sur chaque plateforme. Le processus pour y parvenir est le suivant :
- Créez le contrôle personnalisé
HybridWebView. - Consommer à partir de
HybridWebViewXamarin.Forms. - Créez le renderer personnalisé pour le
HybridWebViewsur chaque plateforme.
Chaque élément sera maintenant abordé à son tour pour implémenter un HybridWebView renderer qui améliore la possibilité d’appeler du Xamarin.FormsWebView code C# à partir de JavaScript. L’instance HybridWebView est utilisée pour afficher une page HTML qui invite l’utilisateur à entrer son nom. Ensuite, quand l’utilisateur clique sur un bouton HTML, une fonction JavaScript appelle une Action C# qui affiche une fenêtre contextuelle contenant le nom de l’utilisateur.
Pour plus d’informations sur le processus d’appel de C# à partir de JavaScript, consultez Appeler C# à partir de JavaScript. Pour plus d’informations sur la page HTML, consultez Créer la page web.
Remarque
Un WebView peut appeler une fonction JavaScript à partir de C# et retourner tout résultat au code C# appelant. Pour plus d’informations, consultez Appel de JavaScript.
Créer hybridWebView
Le HybridWebView contrôle personnalisé peut être créé en sous-classe de 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);
}
}
Le contrôle personnalisé HybridWebView est créé dans le projet de bibliothèque .NET Standard et définit l’API suivante :
- Une propriété
Uriqui spécifie l’adresse de la page web à charger. - Une méthode
RegisterActionqui inscrit uneActionauprès du contrôle. L’action inscrite est appelée à partir d’un code JavaScript contenu dans le fichier HTML référencé par le biais de la propriétéUri. - Une méthode
CleanUpqui supprime la référence à l’Actioninscrite. - Une méthode
InvokeActionqui appelle l’Actioninscrite. Cette méthode est appelée à partir d’un renderer personnalisé dans chaque projet de plateforme.
Utiliser HybridWebView
Vous pouvez référencer le contrôle personnalisé HybridWebView en XAML dans le projet de bibliothèque .NET Standard en déclarant un espace de noms pour son emplacement et en utilisant le préfixe d’espace de noms sur le contrôle personnalisé. L’exemple de code suivant montre comment le contrôle personnalisé HybridWebView peut être consommé par une page 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>
Le préfixe d’espace de noms local peut porter n’importe quel nom. Toutefois, les valeurs clr-namespace et assembly doivent correspondre aux détails du contrôle personnalisé. Une fois l’espace de noms déclaré, le préfixe est utilisé pour référencer le contrôle personnalisé.
L’exemple de code suivant montre comment le contrôle personnalisé HybridWebView peut être consommé par une page C# :
public HybridWebViewPageCS()
{
var hybridWebView = new HybridWebView
{
Uri = "index.html"
};
// ...
Padding = new Thickness(0, 40, 0, 0);
Content = hybridWebView;
}
L’instance HybridWebView est utilisée pour afficher un contrôle web natif sur chaque plateforme. Uri Sa propriété est définie sur un fichier HTML stocké dans chaque projet de plateforme et qui sera affiché par le contrôle web natif. Le code HTML restitué invite l’utilisateur à entrer son nom, une fonction JavaScript appelant une Action C# en réponse à un clic de bouton HTML.
La HybridWebViewPage enregistre l’action à appeler à partir de JavaScript, comme illustré dans l’exemple de code suivant :
public partial class HybridWebViewPage : ContentPage
{
public HybridWebViewPage()
{
// ...
hybridWebView.RegisterAction(data => DisplayAlert("Alert", "Hello " + data, "OK"));
}
}
Cette action appelle la méthode DisplayAlertpour afficher une fenêtre contextuelle modale qui présente le nom entré dans la page HTML affichée par l’instance HybridWebView.
Un renderer personnalisé peut désormais être ajouté à chaque projet d’application pour améliorer les contrôles web de plateforme en autorisant l’appel du code C# à partir de JavaScript.
Créer le renderer personnalisé sur chaque plateforme
Le processus de création de la classe de renderer personnalisé est le suivant :
- Créez une sous-classe de la
WkWebViewRendererclasse sur iOS et laWebViewRendererclasse sur Android et UWP, qui restitue le contrôle personnalisé. - Remplacez la
OnElementChangedméthode qui restitue et écrit la logique pour laWebViewpersonnaliser. Cette méthode est appelée lorsqu’unHybridWebViewobjet est créé. - Ajoutez un
ExportRendererattribut à la classe de renderer personnalisé ou AssemblyInfo.cs, pour spécifier qu’il sera utilisé pour afficher le Xamarin.Forms contrôle personnalisé. Cet attribut est utilisé pour inscrire le renderer personnalisé avec Xamarin.Forms.
Remarque
Pour la plupart des Xamarin.Forms éléments, il est facultatif de fournir un renderer personnalisé dans chaque projet de plateforme. Si un renderer personnalisé n’est pas inscrit, le renderer par défaut de la classe de base du contrôle est utilisé. Toutefois, les renderers personnalisés sont nécessaires dans chaque projet de plateforme lors du rendu d’un élément View.
Le diagramme suivant illustre les responsabilités de chaque projet dans l’exemple d’application ainsi que les relations qu’ils entretiennent les uns avec les autres :

Le HybridWebView contrôle personnalisé est rendu par les classes de renderer de plateforme, qui dérivent de la WkWebViewRenderer classe sur iOS et de la WebViewRenderer classe sur Android et UWP. Cela entraîne le rendu de chaque HybridWebView contrôle personnalisé avec des contrôles web natifs, comme illustré dans les captures d’écran suivantes :

Les WkWebViewRenderer classes exposent WebViewRenderer la OnElementChanged méthode, appelée lorsque le Xamarin.Forms contrôle personnalisé est créé pour afficher le contrôle web natif correspondant. Cette méthode prend un VisualElementChangedEventArgs paramètre qui contient et NewElement des OldElement propriétés. Ces propriétés représentent l’élément Xamarin.Forms auquel le renderer a été attaché, et l’élément Xamarin.Forms auquel le renderer est attaché, respectivement. Dans l’exemple d’application, la propriété OldElement est null et la propriété NewElement contient une référence à l’instance HybridWebView.
Une version substituée de la OnElementChanged méthode, dans chaque classe de renderer de plateforme, est l’endroit où effectuer la personnalisation du contrôle web natif. Une référence au Xamarin.Forms contrôle en cours de rendu peut être obtenue via la Element propriété.
Chaque classe de renderer personnalisée est décorée avec un ExportRenderer attribut qui inscrit le renderer avec Xamarin.Forms. L’attribut prend deux paramètres : le nom de type du Xamarin.Forms contrôle personnalisé en cours de rendu et le nom de type du renderer personnalisé. Le préfixe assembly de l’attribut spécifie que l’attribut s’applique à la totalité de l’assembly.
Les sections suivantes décrivent la structure de la page web chargée par chaque contrôle web natif, le processus d’appel C# à partir de JavaScript et l’implémentation de celle-ci dans chaque classe de renderer personnalisée de plateforme.
Créez la page web.
L’exemple de code suivant montre la page web affichée par le contrôle personnalisé 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 page web permet à un utilisateur d’entrer son nom dans un élément input et fournit un élément button qui appelle du code C# quand l’utilisateur clique cet élément. Le processus pour y parvenir est le suivant :
- Quand l’utilisateur clique sur l’élément
button, la fonction JavaScriptinvokeCSCodeest appelée et reçoit la valeur de l’élémentinput. - La fonction
invokeCSCodeappelle la fonctionlogpour afficher les données qu’elle envoie à l’ActionC#. Elle appelle ensuite la méthodeinvokeCSharpActionpour appeler l’ActionC#, en transmettant le paramètre reçu de l’élémentinput.
La fonction JavaScript invokeCSharpActionn’est pas définie dans la page web ; elle y est injectée par chaque renderer personnalisé.
Sur iOS, ce fichier HTML réside dans le dossier Contenu du projet de plateforme, avec une action de build de BundleResource. Sur Android, ce fichier HTML réside dans le dossier Ressources/Contenu du projet de plateforme, avec une action de build de AndroidAsset.
Appeler C# à partir de JavaScript
Le processus permettant d’appeler C# à partir de JavaScript est identique sur chaque plateforme :
- Le renderer personnalisé crée un contrôle web natif et charge le fichier HTML spécifié par la propriété
HybridWebView.Uri. - Une fois la page web chargée, le renderer personnalisé injecte la fonction JavaScript
invokeCSharpActiondans la page web. - Quand l’utilisateur entre son nom et clique sur l’élément
buttonHTML, la fonctioninvokeCSCodeest appelée, qui appelle à son tour la fonctioninvokeCSharpAction. - La fonction
invokeCSharpActionappelle une méthode dans le renderer personnalisé, qui à son tour appelle la méthodeHybridWebView.InvokeAction. - La méthode
HybridWebView.InvokeActionappelle l’Actioninscrite.
Les sections suivantes expliquent comment ce processus est implémenté sur chaque plateforme.
Créer le renderer personnalisé sur iOS
L’exemple de code suivant illustre le renderer personnalisé pour la plateforme 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 charge la page web spécifiée dans la propriété HybridWebView.Uri dans un contrôle WKWebView natif, puis la fonction JavaScript invokeCSharpAction est injectée dans la page web. Une fois que l’utilisateur entre son nom et clique sur l’élément button HTML, la fonction JavaScript invokeCSharpAction est exécutée, puis la méthode DidReceiveScriptMessage est appelée après la réception d’un message de la page web. À son tour, cette méthode appelle la méthode HybridWebView.InvokeAction, qui appelle l’action inscrite pour afficher la fenêtre contextuelle.
Cette fonctionnalité est obtenue comme suit :
- Le constructeur du convertisseur crée un
WkWebViewConfigurationobjet et récupère sonWKUserContentControllerobjet. L’objetWkUserContentControllerpermet de publier des messages et d’injecter des scripts utilisateur dans une page web. - Le constructeur du convertisseur crée un
WKUserScriptobjet, qui injecte lainvokeCSharpActionfonction JavaScript dans la page web une fois la page web chargée. - Le constructeur du convertisseur appelle la
WKUserContentController.AddUserScriptméthode pour ajouter l’objetWKUserScriptau contrôleur de contenu. - Le constructeur du convertisseur appelle la
WKUserContentController.AddScriptMessageHandlerméthode pour ajouter un gestionnaire de messages de script nomméinvokeActionà l’objet, ce qui entraîne la définition de laWKUserContentControllerfonctionwindow.webkit.messageHandlers.invokeAction.postMessage(data)JavaScript dans toutes les images de toutes lesWebViewinstances qui utilisent l’objetWKUserContentController. - À condition que le renderer personnalisé soit attaché à un nouvel Xamarin.Forms élément :
- La méthode
WKWebView.LoadRequestcharge le fichier HTML qui est spécifié par la propriétéHybridWebView.Uri. Le code spécifie que le fichier est stocké dans le dossierContentdu projet. Une fois la page web affichée, la fonction JavaScriptinvokeCSharpActiony est injectée.
- La méthode
- Les ressources sont libérées lorsque l’élément du renderer est attaché aux modifications.
- L’élément Xamarin.Forms est nettoyé lorsque le renderer est supprimé.
Remarque
La classe WKWebView est uniquement prise en charge dans iOS versions 8 et ultérieures.
De plus, Info.plist doit être mis à jour pour inclure les valeurs suivantes :
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
Créer le renderer personnalisé sur Android
L’exemple de code suivant illustre le renderer personnalisé pour la plateforme 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 charge la page web spécifiée dans la propriété HybridWebView.Uri dans un contrôle WebView natif, puis la fonction JavaScript invokeCSharpAction est injectée dans la page web, avec la substitution de OnPageFinished dans la 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);
}
}
Une fois que l’utilisateur entre son nom et clique sur l’élément button HTML, la fonction JavaScript invokeCSharpAction est exécutée. Cette fonctionnalité est obtenue comme suit :
- À condition que le renderer personnalisé soit attaché à un nouvel Xamarin.Forms élément :
- La
SetWebViewClientméthode définit un nouvelJavascriptWebViewClientobjet comme implémentation deWebViewClient. - La méthode
WebView.AddJavascriptInterfaceinjecte une nouvelle instanceJSBridge, qu’elle nommejsBridge, dans le cadre principal du contexte JavaScript de l’affichage web. Ainsi, les méthodes dans la classeJSBridgesont accessibles à partir de JavaScript. - La méthode
WebView.LoadUrlcharge le fichier HTML qui est spécifié par la propriétéHybridWebView.Uri. Le code spécifie que le fichier est stocké dans le dossierContentdu projet. - Dans la classe
JavascriptWebViewClient, la fonction JavaScriptinvokeCSharpActionest injectée dans la page web une fois celle-ci chargée.
- La
- Les ressources sont libérées lorsque l’élément du renderer est attaché aux modifications.
- L’élément Xamarin.Forms est nettoyé lorsque le renderer est supprimé.
Quand la fonction JavaScript invokeCSharpAction est exécutée, elle appelle à son tour la méthode JSBridge.InvokeAction, comme l’illustre l’exemple de code suivant :
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 doit dériver de Java.Lang.Object, tandis que les méthodes qui sont exposées à JavaScript doivent être décorées avec les attributs [JavascriptInterface] et [Export]. Ainsi, quand la fonction JavaScript invokeCSharpAction est injectée dans la page web et est exécutée, elle appelle la méthode JSBridge.InvokeAction, car celle-ci est décorée avec les attributs [JavascriptInterface] et [Export("invokeAction")]. À son tour, la InvokeAction méthode appelle la HybridWebView.InvokeAction méthode, qui appelle l’action inscrite pour afficher la fenêtre contextuelle.
Important
Les projets Android qui utilisent l’attribut [Export] doivent inclure une référence à Mono.Android.Export, ou une erreur du compilateur se produit.
Notez que la classe JSBridge conserve une WeakReference à la classe HybridWebViewRenderer, afin d’éviter la création d’une référence circulaire entre les deux classes. Pour plus d’informations, consultez Références faibles.
Créer le renderer personnalisé sur UWP
L’exemple de code suivant illustre le renderer personnalisé pour 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 charge la page web spécifiée dans la propriété HybridWebView.Uri dans un contrôle WebView natif, puis la fonction JavaScript invokeCSharpAction est injectée dans la page web, avec la méthode WebView.InvokeScriptAsync. Une fois que l’utilisateur entre son nom et clique sur l’élément button HTML, la fonction JavaScript invokeCSharpAction est exécutée, puis la méthode OnWebViewScriptNotify est appelée après la réception d’une notification de la page web. À son tour, cette méthode appelle la méthode HybridWebView.InvokeAction, qui appelle l’action inscrite pour afficher la fenêtre contextuelle.
Cette fonctionnalité est obtenue comme suit :
- À condition que le renderer personnalisé soit attaché à un nouvel Xamarin.Forms élément :
- Des gestionnaires d’événements pour les événements
NavigationCompletedetScriptNotifysont inscrits. L’événementNavigationCompletedest déclenché quand le contrôleWebViewnatif a terminé de charger le contenu actuel ou si la navigation a échoué. L’événementScriptNotifyest déclenché quand le contenu du contrôleWebViewnatif utilise JavaScript pour passer une chaîne à l’application. La page web déclenche l’événementScriptNotifyen appelantwindow.external.notifytout en passant un paramètrestring. - La propriété
WebView.Sourceest définie sur l’URI du fichier HTML qui est spécifié par la propriétéHybridWebView.Uri. Le code suppose que le fichier est stocké dans le dossierContentdu projet. Une fois la page web affichée, l’événementNavigationCompletedest déclenché et la méthodeOnWebViewNavigationCompletedest appelée. La fonction JavaScriptinvokeCSharpActionest ensuite injectée dans la page web avec la méthodeWebView.InvokeScriptAsync, à condition que la navigation se soit déroulée correctement.
- Des gestionnaires d’événements pour les événements
- L’événement est annulé lorsque l’élément auquel le renderer est attaché aux modifications.
- L’élément Xamarin.Forms est nettoyé lorsque le renderer est supprimé.