前面總共花了十天十篇文章,利用 Messenger、LINE 兩個平台來介紹在訊息平台上各種常見的機器人功能,其中有一部分的功能是只在 Messenge 或是 LINE 其中一個平台上有,但即便如此,還是有許許多多的功能因為篇幅關係完全沒有介紹到。
筆者現在已經研究過六、七個以上的平台,我能說的就是平台之間的差異毫無疑論非常大,有些功能是 Messenger 特有的,例如:「Handover Protocol」、「Airline Template」,有些功能是 LINE 特有的,例如:「Richmenu」、「Imagemap」、「Flex」,或是在 Slack 或甚至 Telegram 上,訊息是可以發出之後再進行修改或刪除的。而且在這之上,每幾個月都依然可以看到功能的推陳出新,不管是互相抄襲又或者是獨一無二的功能。
再回到一些其他的管道,例如:Email、簡訊、語音助理或是論壇,我們能說這些各式各樣的管道會有怎樣的通用介面?
我想真正共有的介面就是只有文字。
語音助理該怎麼去使用圖片或是貼圖呢?把網址唸出來可能是一種 Fallback,但是體驗是好的嗎?我覺得不是。
還記得那種電話轉接的系統嗎?信用卡諮詢請按「1」、總機請按「9」...,這就是用語音的方式來呈現按鈕,一樣的問題是,這樣的體驗好嗎?
在實作跨平台機器人的時候,沒有固定的做法,端看你想要怎樣的體驗,這是我不太喜歡「Write Once, Run Anywhere」的原因。在設計上我們想要採用跟 React Native 一樣的哲學「Learn Once, Write Anywhere」,並試著讓程式碼的共用程度來到 80% 以上,並在各平台達到最好的體驗。
在這邊要把事件的判斷跟操作的 Side Effect 分開來看待。
如同前面所講的,文字算是所有平台共有的介面,就算是語音,標準的做法也是先做語音轉文字再來處理。再來另一個常見的就是按選單或按鈕觸發的 Payload,但就不能算是所有的介面都有。這兩個大概能涵蓋大約 99% 的一般互動,其餘才是傳圖、貼圖、傳檔案、傳地點等等。
所以一般的策略是先把文字跟 Payload 處理起來,其他可以依照平台去處理,例如發現對方在 LINE 送貼圖來,就也送貼圖回去:
if (context.platform === 'line' || context.event.isSticker) {
await context.sendSticker({
packageId: '11537',
stickerId: '52002744',
});
};
其它主要的文字等等當然還是進到你的關鍵字、正規表達式、ML 去處理囉。
那至於機器人已經認清楚 Event 了,並準備要用某種方式回應了,最差的情況就是用 context.sendText
來回應,即便在 Console 或是語音的情境也能接收。但若要做到「漸進增強」,或是依照平台做最佳化,那一樣可以做類似的事:
module.exports = async function App(context) {
if (context.platform === 'messenger') {
await context.sendButtonTemplate(/* ...省略 */);
} else if (context.platform === 'line') {
await context.sendFlex(/* ...省略 */);
} else {
await context.sendText(/* ...省略 */);
}
};
上面的範例在 Messenger 時使用 Button Template、在 LINE 使用 Flex Message,在其他狀況則是使用純文字。
這樣應該就知道怎麼處理五花八門的平台功能了吧。就如同在開發 iOS 跟 Android 時,要把兩個平台的功能、效能、設計風格做到最好,就不得不做平台最佳化。
在實作跨平台機器人時,我們基本上也是必須學習、採用在做網頁時常見的「漸進增強」或是「優雅降級」的策略,來思考讓功能更強的平台使用體驗更好的功能,並讓某些平台不能支援的功能找到能接受的 Fallback 方式。