訪客端 WebView 自行接入
App 用自己的 WebView / WKWebView 打開訪客頁,不接入 Visitor SDK 時按本文對接。
優先使用 訪客 SDK 接入文件。本文只覆蓋「自行載入頁面」。
打開頁面
url 填 控制台設定的 URL 地址,必須 HTTPS。業務參數拼在 query 上,自行做 UTF-8 編碼。不要把密碼、Cookie、AppSecret 或長期 token 放進 URL。
App 內打開建議帶 is_app=1,訪客頁纔會顯示關閉按鈕。
控制台設定的 URL 地址?is_app=1&lang=zh-cn&theme=system
Android:
webView.settings.javaScriptEnabled = true
webView.settings.domStorageEnabled = true
webView.loadUrl(buildVisitorUrl())
iOS:
let config = WKWebViewConfiguration()
config.preferences.javaScriptEnabled = true
webView.load(URLRequest(url: visitorURL))
只加載 URL 即可聊天。關閉按鈕、原生下載、原生鈴聲、Android 錄音授權需要注入 AppBridge,見下文。
query 參數
| 參數 | 必填? | 含義 |
|---|---|---|
is_app | App 內建議 1 | 1 時顯示關閉按鈕,並走 App 返回邏輯 |
lang | 可選,預設頁面語言 | 介面語言:en / zh-cn / zh-tw / ja / ko / de / fr / pt / ru / es / vi / th / id / ms / tl |
theme | 可選,預設 light | light / dark / system |
direct | 直達會話時必填 1 | 直達開關,沒有它時 chatid 無效 |
chatid | 直達會話時必填 | 目標會話 ID(也認 chat_id) |
sbs | 綁使用者時必填 | 業務系統中的使用者唯一 ID |
sbs_mm | 有 sbs 就要 | sbs 的簽名 |
ranstr | 有簽名就要 | 參與簽名的隨機串 |
name | 可選 | 訪客姓名 |
nickname | 可選 | 訪客暱稱 |
email | 可選 | 訪客郵箱 |
phone | 可選 | 訪客手機號 |
customer_remark | 可選 | 客戶備註 |
ext_fk_id | 可選 | 已有訪客 ID,用來續歷史會話 |
referer | 可選 | 來源頁 URL(也認 referer_url) |
source_title | 可選 | 來源頁標題 |
new_message_sound_mode | 可選 | native:新訊息由 App 響鈴;不傳則頁面自己響 |
source | 可選 | webview 隱藏預設返回按鈕 |
不要傳 visitor_id。source=webview 效果等同 is_app=1,傳一個即可。
WebView 要求
- 啓用 JavaScript、DOM Storage
- Cookie / LocalStorage 預設持久化,不要無故清掉(清掉會丟訪客身份)
- 僅加載 HTTPS;系統 ATS / Cleartext 保持預設
- 同域麥克風、相機:在系統中聲明權限(Android
RECORD_AUDIO/CAMERA;iOSNSMicrophoneUsageDescription/NSCameraUsageDescription) - 附件選擇走 WebView 檔案選擇器
- 同域 HTTPS 留在 WebView;跨域 HTTPS 用系統瀏覽器
AppBridge
頁面通過 window.AppBridge.call(method, params, callback) 調 App。頁面每次加載前注入下面腳本(建議 atDocumentStart,不要等 onPageFinished)。
(function () {
window.__TWT_VISITOR_BRIDGE_CONFIG__ = { newMessageSoundMode: 'web' };
window.AppBridge = {
_callbacks: {},
call: function (method, params, callback) {
var id = callback ? 'cb_' + Date.now() + '_' + Math.random().toString(16).slice(2) : null;
if (callback) this._callbacks[id] = callback;
var msg = JSON.stringify({ method: method, params: params || {}, callback: id });
if (window.AppBridgeChannel_native) {
window.AppBridgeChannel_native.postMessage(msg);
} else if (window.webkit && window.webkit.messageHandlers.AppBridgeChannel) {
window.webkit.messageHandlers.AppBridgeChannel.postMessage(msg);
}
return Promise.resolve({ status: 'sent', callbackId: id });
},
invokeCallback: function (id, result) {
var cb = this._callbacks[id];
if (cb) { cb(result); delete this._callbacks[id]; }
}
};
})();
Android 註冊名爲 AppBridgeChannel_native 的 JavascriptInterface(方法名 postMessage)。
iOS 註冊名爲 AppBridgeChannel 的 WKScriptMessageHandler。
訊息 JSON:{ "method": "...", "params": {}, "callback": "cb_..." }。
頁面會調用的方法
| method | 何時 | App 做什麼 |
|---|---|---|
close | 使用者點頁面關閉按鈕 | 關閉 WebView / 退出當前頁 |
download | 儲存圖片、視頻、檔案 | 下載 params.url;完成後見下方回傳 |
new_message | 收到新訊息且鈴聲爲 native | 播放提示音。params 可能含 messageId / chatId |
android_recording_permission | Android 錄音 | 申請麥克風。回傳 { code: 1, data: { permission: true/false } } |
visitor_back_result | 頁面應答了返回 | 見「系統返回」 |
不注入 Bridge 時:關閉按鈕無效果;下載走瀏覽器;鈴聲由頁面自己播。
下載回傳
download 的 params:
| 欄位 | 含義 |
|---|---|
url | 檔案地址 |
type | image / video / 其他 |
fileName | 建議檔案名 |
mimeType | MIME |
requestId | 本次下載 ID |
有 callback 時,下載結束調用:
window.AppBridge.invokeCallback(callbackId, {
code: 1,
data: { requestId: '...', status: 'completed' }
})
status:completed / failed / cancelled。失敗時 code 用 0。
若要把鈴聲交給 App,注入時把 newMessageSoundMode 設爲 'native',或 URL 帶 new_message_sound_mode=native。
系統返回(可選)
使用者按系統返回時,先問頁面(關閉預覽、從會話退回列表):
window.dispatchEvent(new CustomEvent('twt:visitor-event', {
detail: { type: 'back', payload: {} }
}))
約 300ms 內頁面會調 visitor_back_result,params.consumed === true 表示已處理。未處理再關閉 WebView。
執行中切主題(僅 light / dark):
window.dispatchEvent(new CustomEvent('twt:visitor-event', {
detail: { type: 'themeChanged', payload: { theme: 'dark' } }
}))