Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
A Xamarin.FormsWebView é uma exibição que exibe conteúdo da Web e HTML em seu aplicativo. Este artigo explica como criar um renderizador personalizado que estende o WebView para permitir que o código C# seja invocado do JavaScript.
Cada Xamarin.Forms exibição tem um renderizador de acompanhamento para cada plataforma que cria uma instância de um controle nativo. Quando a WebView é renderizado por um Xamarin.Forms aplicativo no iOS, a classe é instanciada, o WkWebViewRenderer que, por sua vez, instancia um controle nativo WkWebView . Na plataforma Android, a classe WebViewRenderer cria uma instância de um controle WebView nativo. Na UWP (Plataforma Universal do Windows), a classe WebViewRenderer cria uma instância de um controle WebView nativo. Para obter mais informações sobre o renderizador e as classes de controle nativas para as quais Xamarin.Forms os controles são mapeados, consulte Classes base do renderizador e controles nativos.
O seguinte diagrama ilustra a relação entre o View e os controles nativos correspondentes que o implementam:

O processo de renderização pode ser usado para implementar personalizações de plataforma criando um renderizador personalizado para um WebView em cada plataforma. O processo para fazer isso é o seguinte:
- Criar o controle personalizado
HybridWebView. - Consuma o
HybridWebViewde Xamarin.Forms. - Criar o renderizador personalizado para a página
HybridWebViewem cada plataforma.
Cada item agora será discutido para implementar um HybridWebView renderizador que aprimora o para permitir que o Xamarin.FormsWebView código C# seja invocado do JavaScript. A instância de HybridWebView será usada para exibir uma página HTML que pede ao usuário para digitar seu nome. Em seguida, quando o usuário clicar em um botão HTML, uma função de JavaScript invocará um Action em C# que exibe um pop-up que contém o nome do usuário.
Para obter mais informações sobre o processo de invocação de C# do JavaScript, consulte Invocar C# do JavaScript. Para obter mais informações sobre a página HTML, consulte Criar a página da Web.
Observação
A WebView pode invocar uma função JavaScript do C# e retornar qualquer resultado para o código C# de chamada. Para obter mais informações, consulte Invocando JavaScript.
Criar o HybridWebView
O HybridWebView controle personalizado pode ser criado subclassificando a 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);
}
}
O controle personalizado HybridWebView é criado no projeto da biblioteca do .NET Standard e define a seguinte API para o controle:
- Uma propriedade
Urique especifica o endereço da página da Web a ser carregada. - Um método
RegisterActionque registra umActioncom o controle. A ação registrada será invocada do JavaScript contido no arquivo HTML referenciado por meio da propriedadeUri. - Um método
CleanUpque remove a referência aoActionregistrado. - Um método
InvokeActionque invoca oActionregistrado. Esse método será chamado de um renderizador personalizado em cada projeto de plataforma.
Consumir o HybridWebView
O controle personalizado HybridWebView pode ser referenciado em XAML no projeto da biblioteca .NET Standard declarando um namespace para sua localização e usando o prefixo do namespace no controle personalizado. O exemplo de código a seguir mostra como o controle personalizado HybridWebView pode ser consumido por uma página 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>
O prefixo do namespace local pode ser qualquer nome. No entanto, os valores de clr-namespace e assembly devem corresponder aos detalhes do controle personalizado. Quando o namespace é declarado, o prefixo é usado para referenciar o controle personalizado.
O seguinte exemplo de código mostra como o controle personalizado HybridWebView pode ser consumido por um página em C#:
public HybridWebViewPageCS()
{
var hybridWebView = new HybridWebView
{
Uri = "index.html"
};
// ...
Padding = new Thickness(0, 40, 0, 0);
Content = hybridWebView;
}
A instância HybridWebView será usada para exibir um controle da Web nativo em cada plataforma. Uri Sua propriedade é definida como um arquivo HTML armazenado em cada projeto de plataforma e que será exibido pelo controle Web nativo. O HTML renderizado solicita que o usuário insira seu nome, com uma função de JavaScript invocando um Action C# em resposta a um clique no botão HTML.
O HybridWebViewPage registra a ação a ser invocada do JavaScript, conforme mostrado no exemplo de código a seguir:
public partial class HybridWebViewPage : ContentPage
{
public HybridWebViewPage()
{
// ...
hybridWebView.RegisterAction(data => DisplayAlert("Alert", "Hello " + data, "OK"));
}
}
Essa ação chama o método DisplayAlert para exibir um pop-up modal que apresenta o nome inserido na página HTML exibida pela instância de HybridWebView.
Um renderizador personalizado agora pode ser adicionado a cada projeto de aplicativo para aprimorar os controles Web da plataforma, permitindo que o código C# seja invocado do JavaScript.
Criar o renderizador personalizado em cada plataforma
O processo para criar a classe do renderizador personalizado é a seguinte:
- Crie uma subclasse da
WkWebViewRendererclasse no iOS e aWebViewRendererclasse no Android e na UWP, que renderiza o controle personalizado. - Substitua o
OnElementChangedmétodo que renderiza aWebViewlógica de gravação e para personalizá-la. Esse método é chamado quando umHybridWebViewobjeto é criado. - Adicione um
ExportRendereratributo à classe ou AssemblyInfo.cs do renderizador personalizado para especificar que ele será usado para renderizar o Xamarin.Forms controle personalizado. Esse atributo é usado para registrar o renderizador personalizado com Xamarin.Forms.
Observação
Para a maioria dos Xamarin.Forms elementos, é opcional fornecer um renderizador personalizado em cada projeto de plataforma. Se um renderizador personalizado não estiver registrado, será usado o renderizador padrão da classe base do controle. No entanto, são necessários renderizadores personalizados em cada projeto da plataforma durante a renderização de um elemento View.
O seguinte diagrama ilustra as responsabilidades de cada projeto no aplicativo de exemplo, bem como as relações entre elas:

O HybridWebView controle personalizado é renderizado por classes de renderizador de plataforma, que derivam da WkWebViewRenderer classe no iOS e da classe no Android e na WebViewRenderer UWP. Isso faz com que cada HybridWebView controle personalizado seja renderizado com controles Web nativos, conforme mostrado nas seguintes capturas de tela:

As WkWebViewRenderer classes and WebViewRenderer expõem o OnElementChanged método, que é chamado quando o Xamarin.Forms controle personalizado é criado para renderizar o controle da Web nativo correspondente. Esse método usa um VisualElementChangedEventArgs parâmetro que contém OldElement e NewElement propriedades. Essas propriedades representam o Xamarin.Forms elemento ao qual o renderizador foi anexado e o Xamarin.Forms elemento ao qual o renderizador está anexado, respectivamente. No aplicativo de exemplo, a propriedade OldElement será null e a propriedade NewElement conterá uma referência à instância de HybridWebView.
Uma versão substituída do OnElementChanged método, em cada classe de renderizador de plataforma, é o local para executar a personalização do controle da Web nativo. Uma referência ao Xamarin.Forms controle que está sendo renderizado pode ser obtida por meio da Element propriedade.
Cada classe de renderizador personalizado é decorada com um ExportRenderer atributo que registra o renderizador com Xamarin.Forms. O atributo usa dois parâmetros: o nome do tipo do Xamarin.Forms controle personalizado que está sendo renderizado e o nome do tipo do renderizador personalizado. O prefixo assembly do atributo especifica que o atributo se aplica a todo o assembly.
As seções a seguir discutem a estrutura da página da Web carregada por cada controle da Web nativo, o processo para invocar C# do JavaScript e a implementação disso em cada classe de renderizador personalizado da plataforma.
Criar a página da Web
O exemplo de código a seguir mostra a página da Web que será exibida pelo controle personalizado 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>
A página da Web permite que um usuário insira seu nome em um elemento input e fornece um elemento button que invocará o código C# quando clicado. O processo para fazer isso é o seguinte:
- Quando o usuário clica na elemento
button, a funçãoinvokeCSCodede JavaScript é chamada, com o valor do elementoinputsendo passado para a função. - A função
invokeCSCodechama a funçãologpara exibir os dados que está enviando para oActionC#. Em seguida, ela chama o métodoinvokeCSharpActionpara invocar oActionC#, passando o parâmetro recebido do elementoinput.
A função JavaScript invokeCSharpAction não está definida na página da Web e será injetada nela por cada renderizador personalizado.
No iOS, esse arquivo HTML reside na pasta de conteúdo do projeto de plataforma, com uma ação de build BundleResource. No Android, esse arquivo HTML reside na pasta de Ativos/Conteúdo do projeto de plataforma, com uma ação de build AndroidAsset.
Invocar C# do JavaScript
O processo para invocar C# do JavaScript é idêntico em todas as plataformas:
- O renderizador personalizado cria um controle da Web nativo e carrega o arquivo HTML especificado pela propriedade
HybridWebView.Uri. - Quando a página da Web é carregada, o renderizador personalizado injeta a função de JavaScript
invokeCSharpActionna página da Web. - Quando o usuário insere seu nome e clica no elemento
buttonHTML, a funçãoinvokeCSCodeé invocada, que, por sua vez, invoca a funçãoinvokeCSharpAction. - A função
invokeCSharpActioninvoca um método no renderizador personalizado, que por sua vez invoca o métodoHybridWebView.InvokeAction. - O método
HybridWebView.InvokeActioninvoca oActionregistrado.
As seções a seguir abordam como esse processo é implementado em cada plataforma.
Criar o renderizador personalizado no iOS
O exemplo de código a seguir mostra o renderizador personalizado para a plataforma 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);
}
}
}
A classe HybridWebViewRenderer carrega a página da Web especificada na propriedade HybridWebView.Uri em um controle WKWebView nativo e a função de JavaScript invokeCSharpAction é injetada na página da Web. Quando o usuário insere seu nome e clica no elemento HTML button, a função de JavaScript invokeCSharpAction é executada, com o método DidReceiveScriptMessage sendo chamado depois que uma mensagem é recebida da página da Web. Por sua vez, esse método invoca o método HybridWebView.InvokeAction, que invoca a ação registrada para exibir o pop-up.
Essa funcionalidade é obtida da seguinte maneira:
- O construtor do renderizador cria um
WkWebViewConfigurationobjeto e recupera seuWKUserContentControllerobjeto. OWkUserContentControllerobjeto permite postar mensagens e injetar scripts de usuário em uma página da web. - O construtor do renderizador cria um
WKUserScriptobjeto, que injeta ainvokeCSharpActionfunção JavaScript na página da Web depois que a página da Web é carregada. - O construtor do renderizador chama o
WKUserContentController.AddUserScriptmétodo para adicionar oWKUserScriptobjeto ao controlador de conteúdo. - O construtor do renderizador chama o
WKUserContentController.AddScriptMessageHandlermétodo para adicionar um manipulador de mensagens de script nomeadoinvokeActionao objeto, oWKUserContentControllerque fará com que a funçãowindow.webkit.messageHandlers.invokeAction.postMessage(data)JavaScript seja definida em todos os quadros em todas asWebViewinstâncias que usam oWKUserContentControllerobjeto. - Desde que o renderizador personalizado esteja anexado a um novo Xamarin.Forms elemento:
- O método
WKWebView.LoadRequestcarrega o arquivo HTML que é especificado pela propriedadeHybridWebView.Uri. O código especifica que o arquivo seja armazenado na pastaContentdo projeto. Após a página da Web ser exibida, a função de JavaScriptinvokeCSharpActionserá injetada na página da Web.
- O método
- Os recursos são liberados quando o elemento ao qual o renderizador está anexado é alterado.
- O Xamarin.Forms elemento é limpo quando o renderizador é descartado.
Observação
A classe WKWebView tem suporte apenas no iOS 8 e posteriores.
Além disso, Info.plist deve ser atualizado para incluir os seguintes valores:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
Criar o renderizador personalizado no Android
O exemplo de código a seguir mostra o renderizador personalizado para a plataforma 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);
}
}
}
A classe HybridWebViewRenderer carrega a página da Web especificada na propriedade HybridWebView.Uri em um controle WebView nativo e a função de JavaScript invokeCSharpAction é injetada na página da Web, após a página da Web terminar de ser carregada, com a substituição OnPageFinished na 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);
}
}
Quando o usuário insere seu nome e clica no elemento HTML button, a função de JavaScript invokeCSharpAction é executada. Essa funcionalidade é obtida da seguinte maneira:
- Desde que o renderizador personalizado esteja anexado a um novo Xamarin.Forms elemento:
- O
SetWebViewClientmétodo define um novoJavascriptWebViewClientobjeto como a implementação doWebViewClient. - O método
WebView.AddJavascriptInterfaceinjeta uma nova instância deJSBridgeno quadro principal do contexto do JavaScript do WebView, denominando-ajsBridge. Isso permite que métodos na classeJSBridgesejam acessados do JavaScript. - O método
WebView.LoadUrlcarrega o arquivo HTML que é especificado pela propriedadeHybridWebView.Uri. O código especifica que o arquivo seja armazenado na pastaContentdo projeto. - Na classe
JavascriptWebViewClient, a função de JavaScriptinvokeCSharpActioné injetada na página da Web depois que a página termina de ser carregada.
- O
- Os recursos são liberados quando o elemento ao qual o renderizador está anexado é alterado.
- O Xamarin.Forms elemento é limpo quando o renderizador é descartado.
Quando a função de JavaScript invokeCSharpAction é executada, por sua vez, ela invoca o método JSBridge.InvokeAction, que é mostrado no exemplo de código a seguir:
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);
}
}
}
A classe deve derivar de Java.Lang.Object, e os métodos que são expostos para o JavaScript devem ser decorados com os atributos [JavascriptInterface] e [Export]. Portanto, quando a função de JavaScript invokeCSharpAction é injetada na página da Web e é executada, ela chama o método JSBridge.InvokeAction por ter sido decorada com os atributos [JavascriptInterface] e [Export("invokeAction")]. Por sua vez, o InvokeAction método invoca o HybridWebView.InvokeAction método, que invocará a ação registrada para exibir o pop-up.
Importante
Os projetos Android que usam o [Export] atributo devem incluir uma referência a Mono.Android.Export, ou resultará em um erro do compilador.
Observe que a classe JSBridge mantém um WeakReference para a classe HybridWebViewRenderer. A finalidade é evitar a criação de uma referência circular entre as duas classes. Para obter mais informações, consulte Referências fracas.
Criar o renderizador personalizado na UWP
O exemplo de código a seguir mostra o renderizador personalizado para a 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);
}
}
}
A classe HybridWebViewRenderer carrega a página da Web especificada na propriedade HybridWebView.Uri em um controle WebView nativo e a função de JavaScript invokeCSharpAction é injetada na página da Web, após a página da Web ser carregada, com o método WebView.InvokeScriptAsync. Quando o usuário insere seu nome e clica no elemento HTML button, a função de JavaScript invokeCSharpAction é executada, com o método OnWebViewScriptNotify sendo chamado depois que uma notificação é recebida da página da Web. Por sua vez, esse método invoca o método HybridWebView.InvokeAction, que invoca a ação registrada para exibir o pop-up.
Essa funcionalidade é obtida da seguinte maneira:
- Desde que o renderizador personalizado esteja anexado a um novo Xamarin.Forms elemento:
- Manipuladores de eventos para os eventos
NavigationCompletedeScriptNotifysão registrados. O eventoNavigationCompletedé acionado quando o controle nativoWebViewtermina de carregar o conteúdo atual ou quando a navegação falha. O eventoScriptNotifyé acionado quando o conteúdo no controleWebViewnativo usa JavaScript para passar uma cadeia de caracteres para o aplicativo. A página da Web aciona o eventoScriptNotifychamandowindow.external.notifyao passar um parâmetrostring. - A propriedade
WebView.Sourceé definida como o URI do arquivo HTML que é especificado pela propriedadeHybridWebView.Uri. O código presume que o arquivo seja armazenado na pastaContentdo projeto. Depois que a página da Web é exibida, o eventoNavigationCompletedé acionado e o métodoOnWebViewNavigationCompletedé invocado. A função de JavaScriptinvokeCSharpAction, em seguida, será injetada na página da Web com o métodoWebView.InvokeScriptAsync, desde que a navegação tenha sido concluída com êxito.
- Manipuladores de eventos para os eventos
- A assinatura do evento é cancelada a partir do momento em que o elemento ao qual o renderizador é anexado é alterado.
- O Xamarin.Forms elemento é limpo quando o renderizador é descartado.