你知道你的網站可能在 InAppBrowser/webview 無法使用嗎?

你知道你的購物網站,可能在 Facebook App 裡面無法結帳嗎?

最近遇到一些案例
– 購物網站上線後,廠商說許多消費者回報「購物車無法刪除商品」
– 購物網站選擇取貨的超商分店後「無法跳回原本的結帳頁面」。
– 活動網站有一些需要使用FB登入或分享後,可以投票或登錄抽獎的功能,但 FB登入或分享後卻無法回到原來的活動網頁,或是擷取到的值有異常。

工程師用了幾十年 的 JavaScript confirm() 跟 window.open() 語法,到底會有什麼問題?

一開始以為是資訊界的「顧客整人」理論(註一)。但是深入了解後,終於重現發生問題的情況: 網站主要導流來源是 Facebook 粉絲專頁,只要使用者使用 iOS Facebook app 內的瀏覽器開啟網站,一些 JS 功能就會失效,但如果將連結使用一般的 Safari 瀏覽器開啟,則是一切正常。這種 APP 內的瀏覽器有個專有名詞,叫做 InAppBrowser(in-app browser),或是對 App 開發人員,叫做 “UIWebView”。

註一: 服務業有所謂「顧客至上」理論,不需要任何邏輯,花錢的就是大爺,客人就是神。資訊界則相傳有「顧客整人」理論,程式不會有問題,常常是使用者不會用,或是軟硬體太舊或太新,而發生相容性問題。

再找了一些瀏覽器功能支援度的線上測試工具,用這年頭最新的 iOS 9 實機測試,Safari 跟 InAppBrowser 的確會跑出不一樣的分數,證據確鑿! 明明在同一台裝置上,都可以看網頁,但這種 in-app browser 跟 Safari, Google Chrome 卻是不一樣的東西。

除了那些細部的測試,另外之後也初步條列出幾個常用,但是會在 InAppBrowser 發生問題的語法:

alert() :無法出現對話提醒視窗

所以「請填寫某欄位」之類的提示通通看不到,假如姓名欄位必填,有個使用者沒填姓名,但是他點送出的時候,網頁也無法提示「請填寫姓名」,使用者只會看到點了送出,怎麼網頁都沒反應?

confirm() :對話確認視窗無法出現

if(confirm) 的行為通通無法繼續操作。「是否確定刪除購物車內的商品?」之類的確認視窗通通看不到,也無法操作,這是使用者體驗的一大忌,因故完全無法操作,但使用者又無法得知發生了什麼事。

下載圖片(儲存影像)

在行動裝置的網頁上,對圖片長按螢幕時,正常會出現一個下載檔案的提示視窗,但是在許多 in-app browser,長按螢幕是沒有任何動作的。

window.open 或 window.opener:與電腦上完全不同的顯示行為。

會有兩種情況產生,一種是點擊後毫無動作,如果選超商分店之類的 emap 是用 window.open 來做,那使用者是無法選擇超商的。target=”_blank”倒是可以用的,沒問題。
另一種是後來開的網頁會覆蓋原本的頁面,而不會在新視窗開啟。如果沒有特別作紀錄,將導致使用者剛剛輸入的內容被清除掉,又得重新輸入。

window.close 或 self.close :失效。

承上,因為頁面已經被覆蓋掉了,所以一些指定視窗跳回的也失效了。程式可以接收到傳回的資料值,但使用者只會看到一個精美的空白畫面,無法關閉分頁。 有些 App 按返回,會直接跳回 App 的文章,而不是網頁的上一頁,不管是卡在空白畫面或是無法回上一頁,等於結帳流程或正常操作流程完全被中斷。

但是裡面有內建瀏覽器,而預設不會直接呼叫 Safari 開啟網頁的 App ,不只有 Facebook 呀!
又測試了一些比較常見的 App,檢測以上項目,只要有一項無法操作,就打叉。

  • Facebook (X)
  • Line (O)
  • Plurk (X)
  • Pinterest (O)
  • Pocket (X)
  • QQ (O)
  • Twitter (X)
  • Wechat (O)
  • Whatsapp (O)
  • 新浪微博 (O)

除了上述的社群軟體或閱讀軟體,其實還有掃描 QR code 的軟體要測,但是太多了,先忽略。以上是 iOS 中發生的問題,至於 Android 呢? Android 4.x 跟 Android 5.01 大致上沒發現這問題。

這份問題 App 清單不一定是準確的,因為症狀通常不會同時出現,還有可能某 App 今天沒事,但更新後就有問題了。或是本來有問題,但某天 App 更新後就正常了。還有明明 App 已經修復此問題,使用者卻從來都不知道要更新 App,繼續使用有問題的版本。

測試頁

點擊前往測試頁

製作了一個簡易的測試頁,可以把網站貼到 Facebook 或是 Line 上面,看看會發生怎樣的情況。

解決方案

現在是科學的時代,先把網站的 GA 報表叫出來看看影響層面究竟有多大? 是否真的有需要解決? 但數據表示用行動裝置的比用桌機的還多,iOS user 更是 Android user 的兩倍,所以目標客戶群主要還是拿 iOS 裝置的使用者,這問題是不能不找出解法了。

要是每個人都去發個負評,那就甭玩了
要是每個人都去發個負評,那就甭玩了

網站已經上線好幾週了,這種裝置不支援的問題算 bug 嗎? 網頁公司是否要無償去修正?
那 Flash 在手機上面不能看也算 bug 嗎?
XX 銀行的 WebATM 因為使用了 ActiveX 或 NPAPI,無法在所有網頁瀏覽器執行,算 bug 嗎?
廠商把責任推給網頁公司,網頁公司把責任推給 Mark Zuckerberg,Mark Zuckerberg 把責任推給 Steve Jobs,所以先準備買機票去美國抗議,使用者的問題最後還是沒解決,事情不是這樣幹的。

這時候要拿出將太的壽司的經典台詞之一:
服務業是一種沒有功勞,只有苦勞的行業
服務業是一種沒有功勞,只有苦勞的行業

改程式、跟開設測試機都是要花錢的,先來考察別人都怎麼解決的:

1.網站公告法

用 Google 找了一下,這種「請消費者用預設瀏覽器開啟網站」的說明文還真不少,
隨便舉幾個來瞧瞧:
in-app 案例一
(案例一▲)

in-app 案例二
(案例二▲)

in-app 案例三
(案例三▲)

(案例四 – 批踢踢網路創業板 – 緊急分享 fb app更新影響訂單成立

in-app 案例五
(案例五▲)

正常的購物行為,不管是明確型還是閒逛型購物,會先去看商店公告,再開始消費的使用者比例其實是不高。如果叫廠商的 FB 小編每次發文時都要加「請消費者用預設瀏覽器開啟網站」,或是「請消費者自己更改 APP 開啟網頁的預設值(這個設定iOS 沒有,只有 Android 的 Facebook app 才有。)」,都是不夠理想的作法,通常是花不起錢,或是時間有限的時候才會做這種事。

2.偵測 in-app browser 自動顯示提示

如果抱著專業心態,遵照一般流程,先 shutdown 有問題的網站…..馬上就被老闆巴頭,所以網站還是要繼續營業。
但是還是要寫報價單、等客戶確認簽回、開設測試主機、調整程式、內部測試、客戶驗收,更新正式機。

這段時間訪客每天嘩啦啦的進來,但問題持續存在,客服人員都崩潰了。應急處置就先來做個提示,判斷如果用 iOS 的 FB APP 開網頁,則會跑出一個「請選擇在 Safari 開啟」的提示。

iOS 8 的那個按鈕都在右上角,iOS 6 的則在右下角,基本上說明圖不能通吃。
iOS 8 的那個按鈕都在右上角,iOS 6 的則在右下角,基本上說明圖不能通吃。

首先發現從 FB App 進站,會帶來源網址(document.referrer),依不同裝置與不同 App 版本,至少會有 http://m.facebook.com, http://m.facebook.com/, https://m.facebook.com, https://m.facebook.com/, http://lm.facebook.com, https://lm.facebook.com/, https://lm.facebook.com, http://lm.facebook.com/ 這八種,所以我們可以用上述 document.referrer 再搭配 iDevice 的 UserAgent 判斷式,來顯示「請選擇在 Safari 開啟」的提示訊息。

但是後來讀取 iOS FB InAppBrowser 的 UserAgent 字串,發現裡面通常有 FBIOS 的字,所以可以這樣寫,用更短的 code 達成需求。
if (navigator.userAgent.match(/FBIOS/i)) {
// show something...
}

以上是針對 FB app 的,那其他的,像是 Line 之類的哩? 一樣可以用實機去測 UA,用 UA 裡的字串來做判斷。
例如 Line 的 in-app browser 瀏覽器的 UA 字串裡面就含有 Line,所以可以如法炮製。

只是以後每流行一個新的 app ,就要去查一次 UA,再加一些判斷式嗎? 得找找有沒有治本的方法。

3.更改程式寫法

台灣是 FB 和 Line 生態系,網站最基本的需求在 FB 上面要完美,不能分享時顯示一些亂七八糟的摘要,還有購物網站要可以完成購物流程。中國大陸地區則是 WeChat 生態系,H5 頁面最基本的標準是要在 WeChat 裡面可以跑,網路上一樣有許多前人分享血淚史。

wechat 也是有本難念的經
wechat 也是有本難念的經

去考察一些連小學生都知道的國內外知名購物網站,或是所謂行動開店服務的網站,是怎麼處理上述問題的。赫然發現,瑞凡,已經沒有人在用 alert(), confirm(), 或 window.open() 了!

防止此網頁產生其他對話方塊
防止此網頁產生其他對話方塊

alert(), confirm() 的歷史悠久,保證絕不出錯,比較不會有明明使用者還沒按下網頁對話視窗上的按鈕,但是程式卻在背後偷跑的情況。也不怕有人關閉視窗,或是繞過去。但是卻有可能有使用者去勾到「防止此網頁產生其他對話方塊」,這樣網站不管執行任何動作,都不會再跳出確認與詢問視窗,造成非常多的問題。每一種瀏覽器的解除法也不一樣,大大增加了客服人員的處理時間。

另一個問題是在每一種瀏覽器、每一種裝置,對話視窗都長得不一樣,例如對話視窗的位置,IE 跟 Firefox 在中間,Chrome for PC 在上方,還有按鈕文字也不同,有的「確定」顯示在右邊,有的「確定」在左邊,在 iOS 上面則顯示「好」,帶來完全不一致的使用者體驗。

由上至下: Safari/ android browser/ chrome on android
由上至下: Safari/ android browser/ chrome on android

window.open() 的好用之處在於可以保留原本的視窗,程式不需要先額外記錄使用者原本輸入的東西後再把視窗轉走。但常見問題則是被瀏覽器的攔截廣告彈跳視窗功能擋住,使用者要發現瀏覽器網址列或是某處多了一些紅叉叉或提示訊息,再去按允許,讓網頁重新整理一次,才能看到應該要顯示的視窗。或是開發人員設定了 windows.open 的尺寸,但是在行動裝置上卻不聽話,造成異常大的空白區域。

一般大型網站是如何排除這些問題呢? 使用自製的網頁 UI 元件

使用自製的元件

  • alert: 使用另外的 Modal, Dialog, Message 相關元件,如淘寶,91APP。
  • confirm: 使用自製的 Modal, Dialog 元件,或是直接執行動作,但是有復原機制,例如有個復原按鈕可以按,如 Yahoo 拍賣。
  • window.open/self.close: 選擇超商的視窗時,先把使用者當下輸入的資料記錄起來,然後整頁轉過去,選完之後再整頁轉回來,並把使用者先前輸入的資料塞回去,完全不彈跳額外的小視窗。如 Yahoo 商城。

結論:

資訊業一日千里,因應日漸複雜的線上資料瀏覽環境,一套程式就想用一輩子是不行的,有些程式只能解決古代的問題,無法解決現代的問題。只會吹噓古時候的成功案例,但是無法滿足現代的客戶,是一點用處都沒有的,必須要常常更新才能更上時代。

但是管理階層或業務常會有「這套程式給某大客戶都用得好好的,幹嘛要更新?」「用起來好像沒啥差別呀,重構後的跟舊的差在哪?」「要做某某功能,應該很快吧?」 的想法,都不用給時間評估哪些地方會有地雷,只能說很容易換了位子就會換了腦袋。

以前高中老師說過,看到一個現象就解釋一個說法,這不叫科學。
但是後來發現長大常常在做不科學的事,見人說人話,見鬼說鬼話,
科學是假的,達成自己的目的才是真的。

2017.5.20 update:
F2E台灣協會發布了一個 JS 套件 detect-inapp,可以用偵測網頁是否在 inapp browser 中運行。
2018.12.22 update:
看網站文章發現 Line 出了個新的參數,只要頁面網址有這個參數,Line 的瀏覽器就會自動把網頁改用 Safari 或外部瀏覽器開啟,嘗試在網頁內增加一段 JS,的確可行:
if (/Line/.test(navigator.userAgent)) {
location.href = location.href + ‘?openExternalBrowser=1’;
}

Previous

行動裝置的水平滾動選單,是個好設計嗎?

Next

讓瀏覽器擴充套件幫助你使用 Google 分析