第一次轉址:透過後台設定 liff.line.me 幫我們自動轉網址
只要有在 LINE LIFF 後台設定 LIFF URL,當使用者透過瀏覽器開啟 LIFF 連結時,瀏覽器會跳轉到 LINE 開發者後台設定該 LIFF 服務的 Endpoint 進入點,例如點擊:
https://liff.line.me/${LIFF_ID}
實際打開後,liff.line.me 會自動幫我們轉網址到後台所設定的進入點網址:
Endpoint URL
這個 Endpoint URL 是由 LIFF 後台所設定的,並且Endpoint URL 一個 LIFF ID 只能設定一個,以我們 Prod 後台的設定,LIFF URL 連結會轉址到 Endpoint URL 設定的 https://產品domain/liff登入頁
並不是在後台設定 LIFF 的 Endpoint URL 後,這個網站就馬上成為完整的 LIFF 服務了,完整的 LIFF 服務還需要在網站載入 SDK 並初始化。
由於 /liff登入頁
只是我們自訂的獨立頁面(以滿足進入點的條件),而 Endpoint URL 只能設定一個,無法設定多組或在後台用 *
字號等方式。為了讓使用者能正確轉址到正確的路徑,我們還需要在 /liff登入頁
內去自己實作轉址的功能。
不論網站本身有沒有載入 LIFF SDK,在 LINE LIFF 後台設定產生出來的 LIFF 連結,LINE 都會將其轉網址到後台設定的 Endpoint URL ,後台的 LIFF 與 Endpoint URL 設定,這就是「第一次」的轉網址。
真實世界的轉網址、路徑的目標
LINE LIFF 後台自動幫我們把 LIFF URL 轉網址到 Endpoint URL,然而以現實商業需求來看,不可能只讓 LIFF 服務只有一個撒出去的連結,我們會希望目前產品的 domain 連結都能轉成 LIFF連結。
既然 LINE LIFF 後台的 LIFF 與 Endpoint URL 設定幫我們做「第一次」的轉網址,接下來我們要實作「第二次」的轉網址,或者確切的說是同網站下的「轉路徑」。
第二次轉址:銜接在 LIFF URL 後的 Sub Path 與 Query String
按照 Endpoint URL 是否有載入 SDK 去區分,我們銜接 sub path 自訂路徑 與 query string 網址參數 的做法又略微不同。網站有載入 LIFF SDK 就會將 $自訂路徑 和 $網址參數 直接銜接在 Endpoint URL 後面,沒有載入就會透過 query string ?liff.state=
接在 Endpoint URL 後面:
有載入 LIFF SDK 初始化
https://liff.line.me/{$LIFF_ID}/{$自訂路徑}{$網址參數}
網址就會轉址為
Endpoint URL/{$自訂路徑}{$網址參數}
因為後台的 Endpoint URL 是設定 產品domain/liff登入頁
,所以其實是轉址到:
https://產品domain/liff登入頁/{$自訂路徑}{$網址參數}
沒有載入 LIFF SDK
https://liff.line.me/{$LIFF_ID}/{$自訂路徑}{$網址參數}
網址就會轉址為
Endpoint URL ?liff.state={$自訂路徑}{$網址參數}
因為後台的 Endpoint URL 是設定 https://產品domain/liff登入頁
,所以其實是轉址到:
https://產品domain/liff登入頁?liff.state={$自訂路徑}{$網址參數}
在 Endpoint URL /liff登入頁
擷取並銜接正確的路徑
為了讓 LIFF URL 轉址後的 Endpoint URL 網址
https://產品domain/liff登入頁/{$自訂路徑}{$網址參數}
還能再正確轉址到
https://產品domain/{$自訂路徑}{$網址參數}
我們需要到 /liff登入頁
對應的 React 元件內去撰寫轉址邏輯。
這邊就要按照有沒有載入 LIFF SDK 撰寫各自的跳轉邏輯:
有載入 LIFF SDK 初始化
示意程式碼如下:
const history = useHistory();
const { search } = useLocation();
const { path } = useParams();
const originalPath = path ? `/${path}${search}` : `/${search}`;
history.replace(originalPath);
沒有載入 LIFF SDK
我們要自己擷取 liff.state 的內容,再將網站轉過去,示意程式碼如下:
const originalPath = queryString.parse(search);
history.replace(
originalPath["liff.state"] ? originalPath["liff.state"] : "/"
);
最終 LIFF 跳轉順序
有載入 LIFF SDK 初始化
- 使用者在 LINE APP 點擊了 LIFF 連結
https://liff.line.me/${LIFF_ID}/路徑?參數
- 透過 LINE LIFF 後台設定的 Endpoint URL ,liff.line.me 會自動進行「第一次轉址」到目標網站
並且因為有使用 LIFF SDK,SDK 自動將/路徑?參數 接在網址後面。
https://產品domain/liff登入頁/路徑?參數
- 透過我們自行在
/liff登入頁
的實作,將/路徑?參數
銜接回產品 domain 並進行「第二次轉址」到目標路徑。
https://產品domain/路徑?參數
沒有載入 LIFF SDK 初始化
- 使用者在非 LINE 環境(手機瀏覽器、桌機瀏覽器)輸入了 LIFF 網址連結
https://liff.line.me/${LIFF_ID}/路徑?參數
- 透過 LINE LIFF 後台設定的 Endpoint URL ,liff.line.me 會自動進行「第一次轉址」到目標網站
由於未使用 LIFF SDK,liff.line.me 會自動將/路徑?參數 當成字串,接在網址後面的 ?liff.state query string。
https://產品domain/liff登入頁?liff.state=/路徑?參數
- 透過我們在
/liff登入頁
的實作,擷取 query string 的 liff.state 字串,將路徑與參數銜接回我們主網站產品 domain 網址進行「第二次轉址」到目標路徑。
https://產品domain/路徑?參數
限制:避免不了的 Loading Spinner
目前幾乎所有第三方廠商在 LINE LIFF 上的服務,如訂餐服務(ex: 快一點)、會員管理服務(ex: 路易莎黑卡),這些 LIFF 服務都會有個明顯的 Loading Spinner UI。
原因除了 Today 外的第三方廠商都一樣:
一個 LINE LIFF 服務對應一個 LIFF ID,而一個 LIFF ID 在後台可以設定的 Endpoint URL 進入點只有一個。由於後台的限制,為了讓使用者能正確轉址到他們網站上的真實路徑,開發者們需要自己做二次轉址動作。
再加上轉址前需要在 Client 判斷是否有載入 LINE LIFF SDK 初始化 (SDK 只能在 Client 執行),只要在 Client 處理邏輯再跳轉,使用者體感上就會出現時間差,這也是為什麼大家網站在跳轉過程都會塞一個 Loading Spinner UI。
困惑、待考證原理
比較特殊的是 LINE Today,當我們在 LINE APP 點擊 LINE Today 的版位,都是在「Today 服務的 Tab 一拉起來的瞬間就看得到內容」,且在 LINE APP 上分享 Today 連結時,會發現分享出的文章也liff.line.me。
由於 MINI APP 和 LIFF 都是使用同一套對外的「LIFF 連結規則」,無法確定他們是使用 MINI APP 和 LIFF。
LINE Today 可以當成規格外的例子賴看,畢竟他們才是 LINE APP 本家第一方服務,我們無從得知他們是否有特製什麼功能,亦或者他們有什麼特製功能或規則是沒有對外開放的。
另外,注意看 LINE APP 點擊 LINE Today 的版位拉起來的 Tab,還會發現 Tab 上方的 Loading Progress Bar 跑了「兩次」, Loading Progress Bar 跑了「兩次」乍看符合前面此篇轉址兩次的紀錄,然而「Today 服務的 Tab 一拉起來的瞬間就看得到內容」就讓人困惑,難道他們的 Endpoint URL 不只一個嗎?