# Mobile (Webview)

Pertama, pilih file HTML **index-debug-standard.html** dan ganti namanya menjadi **index-mobile.html (**&#x49;ni opsional atau Anda dapat membiarkannya saja seperti itu).

Kemudian, buka file HTML dan salin kode di bawah ini ke index situs web Anda atau masukkan file HTML. Tempel kode di dalam tag **\<head>** Anda.

```
<html>
<head>
  <meta charset="UTF-8">
  <title>Enterprise Web Chat</title>
  <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1,user-scalable=no" />
  <link rel='stylesheet prefetch' href='https://fonts.googleapis.com/css?family=Open+Sans'>
  <link rel="stylesheet" href="css/indigo.css">
  <link rel="stylesheet" href="css/widget.css">
  <link rel="stylesheet" href="css/lightslider.css">
  <link rel="stylesheet" href="css/intlTelInput.css">
	<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1,user-scalable=no" />
	<style type="text/css">
		html {
			background: url(images/bg-login.svg) no-repeat;
			height: 100%;
			background-size: cover;
		}
	</style>
  <!-- <script src="https://maps.googleapis.com/maps/api/js?key=<KEY>&libraries=places"></script> -->
  <script src="https://www.google.com/recaptcha/api.js"></script>
  <!-- <script src="http://code.responsivevoice.org/responsivevoice.js"></script> -->
  <script src='js/jquery-2.1.3.min.js'></script>
  <script src='js/iframeResizer.contentWindow.js'></script>
  <script src='js/iframeResizer.js'></script>
  <script src='js/lightslider.js'></script>  
  <script src='js/lazyload.min.js'></script>  
  <script src="js/cryptojs/pbkdf2.js"></script>
  <script src="js/cryptojs/aes.js"></script>
  <script src="js/cipher/aes-util.js"></script>
  <script src="js/stp.js"></script>
  <script src="js/sjs.js"></script>
  <script src="js/chat.js"></script>
  <script src="js/fuse.js"></script>
  <script src="js/speech.js"></script>
  <script src="js/intlTelInput.js"></script>
  <script>
  $(document).ready(function() {
	    Chat.init({
	        header: 'Welcome to Our Chat',
	        login_sub_header: 'Please tell us about yourself',
	        connect_message: 'Do you have questions ? <br>Come chat with us, we are here to help you',
	        chat_sub_header: 'Our agent will serve you shortly',
			url: 'https://<host>:<port>',
			client_id: '<client_id>',
			client_secret: '<client_secret>',	
	        type_placeholder: 'Type message...',
			avatar: '<bot_image>',
			icon_avatar: '<icon_image>',
			agent_avatar: '<agent_image>',
	        enable_attachment: true,
	        enable_voice: true,
	        enable_speech: true,
	        enable_queue: true,
	        enable_history: true,
	        compatibility_mode: false,
	        queue_text: "⏰NOMOR URUT: ",
	        enable_campaign: false,
	        campaign_avatar: '<campaign_image>',
			campaign_title: '<campaign_title>',
	        campaign_text: 'Hello 👋, What do you think about our service ?',
	        campaign_timer: 5000,
	        campaign_menu: [{
	            "label": "<Campaign Label>",
	            "value": "<Campaign Payload>",
	            "icon": "<campaign_icon>"
	        }, {
	            "label": "<Campaign Label>",
	            "value": "<Campaign Payload>",
	            "icon": "<campaign_icon>"
	        }, {
	            "label": "<Campaign Label>",
	            "value": "<Campaign Payload>",
	            "icon": "<campaign_icon>"
	        }],
	        max_upload_message: "File size limit exceeded. Maximum filesize is [max_filesize]",
	        selection_topic_placeholder: "Please select a topic",
	        selection_topic_member: ["Product", "Service"],
	        selection_topic_non_member: ["Hai", "Hello"],
			member_mode: false,
	        selection_topic_placeholder: "Please select a topic",
	        enable_service_hour: false,
	        service_hour: [{
	                "days": "sunday",
	                "startHour": "00:00",
	                "endHour": "23:59",
	                "holiday": true
	            },
	            {
	                "days": "monday",
	                "startHour": "00:00",
	                "endHour": "23:59",
	                "holiday": true
	            },
	            {
	                "days": "tuesday",
	                "startHour": "00:00",
	                "endHour": "15:52",
	                "holiday": true
	            },
	            {
	                "days": "wednesday",
	                "startHour": "00:00",
	                "endHour": "23:59",
	                "holiday": true
	            },
	            {
	                "days": "thursday",
	                "startHour": "00:00",
	                "endHour": "23:59",
	                "holiday": true
	            },
	            {
	                "days": "friday",
	                "startHour": "00:00",
	                "endHour": "23:59",
	                "holiday": true
	            },
	            {
	                "days": "saturday",
	                "startHour": "00:00",
	                "endHour": "23:59",
	                "holiday": true
	            }
	        ],
	        channel_id_email: "25b7fe4f7bd81aa0533be4963972ac74", /* channel id email */
	        subject_email: "Of service hour ticket",
	        send_email_success_message: "Email sent successfully !<br/><br/>Thanks, we have received your question or your complaint",
	        process_send_email_message: "Sending Email...",
	        process_send_email_error_message: "Email sent failed !",
			is_waiting_text_icon: true
	    });
	});
  </script>
</head>
<body>  
</body>
</html>
```

Hapus semua file HTML tetapi pertahankan **index-mobile.html** sebagai gantinya.

![Remove HTML File](https://373685398-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MNQidQwa-0K9_KnQpoc%2F-MVot8IwYOnUt7m-rDlG%2F-MVowMUSM7C6yHkQRSh-%2Fimage.png?alt=media\&token=194a95ba-74d8-4850-88b9-bbf56ddf47db)

Salin seluruh direktori live chat yang tersisa ke path yang Anda tentukan dari server hosting web Anda.&#x20;

Asumsikan yang ingin Anda pilih adalah tema indigo, lalu buka **index-mobile.html** dan ubah kode menggunakan warna yang Anda inginkan.

```
<link rel="stylesheet" href="css/indigo.css">
  <link rel="stylesheet" href="css/widget.css">
  <link rel="stylesheet" href="css/lightslider.css">
  <link rel="stylesheet" href="css/intlTelInput.css">
```

Jangan lupa untuk menyesuaikan resource path yang ada di **index-mobile.html** yang digunakan untuk memuat file seperti js, CSS, atau gambar, sesuai dengan tempat resource disimpan di server Anda.

```
<html>
<head>
  <meta charset="UTF-8">
  <title>Enterprise Web Chat</title>
  <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1,user-scalable=no" />
  <link rel='stylesheet prefetch' href='https://fonts.googleapis.com/css?family=Open+Sans'>
  <link rel="stylesheet" href="css/indigo.css">
  <link rel="stylesheet" href="css/widget.css">
  <link rel="stylesheet" href="css/lightslider.css">
  <link rel="stylesheet" href="css/intlTelInput.css">
	<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1,user-scalable=no" />
	<style type="text/css">
		html {
			background: url(images/bg-login.svg) no-repeat;
			height: 100%;
			background-size: cover;
		}
	</style>
  <!-- <script src="https://maps.googleapis.com/maps/api/js?key=<KEY>&libraries=places"></script> -->
  <script src="https://www.google.com/recaptcha/api.js"></script>
  <!-- <script src="http://code.responsivevoice.org/responsivevoice.js"></script> -->
  <script src='js/jquery-2.1.3.min.js'></script>
  <script src='js/iframeResizer.contentWindow.js'></script>
  <script src='js/iframeResizer.js'></script>
  <script src='js/lightslider.js'></script>  
  <script src='js/lazyload.min.js'></script>  
  <script src="js/cryptojs/pbkdf2.js"></script>
  <script src="js/cryptojs/aes.js"></script>
  <script src="js/cipher/aes-util.js"></script>
  <script src="js/stp.js"></script>
  <script src="js/sjs.js"></script>
  <script src="js/chat.js"></script>
  <script src="js/fuse.js"></script>
  <script src="js/speech.js"></script>
  <script src="js/intlTelInput.js"></script>
  <script>
  $(document).ready(function() {
	    Chat.init({
	        header: 'Welcome to Our Chat',
	        login_sub_header: 'Please tell us about yourself',
	        connect_message: 'Do you have questions ? <br>Come chat with us, we are here to help you',
	        chat_sub_header: 'Our agent will serve you shortly',
			url: 'https://<host>:<port>',
			client_id: '<client_id>',
			client_secret: '<client_secret>',	
	        type_placeholder: 'Type message...',
			avatar: '<bot_image>',
			icon_avatar: '<icon_image>',
			agent_avatar: '<agent_image>',
	        enable_attachment: true,
	        enable_voice: true,
	        enable_speech: true,
	        enable_queue: true,
	        enable_history: true,
	        compatibility_mode: false,
	        queue_text: "⏰NOMOR URUT: ",
	        enable_campaign: false,
	        campaign_avatar: '<campaign_image>',
			campaign_title: '<campaign_title>',
	        campaign_text: 'Hello 👋, What do you think about our service ?',
	        campaign_timer: 5000,
	        campaign_menu: [{
	            "label": "<Campaign Label>",
	            "value": "<Campaign Payload>",
	            "icon": "<campaign_icon>"
	        }, {
	            "label": "<Campaign Label>",
	            "value": "<Campaign Payload>",
	            "icon": "<campaign_icon>"
	        }, {
	            "label": "<Campaign Label>",
	            "value": "<Campaign Payload>",
	            "icon": "<campaign_icon>"
	        }],
	        max_upload_message: "File size limit exceeded. Maximum filesize is [max_filesize]",
	        selection_topic_placeholder: "Please select a topic",
	        selection_topic_member: ["Product", "Service"],
	        selection_topic_non_member: ["Hai", "Hello"],
			member_mode: false,
	        selection_topic_placeholder: "Please select a topic",
	        enable_service_hour: false,
	        service_hour: [{
	                "days": "sunday",
	                "startHour": "00:00",
	                "endHour": "23:59",
	                "holiday": true
	            },
	            {
	                "days": "monday",
	                "startHour": "00:00",
	                "endHour": "23:59",
	                "holiday": true
	            },
	            {
	                "days": "tuesday",
	                "startHour": "00:00",
	                "endHour": "15:52",
	                "holiday": true
	            },
	            {
	                "days": "wednesday",
	                "startHour": "00:00",
	                "endHour": "23:59",
	                "holiday": true
	            },
	            {
	                "days": "thursday",
	                "startHour": "00:00",
	                "endHour": "23:59",
	                "holiday": true
	            },
	            {
	                "days": "friday",
	                "startHour": "00:00",
	                "endHour": "23:59",
	                "holiday": true
	            },
	            {
	                "days": "saturday",
	                "startHour": "00:00",
	                "endHour": "23:59",
	                "holiday": true
	            }
	        ],
	        channel_id_email: "25b7fe4f7bd81aa0533be4963972ac74", /* channel id email */
	        subject_email: "Of service hour ticket",
	        send_email_success_message: "Email sent successfully !<br/><br/>Thanks, we have received your question or your complaint",
	        process_send_email_message: "Sending Email...",
	        process_send_email_error_message: "Email sent failed !",
			is_waiting_text_icon: true
	    });
	});
  </script>
</head>
<body>  
</body>
</html>
```

Selanjutnya, sesuaikan url, client\_id dan properti client\_secret sesuai dengan konfigurasi channel back-end Anda. Silakan merujuk kembali ke bagian [How to Connect Client to Live Chat Channel](https://docs.3dolphins.ai/5.1.x-1/integration/chanel-connector/live-chat/how-to-connect-client-to-live-chat-channel)  untuk informasi lebih lanjut.&#x20;

Di bagian sebelumnya ditujukkan untuk meletakkan source code pada situs web yang sudah tersedia, sedangkan di bagian ini kita harus membuat host live chat secara mandiri.

Di bawah ini merupakan sample code untuk mengonfigurasi tampilan web Anda yang menampilkan **index-mobile.html** yang sudah dihosting.

### **Configure Web View**&#x20;

Anda perlu mengaktifkan Javascript dan DomStorage untuk LocalStorage.

```
webview.getSettings().setJavaScriptEnabled(true);
webview.getSettings().setDatabaseEnabled(true);
webview.getSettings().setDomStorageEnabled(true);
```

Sekarang Anda dapat memuat URL.

```
webview.loadUrl("https://hostname/webchat/index-debug-standard.html");
```

Untuk menyesuaikannya setelah load halaman selesai, Anda dapat menjalankan kode ini.

```
webview.setWebViewClient(new WebViewClient() {
     @Override
     public void onPageFinished(WebView view, String url) {
          progressBar.setVisibility(View.GONE);
          super.onPageFinished(view, url);
     }
});
```

#### Enable Voice to Text (Speech Recognition)

Untuk mengaktifkan fitur ini, pertama-tama Anda perlu mengaktifkan RECORD\_AUDIO pada android manifest.

```
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.imi.dolphin.bella">

    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.RECORD_AUDIO"/>
		...
		...
</manifest>
```

Kemudian, silahkan menginisialisasi Properties untuk mengaktifkan Record Audio Permission.

```
private static final int RECORD_AUDIO_REQUEST_CODE = 123;
private PermissionRequest permissionRequest;
```

{% hint style="info" %}
permissionRequest property digunakan untuk mengakomodasi permintaan dari tampilan web yang akan diberikan akses nanti.
{% endhint %}

Saat ikon 'microphone' diklik, browser akan meminta izin ke perangkat, aplikasi Anda harus menangkap permintaan tersebut. dapat dilakukan dengan:

```
private void loadLiveChat() {
		...
		...

    webview.setWebChromeClient(new WebChromeClient() {
        @Override
        public void onPermissionRequest(PermissionRequest request) {
            if (request != null) {
                permissionRequest = request;
                askPermission();
            }
        }
    });
}

private void askPermission() {
    if (ContextCompat.checkSelfPermission(getApplicationContext(), 
						Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
        
				ActivityCompat.requestPermissions(
						MainActivity.this, 
						new String[]{Manifest.permission.RECORD_AUDIO}, 
						RECORD_AUDIO_REQUEST_CODE
				);
    } else {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            permissionRequest.grant(permissionRequest.getResources());
        }
    }
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    if(requestCode == RECORD_AUDIO_REQUEST_CODE){
        if(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                permissionRequest.grant(permissionRequest.getResources());
            }
            Toast.makeText(getApplicationContext(), "Permission Granted", Toast.LENGTH_SHORT).show();
        }
    }
}
```

#### Enable Attachment

Anda perlu mengaktifkan izin untuk READ\_EXTERNAL\_STORAGE pada android manifest.

```
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.imi.dolphin.bella">

    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.RECORD_AUDIO"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
		...
</manifest>
```

kemudian, inisialisasi Properties untuk mengakses file.

```
private static final int INPUT_FILE_REQUEST_CODE = 1;
private ValueCallback<Uri[]> mFilePathCallback;
```

Konfigurasi web view untuk mengakses akses file.

```
private void loadLiveChat() {
		...
    webview.getSettings().setLoadWithOverviewMode(true);
    webview.getSettings().setAllowFileAccess(true);
		...
		...
}
```

Saat ikon 'attachment' diklik, browser akan meminta untuk membuka penyimpanan perangkat. Dapat dilakukan dengan:

```
private void loadLiveChat() {
    ...
		...

    webview.setWebChromeClient(new WebChromeClient() {
        ...
				...
				@Override
        public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) { 
            if (mFilePathCallback != null) {
                mFilePathCallback.onReceiveValue(null);
            }
            mFilePathCallback = filePathCallback;

            Intent chooserIntent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
            startActivityForResult(chooserIntent, INPUT_FILE_REQUEST_CODE);
            return true;
        }
    });
}

@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        if (requestCode != INPUT_FILE_REQUEST_CODE || mFilePathCallback == null) {
            super.onActivityResult(requestCode, resultCode, data);
            return;
        }
        Uri[] results = null;
        if (resultCode == Activity.RESULT_OK) {
            if (data != null) {
                String dataString = data.getDataString();
                results = new Uri[]{Uri.parse(dataString)};
            }
        }
        mFilePathCallback.onReceiveValue(results);
        mFilePathCallback = null;
    }
}
```

Di bawah ini adalah contoh final code jika Anda sudah mengikuti langkah-langkah di atas.&#x20;

```
package com.imi.dolphin.bella;

import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.view.View;
import android.webkit.PermissionRequest;
import android.webkit.ValueCallback;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.ProgressBar;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

public class MainActivity extends AppCompatActivity {

    /**
     * Properties to access file
     */
    private static final int INPUT_FILE_REQUEST_CODE = 1;
    private ValueCallback<Uri[]> mFilePathCallback;

    /**
     * Properties to enable Record Audio Permission
     * <p>
     * the permissionRequest property is used to accommodate requests from the web view that will be granted access later
     */
    private static final int RECORD_AUDIO_REQUEST_CODE = 123;
    private PermissionRequest permissionRequest;

    /**
     * Initial Component Web View and Progress Bar
     */
    private WebView webview;
    private ProgressBar progressBar;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        init();
        loadLiveChat();
    }

    /**
     * Configure Web View
     */
    @SuppressLint("SetJavaScriptEnabled")
    private void loadLiveChat() {
        webview.loadUrl("<Server URL>");

        // Configure WebView To set Enable Javascript True And To Activate DomStorage True For LocalStorage
        webview.getSettings().setJavaScriptEnabled(true);
        webview.getSettings().setDatabaseEnabled(true);
        webview.getSettings().setDomStorageEnabled(true);

        // Configure WebView to access file access
        webview.getSettings().setLoadWithOverviewMode(true);
        webview.getSettings().setAllowFileAccess(true);

        webview.setWebViewClient(new WebViewClient() {
            @Override
            public void onPageFinished(WebView view, String url) {
                progressBar.setVisibility(View.GONE);
                super.onPageFinished(view, url);
            }
        });
        webview.setWebChromeClient(new WebChromeClient() {
            @Override
            public void onPermissionRequest(PermissionRequest request) {
                if (request != null) {
                    permissionRequest = request;
                    askPermission();
                }
            }

            @Override
            public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
                // Double check that we don't have any existing callbacks
                if (mFilePathCallback != null) {
                    mFilePathCallback.onReceiveValue(null);
                }
                mFilePathCallback = filePathCallback;

                Intent chooserIntent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
                startActivityForResult(chooserIntent, INPUT_FILE_REQUEST_CODE);
                return true;
            }
        });
    }

    /**
     * Binding Item
     */
    private void init() {
        webview = findViewById(R.id.web_view);
        progressBar = findViewById(R.id.progress_bar);
        progressBar.setVisibility(View.VISIBLE);
    }

    /**
     * ask permission for Record Audio
     */
    private void askPermission() {
        if (ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.RECORD_AUDIO}, RECORD_AUDIO_REQUEST_CODE);
        } else {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                permissionRequest.grant(permissionRequest.getResources());
            }
        }
    }

    /**
     * Catch permission from user
     */
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        if (requestCode == RECORD_AUDIO_REQUEST_CODE) {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                    permissionRequest.grant(permissionRequest.getResources());
                }
                Toast.makeText(getApplicationContext(), "Permission Granted", Toast.LENGTH_SHORT).show();
            }
        }
    }

    /**
     * Catch File data from user
     */
    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            if (requestCode != INPUT_FILE_REQUEST_CODE || mFilePathCallback == null) {
                super.onActivityResult(requestCode, resultCode, data);
                return;
            }
            Uri[] results = null;
            if (resultCode == Activity.RESULT_OK) {
                if (data != null) {
                    String dataString = data.getDataString();
                    results = new Uri[]{Uri.parse(dataString)};
                }
            }
            mFilePathCallback.onReceiveValue(results);
            mFilePathCallback = null;
        }
    }
}
```

Jika Anda ingin mencoba code kami, klik [ini](https://github.com/3dolphin/3dolphins-webview-android) untuk memulai.
