Apa itu WebView
WebView adalah sebuah class pada Android yang berfungsi sebagai semacam sandbox untuk menampilkan dan menjalan aplikasi mobile yang berbasiskan web, entah itu HTML5, JQuery Mobile, dan sebagainya. Cara gampangnya WebView itu seperti Android browser, tetapi tidak mempunyai address bar tempat memasukkan alamat URL. Karena URL yang mau kita buka sudah didefinisikan di aplikasi dan tidak bisa kita ganti.
Web Client
Dalam implementasinya, WebView mempunyai dua buah klien yang bisa kita gunakan untuk me-render halaman web, dan tiap-tiap klien tersebut mempunyai fungsionalitas yang berbeda-beda. Kedua klien tersebut adalah WebViewClient dan WebChromeClient.
WebViewClient adalah sebuah browser klien yang menyediakan fungsi-fungsi dasar dalam menampilkan halaman web. Sedangkan,
WebChromeClient adalah browser klien yang menyediakan fitur-fitur advanced dalam rendering halaman web, kebanyakan berhubungan dengan interaksi antara browser dengan javascript, menampilkan objek seperti video, dan fitur-fitur advanced lainnya. Kalian bisa menggunakan kedua klien tersebut, namun apabila kalian hanya ingin me-render halaman web yang tidak membutuhkan banyak fitur (misal berisi HTML saja, tanpa javascript) maka kalian cukup menggunakan WebViewClient.
Pada dasarnya inisialisasi sebuah aplikasi WebView di Android adalah seperti berikut :
webView= (WebView) findViewById(R.id.webview);
webView.setWebChromeClient(new WebChromeClient());
webView.setWebViewClient(new WebViewClient());
//mengaktifkan dukungan untuk javascript
webView.getSettings().setJavaScriptEnabled(true);
webView.loadUrl("http://www.twoh.co");
Adapun untuk aplikasi yang lebih advanced, contoh kodenya seperti berikut :
webView = (WebView) findViewById(R.id.wv_twoh);
webSettings = (WebSettings) webView.getSettings();
String url = "http://twoh.co";
// memberitahukan browser untuk mengaktifkan Wide ViewPort
webSettings.setUseWideViewPort(true);
// otomatis website akan diload dengan zoom out
webSettings.setLoadWithOverviewMode(true);
// otomatis menampilkan javascript window
webSettings.setJavaScriptCanOpenWindowsAutomatically(true);
// mengaktifkan fungsi-fungsi storage HTML5
webSettings.setDatabaseEnabled(true);
webSettings.setDomStorageEnabled(true);
String databasePath = this.getApplicationContext()
.getDir("databases", Context.MODE_PRIVATE).getPath();
webSettings.setDatabasePath(databasePath);
webSettings.setJavaScriptEnabled(true);
// mengaktifkan fitur geolocation (deteksi lokasi)
webSettings.setGeolocationEnabled(true);
webSettings.setGeolocationDatabasePath(databasePath);
// menonaktifkan hw acceleration yang kadang bermasalah
// dengan mengaktifkan software layer
webView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
webView.loadUrl(url);
Bisa dilihat, banyak sekali settingan yang saya nyalakan pada kode di atas. Untuk geolocation, ketika diaktifkan maka browser akan menampilkan alert, apakah aplikasi boleh mengakses lokasi pengguna atau tidak. Namun fungsionalitas ini bisa di bypass sehingga aplikasi secara otomatis akan mendapatkan lokasi pengguna. 😀 Setelah itu saya akan memberikan contoh pembuatan custom WebViewClient dan WebChromeClient
Custom WebViewClient
Pada aplikasi WebView yang saya buat, tidak ada banyak perubahan untuk kelas WebViewClient. Adapun beberapa hal dasar yang saya implementasikan seperti, menampilkan progress dialog ketika mulai me-load web page, dan meng-override url loading sehingga url yang diklik akan di-load pada WebView tersebut dan tidak membuka aplikasi browser lainnya. Berikut ini contoh kodenya.
public class TwohWebViewClient extends WebViewClient{
public static final String TAG = TwohWebViewClient.class.getSimpleName();
private Activity activity;
private ProgressDialog pgDialog;
public TwohWebViewClient(Activity act) {
activity = act;
// inisialisasi progress dialog
pgDialog = TwohWebViewUtils.getProgressDialog(activity, ProgressDialog.STYLE_SPINNER, true, "loading", false);
}
// Untuk memaksa me-load URL pada browser WebView ini
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
webView.loadUrl(url);
return true;
}
// dipanggil pada saat halaman web mulai di-load, menampilkan progress dialog
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon)
{
super.onPageStarted(view, url, favicon);
pgDialog.show();
Log.v(TAG,"page started "+ url);
}
// dipanggil pada saat halaman web selesai di-load, menghilangkan progress dialog
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
pgDialog.dismiss();
Log.v(TAG,"page finished "+ url);
}
}
Custom WebChromeClient
Sedangkan untuk custom WebChromeClient, ada lumayan banyak method yang harus diubah. Diantaranya seperti bypass geolocation permission menjadi always allow, kemudian menampilkan output
console.log()
pada javascript ke logcat Android, dan yang terakhir adalah mengaktifkan fitur HTML5 media capture. Dan bagian terakhir ini yang menjadi blunder terbesar. :v
public class TwohWebChromeClient extends WebChromeClient{
private Context context;
private Activity activity;
public static final String TAG = TwohWebChromeClient .class.getSimpleName();
public TwohWebChromeClient (Context ctx, Activity act) {
context = ctx;
activity = act;
}
// display javascript log message pada LogCat
@Override
public boolean onConsoleMessage(ConsoleMessage cm) {
Log.v(TAG,cm.message() + " log from line "+cm.lineNumber()+ " of " + cm.sourceId());
return true;
}
// tidak menampilkan prompt, bypass menjadi always allow get location
@Override
public void onGeolocationPermissionsShowPrompt(final String origin,
final GeolocationPermissions.Callback callback) {
callback.invoke(origin, true, true);
}
// hidden API, akan dijelaskan lebih lanjut 😀
public void openFileChooser(ValueCallback<Uri> uploadMsg,String acceptType, String capture) {
Log.v(TAG, "called first");
openFileChooser(uploadMsg);
}
public void openFileChooser(ValueCallback<Uri> uploadMsg,
String acceptType) {
Log.v(TAG, "called two");
openFileChooser(uploadMsg);
}
public void openFileChooser(ValueCallback<Uri> uploadMsg) {
TwohWebActivity.mUploadMessage = uploadMsg;
Log.v(TAG, "called three");
Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
File externalDataDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM);
File cameraDataDir = new File(externalDataDir.getAbsolutePath() +
File.separator + "browser-photos");
cameraDataDir.mkdirs();
TwohWebActivity.filePath = cameraDataDir.getAbsolutePath() + File.separator +"static_photo.jpg";
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(TwohWebActivity.filePath)));
activity.startActivityForResult(cameraIntent, TwohWebActivity.TAKE_PICTURE);
}
}
Kelemahan WebView
Sebenarnya untuk fungsi-fungsi dasar, aplikasi ini berjalan dengan lancar. Hingga kemudian ada satu requirements yaitu capture image dari kamera dan kemudian menguploadnya ke web yang ternyata tidak berjalan dengan mulus. Pada kode HTML-nya menggunakan syntax HTML5 untuk upload file, yaitu
<input type="file" media="capture" />
. Ketika link tersebut dibuka lewat browser bawaan Android dan Google Chrome for Android, aplikasi akan langsung menjalankan kamera sehingga user bisa ambil gambar dan menguploadnya. Namun ketika membukanya menggunakan WebView, tidak muncul apa-apa. 😀 Setelah saya selidiki, ternyata ada sebuah hidden API yang harus dipanggil supaya aplikasi bisa membuka kamera dan menjalankan HTML5 media capture. Hidden API itu adalah method
openFileChooser()
.
Disebut hidden API karena method tersebut adalah private API, bukan public API, sehingga apabila kalian menulis ulang method tersebut dan menambahkan
@Override
, Eclipse akan memberikan pesan error walaupun nyatanya memang method tersebut sudah di-override.
Selain merupakan private API, jika kalian cermati pada kode di atas ada tiga buah deklarasi
openFileChooser()
method. Hal itu karena pada tiap-tiap API level, method openFileChooser() yang dipanggil berbeda-beda, yaitu :
– openFileChooser(ValueCallback uploadMsg), untuk Android versi <= 3.0
– openFileChooser(ValueCallback uploadMsg, String acceptType), untuk Android versi > 3.0
– openFileChooser(ValueCallback uploadMsg, String acceptType, String capture), untuk Android versi Jelly Bean
Lantas, bagaimana dengan KitKat? 😀
Ternyata, pada release Android KitKat, default WebView pada Android diganti menggunakan engine Chrome. Sehingga tidak ada satupun method
openFileChooser di atas yang berjalan pada Android KitKat.
Tidak hanya itu, WebView seringkali juga menunjukkan performansi yang tidak konsisten. Seperti kadang berhasil upload gambar, dan kadang tidak berhasil. Padahal menggunakan baris kode yang sama. Walaupun sebenarnya bisa saja hal ini disebabkan oleh script di sisi web-nya, karena kebetulan yang membuat aplikasi web-nya bukan saya, sehingga kurang bebas untuk melakukan modifikasi. Mungkin untuk teknik lebih advanced-nya, aplikasi mobile web yang akan ditampilkan menggunakan WebView harus dicoding dengan Android in mind. Dan kemudian dari sisi Android membuat sebuah javascript interface sendiri yang bisa berinteraksi dengan javascript di sisi website.
Untuk aplikasi web mobile yang sekedar browsing, input form dan sebagainya, WebView masih bagus dan recommended untuk digunakan. Namun untuk aplikasi yang membutuhkan fungsi native, sepertinya harus menggunakan aplikasi native juga. Atau framework yang lebih canggih seperti PhoneGap/Apache Cordova.
Baca juga