Menyesuaikan WebView
Xamarin.FormsWebView
adalah tampilan yang menampilkan konten web dan HTML di aplikasi Anda. Artikel ini menjelaskan cara membuat perender kustom yang memperluas WebView
untuk memungkinkan kode C# dipanggil dari JavaScript.
Setiap Xamarin.Forms tampilan memiliki perender yang menyertainya untuk setiap platform yang membuat instans kontrol asli. WebView
Ketika dirender oleh Xamarin.Forms aplikasi di iOS, WkWebViewRenderer
kelas dibuat, yang pada gilirannya membuat instans kontrol asliWkWebView
. Pada platform Android, WebViewRenderer
kelas membuat instans kontrol asli WebView
. Pada Platform Windows Universal (UWP), WebViewRenderer
kelas membuat instans kontrol asliWebView
. Untuk informasi selengkapnya tentang kelas perender dan kontrol asli yang Xamarin.Forms mengontrol peta ke, lihat Kelas Dasar Perender dan Kontrol Asli.
Diagram berikut mengilustrasikan hubungan antara View
kontrol asli terkait dan yang mengimplementasikannya:
Proses penyajian dapat digunakan untuk mengimplementasikan kustomisasi platform dengan membuat perender kustom untuk WebView
di setiap platform. Proses untuk melakukan ini adalah sebagai berikut:
HybridWebView
Buat kontrol kustom.HybridWebView
Gunakan dari Xamarin.Forms.- Buat perender kustom untuk
HybridWebView
di setiap platform.
Setiap item sekarang akan dibahas pada gilirannya untuk mengimplementasikan perender HybridWebView
yang meningkatkan Xamarin.FormsWebView
untuk memungkinkan kode C# dipanggil dari JavaScript. HybridWebView
Instans akan digunakan untuk menampilkan halaman HTML yang meminta pengguna untuk memasukkan namanya. Kemudian, ketika pengguna mengklik tombol HTML, fungsi JavaScript akan memanggil C# Action
yang menampilkan pop-up yang berisi nama pengguna.
Untuk informasi selengkapnya tentang proses pemanggilan C# dari JavaScript, lihat Memanggil C# dari JavaScript. Untuk informasi selengkapnya tentang halaman HTML, lihat Membuat Halaman Web.
Catatan
Dapat WebView
memanggil fungsi JavaScript dari C#, dan mengembalikan hasil apa pun ke kode C# panggilan. Untuk informasi selengkapnya, lihat Memanggil JavaScript.
Membuat HybridWebView
HybridWebView
Kontrol kustom dapat dibuat dengan subkelas WebView
kelas:
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);
}
}
HybridWebView
Kontrol kustom dibuat dalam proyek pustaka .NET Standard dan menentukan API berikut untuk kontrol:
- Properti
Uri
yang menentukan alamat halaman web yang akan dimuat. - Metode
RegisterAction
yang mendaftarkanAction
dengan kontrol. Tindakan terdaftar akan dipanggil dari JavaScript yang terkandung dalam file HTML yang direferensikan melaluiUri
properti . - Metode
CleanUp
yang menghapus referensi ke yang terdaftarAction
. - Metode
InvokeAction
yang memanggil yang terdaftarAction
. Metode ini akan dipanggil dari perender kustom di setiap proyek platform.
Mengonsumsi HybridWebView
HybridWebView
Kontrol kustom dapat direferensikan dalam XAML dalam proyek pustaka Standar .NET dengan mendeklarasikan namespace untuk lokasinya dan menggunakan awalan namespace pada kontrol kustom. Contoh kode berikut menunjukkan bagaimana HybridWebView
kontrol kustom dapat digunakan oleh halaman 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>
local
Awalan namespace dapat diberi nama apa pun. Namun, clr-namespace
nilai dan assembly
harus cocok dengan detail kontrol kustom. Setelah namespace dinyatakan, awalan digunakan untuk mereferensikan kontrol kustom.
Contoh kode berikut menunjukkan bagaimana HybridWebView
kontrol kustom dapat dikonsumsi oleh halaman C#:
public HybridWebViewPageCS()
{
var hybridWebView = new HybridWebView
{
Uri = "index.html"
};
// ...
Padding = new Thickness(0, 40, 0, 0);
Content = hybridWebView;
}
HybridWebView
Instans akan digunakan untuk menampilkan kontrol web asli di setiap platform. Uri
Properti ini diatur ke file HTML yang disimpan di setiap proyek platform, dan yang akan ditampilkan oleh kontrol web asli. HTML yang dirender meminta pengguna untuk memasukkan namanya, dengan fungsi JavaScript memanggil C# Action
sebagai respons terhadap klik tombol HTML.
mendaftarkan HybridWebViewPage
tindakan yang akan dipanggil dari JavaScript, seperti yang ditunjukkan dalam contoh kode berikut:
public partial class HybridWebViewPage : ContentPage
{
public HybridWebViewPage()
{
// ...
hybridWebView.RegisterAction(data => DisplayAlert("Alert", "Hello " + data, "OK"));
}
}
Tindakan ini memanggil DisplayAlert
metode untuk menampilkan pop-up modal yang menyajikan nama yang dimasukkan di halaman HTML yang ditampilkan oleh HybridWebView
instans.
Perender kustom sekarang dapat ditambahkan ke setiap proyek aplikasi untuk meningkatkan kontrol web platform dengan memungkinkan kode C# dipanggil dari JavaScript.
Membuat perender kustom di setiap platform
Proses untuk membuat kelas perender kustom adalah sebagai berikut:
- Buat subkelas
WkWebViewRenderer
kelas di iOS, danWebViewRenderer
kelas di Android dan UWP, yang merender kontrol kustom. - Ambil alih
OnElementChanged
metode yang merenderWebView
logika tulis dan untuk menyesuaikannya. Metode ini dipanggil ketikaHybridWebView
objek dibuat. ExportRenderer
Tambahkan atribut ke kelas perender kustom atau AssemblyInfo.cs, untuk menentukan bahwa atribut tersebut akan digunakan untuk merender Xamarin.Forms kontrol kustom. Atribut ini digunakan untuk mendaftarkan perender kustom dengan Xamarin.Forms.
Catatan
Untuk sebagian besar Xamarin.Forms elemen, adalah opsional untuk menyediakan perender kustom di setiap proyek platform. Jika perender kustom tidak terdaftar, maka perender default untuk kelas dasar kontrol akan digunakan. Namun, perender kustom diperlukan di setiap proyek platform saat merender elemen Tampilan .
Diagram berikut mengilustrasikan tanggung jawab setiap proyek dalam aplikasi sampel, bersama dengan hubungan di antara mereka:
HybridWebView
Kontrol kustom dirender oleh kelas perender platform, yang berasal dari WkWebViewRenderer
kelas di iOS, dan dari WebViewRenderer
kelas di Android dan UWP. Ini menghasilkan setiap HybridWebView
kontrol kustom yang dirender dengan kontrol web asli, seperti yang ditunjukkan pada cuplikan layar berikut:
Kelas WkWebViewRenderer
dan WebViewRenderer
mengekspos OnElementChanged
metode , yang dipanggil ketika Xamarin.Forms kontrol kustom dibuat untuk merender kontrol web asli yang sesuai. Metode ini mengambil VisualElementChangedEventArgs
parameter yang berisi OldElement
properti dan NewElement
. Properti ini mewakili Xamarin.Forms elemen tempat perender dilampirkan, dan Xamarin.Forms elemen yang dilampirkan oleh perender. Dalam aplikasi OldElement
sampel, properti akan menjadi null
dan NewElement
properti akan berisi referensi ke HybridWebView
instans.
Versi metode yang OnElementChanged
ditimpa, di setiap kelas perender platform, adalah tempat untuk melakukan penyesuaian kontrol web asli. Referensi ke Xamarin.Forms kontrol yang sedang dirender dapat diperoleh melalui Element
properti .
Setiap kelas perender kustom dihiasi dengan ExportRenderer
atribut yang mendaftarkan perender dengan Xamarin.Forms. Atribut mengambil dua parameter – nama jenis kontrol kustom yang Xamarin.Forms dirender, dan nama jenis perender kustom. assembly
Awalan ke atribut menentukan bahwa atribut berlaku untuk seluruh rakitan.
Bagian berikut membahas struktur halaman web yang dimuat oleh setiap kontrol web asli, proses untuk memanggil C# dari JavaScript, dan implementasinya di setiap kelas perender kustom platform.
Membuat halaman web
Contoh kode berikut menunjukkan halaman web yang akan ditampilkan oleh HybridWebView
kontrol kustom:
<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>
Halaman web memungkinkan pengguna memasukkan namanya dalam input
elemen, dan menyediakan button
elemen yang akan memanggil kode C# saat diklik. Proses untuk mencapai ini adalah sebagai berikut:
- Ketika pengguna mengklik elemen ,
invokeCSCode
fungsi JavaScript dipanggilbutton
, dengan nilaiinput
elemen yang diteruskan ke fungsi . - Fungsi memanggil
invokeCSCode
log
fungsi untuk menampilkan data yang dikirimnya ke C#Action
. Kemudian memanggilinvokeCSharpAction
metode untuk memanggil C#Action
, meneruskan parameter yang diterima dariinput
elemen .
Fungsi invokeCSharpAction
JavaScript tidak ditentukan di halaman web, dan akan disuntikkan ke dalamnya oleh setiap perender kustom.
Di iOS, file HTML ini berada di folder Konten proyek platform, dengan tindakan build BundleResource. Di Android, file HTML ini berada di folder Aset/Konten proyek platform, dengan tindakan build AndroidAsset.
Memanggil C# dari JavaScript
Proses untuk memanggil C# dari JavaScript identik pada setiap platform:
- Perender kustom membuat kontrol web asli dan memuat file HTML yang ditentukan oleh
HybridWebView.Uri
properti . - Setelah halaman web dimuat, perender kustom menyuntikkan
invokeCSharpAction
fungsi JavaScript ke halaman web. - Ketika pengguna memasukkan nama mereka dan mengklik elemen HTML
button
,invokeCSCode
fungsi dipanggil, yang pada gilirannyainvokeCSharpAction
memanggil fungsi. - Fungsi ini
invokeCSharpAction
memanggil metode dalam perender kustom, yang pada gilirannyaHybridWebView.InvokeAction
memanggil metode . - Metode memanggil
HybridWebView.InvokeAction
yang terdaftarAction
.
Bagian berikut akan membahas bagaimana proses ini diterapkan pada setiap platform.
Membuat perender kustom di iOS
Contoh kode berikut menunjukkan perender kustom untuk platform 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);
}
}
}
Kelas HybridWebViewRenderer
memuat halaman web yang ditentukan dalam HybridWebView.Uri
properti ke dalam kontrol asli WKWebView
, dan invokeCSharpAction
fungsi JavaScript disuntikkan ke halaman web. Setelah pengguna memasukkan nama mereka dan mengklik elemen HTML button
, invokeCSharpAction
fungsi JavaScript dijalankan, dengan metode yang DidReceiveScriptMessage
dipanggil setelah pesan diterima dari halaman web. Pada gilirannya, metode ini memanggil HybridWebView.InvokeAction
metode , yang akan memanggil tindakan terdaftar untuk menampilkan pop-up.
Fungsionalitas ini dicapai sebagai berikut:
- Konstruktor perender membuat
WkWebViewConfiguration
objek, dan mengambil objeknyaWKUserContentController
. Objek memungkinkanWkUserContentController
memposting pesan dan menyuntikkan skrip pengguna ke halaman web. - Konstruktor perender membuat
WKUserScript
objek, yang menyuntikkaninvokeCSharpAction
fungsi JavaScript ke halaman web setelah halaman web dimuat. - Konstruktor perender memanggil
WKUserContentController.AddUserScript
metode untuk menambahkanWKUserScript
objek ke pengontrol konten. - Konstruktor perender memanggil
WKUserContentController.AddScriptMessageHandler
metode untuk menambahkan penangan pesan skrip bernamainvokeAction
keWKUserContentController
objek, yang akan menyebabkan fungsiwindow.webkit.messageHandlers.invokeAction.postMessage(data)
JavaScript didefinisikan dalam semua bingkai di semuaWebView
instans yang menggunakanWKUserContentController
objek . - Asalkan perender kustom dilampirkan ke elemen baru Xamarin.Forms :
- Metode
WKWebView.LoadRequest
memuat file HTML yang ditentukan olehHybridWebView.Uri
properti . Kode menentukan bahwa file disimpan diContent
folder proyek. Setelah halaman web ditampilkan,invokeCSharpAction
fungsi JavaScript akan disuntikkan ke halaman web.
- Metode
- Sumber daya dirilis saat elemen perender dilampirkan ke perubahan.
- Elemen Xamarin.Forms dibersihkan ketika perender dibuang.
Catatan
Kelas WKWebView
hanya didukung di iOS 8 dan yang lebih baru.
Selain itu, Info.plist harus diperbarui untuk menyertakan nilai berikut:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
Membuat perender kustom di android
Contoh kode berikut menunjukkan perender kustom untuk platform 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);
}
}
}
Kelas HybridWebViewRenderer
memuat halaman web yang ditentukan dalam HybridWebView.Uri
properti ke dalam kontrol asli WebView
, dan invokeCSharpAction
fungsi JavaScript disuntikkan ke halaman web, setelah halaman web selesai dimuat, dengan OnPageFinished
penimpaan di JavascriptWebViewClient
kelas:
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);
}
}
Setelah pengguna memasukkan nama mereka dan mengklik elemen HTML button
, invokeCSharpAction
fungsi JavaScript dijalankan. Fungsionalitas ini dicapai sebagai berikut:
- Asalkan perender kustom dilampirkan ke elemen baru Xamarin.Forms :
- Metode
SetWebViewClient
ini menetapkan objek baruJavascriptWebViewClient
sebagai implementasi .WebViewClient
- Metode ini
WebView.AddJavascriptInterface
menyuntikkan instans baruJSBridge
ke dalam bingkai utama konteks JavaScript WebView, memberinyajsBridge
nama . Ini memungkinkan metode diJSBridge
kelas diakses dari JavaScript. - Metode
WebView.LoadUrl
memuat file HTML yang ditentukan olehHybridWebView.Uri
properti . Kode menentukan bahwa file disimpan diContent
folder proyek. JavascriptWebViewClient
Di kelas ,invokeCSharpAction
fungsi JavaScript disuntikkan ke halaman web setelah halaman selesai dimuat.
- Metode
- Sumber daya dirilis saat elemen perender dilampirkan ke perubahan.
- Elemen Xamarin.Forms dibersihkan ketika perender dibuang.
invokeCSharpAction
Ketika fungsi JavaScript dijalankan, fungsi tersebut pada gilirannya memanggil JSBridge.InvokeAction
metode , yang ditunjukkan dalam contoh kode berikut:
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);
}
}
}
Kelas harus berasal dari Java.Lang.Object
, dan metode yang terekspos ke JavaScript harus dihiasi dengan [JavascriptInterface]
atribut dan [Export]
. Oleh karena itu, ketika invokeCSharpAction
fungsi JavaScript disuntikkan ke halaman web dan dijalankan, fungsi ini akan memanggil JSBridge.InvokeAction
metode karena dihiasi dengan [JavascriptInterface]
atribut dan [Export("invokeAction")]
. Pada gilirannya InvokeAction
, metode HybridWebView.InvokeAction
memanggil metode , yang akan memanggil tindakan terdaftar untuk menampilkan pop-up.
Penting
Proyek Android yang menggunakan [Export]
atribut harus menyertakan referensi ke Mono.Android.Export
, atau kesalahan kompilator akan dihasilkan.
Perhatikan bahwa JSBridge
kelas mempertahankan WeakReference
ke HybridWebViewRenderer
kelas . Hal ini untuk menghindari pembuatan referensi melingkar antara kedua kelas. Untuk informasi selengkapnya, lihat Referensi Lemah.
Membuat perender kustom di UWP
Contoh kode berikut menunjukkan perender kustom untuk 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);
}
}
}
Kelas HybridWebViewRenderer
memuat halaman web yang ditentukan dalam HybridWebView.Uri
properti ke dalam kontrol asli WebView
, dan invokeCSharpAction
fungsi JavaScript disuntikkan ke halaman web, setelah halaman web dimuat, dengan WebView.InvokeScriptAsync
metode . Setelah pengguna memasukkan nama mereka dan mengklik elemen HTML button
, invokeCSharpAction
fungsi JavaScript dijalankan, dengan metode yang OnWebViewScriptNotify
dipanggil setelah pemberitahuan diterima dari halaman web. Pada gilirannya, metode ini memanggil HybridWebView.InvokeAction
metode , yang akan memanggil tindakan terdaftar untuk menampilkan pop-up.
Fungsionalitas ini dicapai sebagai berikut:
- Asalkan perender kustom dilampirkan ke elemen baru Xamarin.Forms :
- Penanganan aktivitas untuk
NavigationCompleted
peristiwa danScriptNotify
didaftarkan. PeristiwaNavigationCompleted
diaktifkan ketika kontrol asliWebView
telah selesai memuat konten saat ini atau jika navigasi telah gagal. Peristiwa diaktifkanScriptNotify
ketika konten dalam kontrol asliWebView
menggunakan JavaScript untuk meneruskan string ke aplikasi. Halaman web mengaktifkanScriptNotify
peristiwa dengan memanggilwindow.external.notify
saat meneruskanstring
parameter. - Properti
WebView.Source
diatur ke URI file HTML yang ditentukan olehHybridWebView.Uri
properti . Kode mengasumsikan bahwa file disimpan diContent
folder proyek. Setelah halaman web ditampilkan,NavigationCompleted
peristiwa akan diaktifkan danOnWebViewNavigationCompleted
metode akan dipanggil. FungsiinvokeCSharpAction
JavaScript kemudian akan disuntikkan ke halaman web denganWebView.InvokeScriptAsync
metode , asalkan navigasi berhasil diselesaikan.
- Penanganan aktivitas untuk
- Peristiwa dihentikan langganannya dari saat elemen perender dilampirkan ke perubahan.
- Elemen Xamarin.Forms dibersihkan ketika perender dibuang.