文末福利:下載《小程式大世界》電子書。
在 2019 年,阿里巴巴文娛的淘票票幾乎涉足了當時市面上所有的小程式,其中在不少平臺上,我們是阿里第一批吃螃蟹的技術團隊。回顧過往,我們做過很多嘗試,也踩過很多坑。
我們特別整理了支付寶小程式、百度小程式、位元組跳動小程式、快應用的開發經驗,希望為你帶來啟發。
一 支付寶小程式
支付寶內的淘票票使用者主要是以購票為主,工具屬性比較明顯。淘票票入口眾多,均引導跳轉到小程式,引導使用者在小程式內進行購票、娛樂消費、收藏、新增到首頁/桌面、分享等行為。
淘票票支付寶小程式,經歷了近一年的起步開發,以及一年多的版本迭代,業務開發涵蓋了購票、視訊、資訊、社群等多個場景。
1 小程式開發
1) 在核心業務中慎用 web-view
實際專案線上執行情況及使用者反饋表明:web-view 初始化較慢、易受網路干擾、效能差(對比離線包及普通 H5 頁面)、問題較多,建議不要在核心業務中使用 web-view 進行承載。
2) 自有城市體系與支付寶城市元件的適配技巧
由於支付寶的城市元件是基於自身城市體系的,淘票票擁有獨立的城市體系,所以需要城市選擇元件適配不同城市體系的場景。經過幾輪推動迭代,淘票票線上已使用城市選擇元件,已支援複寫當前定位城市、歷史訪問城市、熱門城市、城市列表資訊等。使用my.chooseCity、my.onLocatedComplete、my.setLocatedCity 三個 JSAPI 可實現對應效果。
3) 如何實現沉浸式效果(透明導航欄)?
首先在 page.json 配置 “transparentTitle” 為 “auto” 屬性,開啟沉浸式佈局。其次,頁面佈局適配沉浸式頂部透明導航欄即可,通過 my.getSystemInfo 獲取 titleBarHeight 及 statusBarHeight 可計算出頂部透明高度。注意:Android 5.0 以下由於不支援沉浸式狀態列,所以頁面會從狀態列下開始佈局。
4) 小程式 tabBar 換膚、紅點
主要使用的JSAPI及event:my.setTabBarStyle、my.setTabBarItem、page.onTabItemTap,引數參考官方文件即可。注意事項如下:
小程式觸發 relaunch 時,tabBar 的樣式會被清除,需要再次設定,目前建議在 app.onShow 裡多次觸發設定邏輯。儘量使用本地圖片,線上圖片有個下載的過程,體驗不太好,且弱網下圖片載入可能失敗。my.setTabBarItem 的引數每一項均需要賦值,否則 Android 可能會報 “invalid parameter”。2 小程式開發注意事項
不要使用 tnpm 安裝依賴,tnpm 軟連線目前支援有問題。devDependencies 和 dependencies 需要分開,將 devDependencies 移到專案程式碼外層,否則會額外增加包大小。設定 transparent/pullRefresh 等 window 配置時,跳轉別的頁面會被繼承,需要在 app.json 初始化此類配置資訊規避。web-view 裡面的頁面會失去下拉重新整理、resume 等特性。Android 低版本不支援 sticky 屬性。某個值控制 dom 是否渲染,下次更新時此值若為 undefined 時不會銷燬掉會被忽略掉。window.atob、window.btoa 需要第三方庫來替代。lodash 某些方法不能直接使用,因為小程式構建時無 global 物件。3 小程式監控
使用阿里雲的 ARMS 平臺,參考官方文件接入即可。
優點:有實時大盤,排查使用者日誌方便,上報更自由、豐富。缺點:有接入成本、需要開發,增加包大小,且要收費。4 小程式許可權
小程式有許可權管控,無論是申請 JSAPI 許可權還是 H5 域名配置,都是需要打新的包上傳才能生效。
二 百度小程式
1 背景
以微信小程式為藍本的百度小程式,也同樣具備相似的商業定位。依賴百度這樣的老牌搜尋門戶,百度小程式更加偏向目的性強的搜尋熱詞進行小程式的關聯調起和互動,這也是百度小程式和其他小程式的區別。
由此,我們在 2018 年底進行了百度小程式的開發工作,由於在前期積累了小程式開發經驗,百度小程式的開發更加的平穩和快速,不到一個月就上線運營了。
2 應用場景
百度小程式入口:
三種入口:百度App搜尋關聯、百度貼吧關聯、其他百度生態搜尋關聯。
3 開發實戰
下面是淘票票百度小程式開發過程中遇到的坑和總結:
1)基礎開發
第一塊:HTML。構建頁面框架:使用 xxx.swan 檔案進行頁面元素框架的搭建,具有獨特的 HTML 標籤如 view,scroll-view 等。第二塊:CSS。管理頁面樣式:使用 xxx.css 檔案進行頁面樣式的管理,基本的 CSS 的樣式都大部分支援。第三塊:JS。編寫頁面邏輯:使用 xxx.js 檔案進行頁面邏輯的書寫,小程式具有其獨特的生命週期管理方法。第四塊:JSON。元件註冊:百度小程式支援通過元件的方式進行頁面的搭建,通過在 xxx.json 中註冊元件供頁面使用。2)template 模板使用
與其他的小程式相同,百度小程式也提供了模板 template 的能力,使用模板可以提高工程化和程式碼可維護性,開發者可以在模板中設計程式碼片段,向外暴露介面注入外界變數之後,可以在合適的時機去使用該程式碼片段。
但是在百度小程式使用 template 使用時,需要注意傳遞資料時需要使用 {{{ }}} 三層花括號包裹物件,否則資料注入時會出現異常。
百度小程式的 template 的使用:
<template is="xxx" data="{{{item}}}"/><template is="xxx" data="{{item}}"/>3)元件屬性的 observer 使用
在使用元件(Component)是大概率會使用到屬性的 observer 方法,當屬性被改變時會執行屬性對應的 observer 方法,此處需要注意在使用 observer 方法時,避免使用下劃線開頭的方法名,可能會造成 observer 方法的迴圈呼叫問題。
或者當發現 properties 中的 observer 方法被迴圈呼叫時,檢查一下 observer 繫結的方法是否有下劃線。方法命名移除下劃線,大概率可以解決迴圈呼叫問題。
會出現 observer 迴圈呼叫的情況:
isShowLoadMore: { type: Boolean, value: false, observer: '_isshowChange' },推薦的寫法:
isShowLoadMore: { type: Boolean, value: false, observer: 'isshowChange' },4)scroll-view 的使用
在使用 scroll-view 的開發過程中,對存在多個可滑動區域的頁面且其中一個滑動區域為 fixed 樣式時,iOS 機型會偶現 scroll-view 空白的問題。
可能存在異常的頁面佈局如下:
<view class='頭部元件' style='position:fixed'/><scroll-view class='可滑動區域1' style='position:fixed' /><view class='可滑動區域2' />其中 “可滑動區域 2” 為依賴內容撐開的頁面 View,當內容到達一定長度時,頁面 View 會提供滑動能力。如果使用上述寫法可能會出現 scroll-view 空白的問題。
推薦的寫法:
<view class='頭部元件' style='position:fixed'/><scroll-view class='可滑動區域1' style='position:fixed;height:44px' /><scroll-view class='可滑動區域2' style='height:80vh' />5)小程式 DSL 頁與 WebView 頁的登入流程
小程式的頁面實現方式可以分為兩種:一種為小程式原生的頁面;另外一種是使用 WebView 元件,將 H5 頁面展示在小程式中。處理兩種頁面的登入時一般是先進行 DSL 頁登入(小程式原生頁面),完成 DSL 頁登入後,再進行 H5 容器頁的登入。
a) DSL 頁登入
先進行小程式的登入授權,獲取到小程式的登入憑證,拿著登入憑證去自己的業務服務端獲取真實的小程式登入資訊,當開發者完成上述流程之後,將登入態資訊加密後儲存在本地。下次進行需要登入校驗的頁面時,進行本地登入資訊的登入校驗,則 DSL 頁的登入流程就完成了。
b) WebView 容器頁登入
由於百度小程式無法操作到 WebView 容器的 cookie 資訊,所以在 WebView 容器頁進行登入時,勢必要進行一次從服務端獲取登入 cookie 的過程。目前可以在進入需要登入校驗登入的 WebView 容器頁之前,先發起獲取 cookie 的服務端請求,服務端處理好使用者登入資訊校驗之後就可以提供一個同步 cookie 的專用頁面。當介面返回連結之後,小程式的 WebView 容器需要做的就是訪問這條連結將服務端返回的 cookie 同步到 WebView 容器中,這樣 WebView 容器就具備了可供校驗的登入資訊。
完成上述頁面的登入操作之後,小程式登入流程就結束了。
4 百度小程式總結
本文著重描述的是開發過程中大概率會遇到的問題和解決方案,最好結合官方文件一起檢視。
三 位元組跳動小程式
1 背景
位元組跳動小程式是基於位元組跳動全產品矩陣開發, 與圖文、視訊等場景有著天然的搭配性,帶動小程式分發,由內容為小程式帶量以及裂變。作為一個大流量且高度活躍的平臺,具有很大使用者增量挖掘空間。
2 應用場景
抖音的四個主要場景:
小視訊掛載 企業號主頁 搜尋展示 留存入口
廣告投放
3 基礎介紹
位元組跳動小程式基本開發思路類似於前端開發,並增強呼叫大量端能力,效能體驗優於普通 Web 。上層架構基於 JS 開發,可以輔助開發者進行良好得開發。框架結構和開放式類似於支付寶小程式、微信小程式和百度小程式。
目錄結構:主要分為以下幾類的檔案:
.json 為字尾的 JSON 配置檔案,這個檔案配置了小程式所有頁面的路徑和介面展現樣式等。.ttml 結尾的模板檔案,用來描述當前這個頁面的檔案結構,類似於網頁中的 HTML 檔案。.ttss 結尾的樣式檔案,描述頁面樣式,類似於網頁中的 CSS 檔案。.js 結尾的 JS 檔案,處理這個頁面和使用者的互動。目錄結構
四 快應用卡片
1 概述
當前,基於超級 APP 推出的各種小程式,對手機廠商的分發能力及話語權有明顯削弱趨勢。因此國內各手機廠商在推出快應用後,也逐漸對外開放手機負一屏的能力,為快應用及其他服務提供直接的入口。
2 卡片型別
快應用的卡片型別可以分為:應用型別的卡片、服務型別的卡片和其它型別的卡片。
應用型別的卡片:是使用者訂閱的一種卡片,內容相對固定。服務型別的卡片:針對使用者關心資料的狀態,內容實時變更。其它型別的卡片:自定義卡片,根據實現對應內容展示及跳轉。3 應用卡片的具體接入
卡片的開發基於快應用,所使用的 API 是快應用的子集,部分 API 不能在卡片中使用。目前已知的 vivo,OPPO,NUBIA 都需要卡片的開發不依賴主 rpk,也就是需要保證卡片能脫離主 rpk 獨立渲染,為保證卡片的獨立渲染,不能使用 this.$app 相關物件及檔案 app.ux 中宣告的工具類或生成的物件。
1)卡片的初始化配置
a) 配置檔案
所有的卡片都需要和快應用中宣告頁面一樣在 manifest.json 中宣告。具體是在 router.widgets 中配置,各廠商之間有部分差異,但差異不大。
b) 卡片配置檔案注意事項
widgets 中配置的 key 值請使用路徑名字,如果路徑為兩級(例:/A/B),則 key 值配置為 "A/B",且該值最終對應到廠商後臺上傳卡片時填入的卡片路徑,基於此廠商才能正確解析到上傳到聯盟上統一的快應用包中對應的卡片。卡片的屬性 features 中需要宣告該卡片會用到的系統 API,這些 API 在外層應用的 features 中已經宣告過,此處需要再次宣告,否則不能使用。2)應用型別卡片接入(以 vivo 為例)
負一屏卡片線上效果圖
a) 卡片的宣告
在 manifest.json 中的除了上面提到的配置之外,對於卡片需要注意卡片屬性中的以下欄位:
params 欄位用來配置卡片更為詳細的引數,及特有的支援引數,需要按照文件進行配置。targetManufactorys 為對應廠商適配標明該卡片匹配的廠商,具體參看文件。b) 卡片的開發的不同點(所使用的 API 及元件為其子集具體參看官方文件)
vivo 卡片是單獨工程,不能配置在快應用工程中,需要另外建立新的工程。對應包打出也需要單獨配置和主快應用不相同,需要用到 vivo 給出的相關工具。卡片有單獨設定主題的功能。卡片有摺疊功能。卡片視覺稿由內容提供方給出。卡片開發只需開發內容區域,title 區域無需開發(由 vivo 負一屏容器完成繪製)同時意味著下半部分的圓角需要自己繪製。上傳卡片包時需要提供對應的 icon。c) 卡片除錯
卡片除錯需要使用 vivo 方提供的工具打出來的 rpk 檔案,同時需要使用 vivo 方提供的專用核心及容器,具體按照文件執行即可。
d) 卡片提交
首先需要完成自測,自測之後需要使用 vivo 提供的專用打包工具,打包之後到 Jovi 後臺地址提交,同時需要提供一個應用圖示。
4 負一屏服務型別卡接入
以下以 OPPO 服務卡接入為例:
觸發場景:使用者在淘票票快應用中購票之後,在影片上映前的固定時間內觸發該卡片內容展示,進而提醒使用者取票,即訊息觸發場景。
OPPO 負一屏卡片線上效果圖
1)OPPO服務卡卡片的宣告
在 manifest.json 中的 router 欄位中新增 widgets 欄位,並在該欄位中新增對應的配置,與 OPPO 應用卡片完全相同。
2) 卡片開發
OPPO 服務卡開發涉及使用者關心資料狀態改變觸發卡片的場景,因此整體需要解決以下幾個問題:首先是觸發時機問題,然後是要確認觸發的卡片 ID,還要解決要觸發哪一個 OPPO 使用者。
3)OPPO 服務卡整體開發流程
前提:要開通 OPPO 賬號服務,保證在快應用中能夠拿到 OPPO 當前登入的使用者的授權碼。
a) 賬號繫結,即 OPPO 賬號和快應用賬號的繫結
賬號繫結的入口:該入口由 OPPO 負一屏容器統一提供,位置如下圖左:
OPPO 服務卡繫結入口及自定義繫結頁面
該入口對應一個快應用內的繫結頁面。
b) 繫結頁面開發,該頁面是快應用頁面,主要提供繫結功能
作用是讓內容商服務端知道自己的賬號和 OPPO 測的對應關係,及換取發訊息到 OPPO 端時所需要的 TOKEN 值。
c) 觸發對應 OPPO 使用者負一屏的卡片
內容服務商在使用者關心資料變更時,觸發推送訊息到 OPPO 服務端,該訊息按 OPPO 文件約定,帶上對應的 TOKEN 值,要觸發的卡片 ID,訊息內容,要觸發的時機及時長,OPPO 服務端會根據該 TOKEN 找到對應的使用者下發訊息,並在需要的時機拉起對應 ID 的卡片。
d) 卡片消失
由傳送訊息中定義的卡片時長決定,展示時間到點後,負一屏容器會自動移除該卡片。
e) 除錯
首先,需要 OPPO 服務端參與其次,需要 OPPO 提供負一屏開發環境版本,以保證 OPPO 服務端日常環境的資料能夠到達。再次,需要提供初步測試完成包含服務卡的 rpk 到 OPPO 側,把該 rpk 配置到 OPPO 對應的環境。f) 提交市場
測試完成可以在 OPPO 後臺提交該卡片,同時同步正式生成的卡片標示到自己的服務端用來推送訊息使用。
g) 綜上涉及各端的開發工作如下:
首先,涉及服務端賬號繫結開發,TOKEN 重新整理維護,觸發的訊息推送到 OPPO。其次,涉及前端的服務卡片開發以及繫結頁面開發。涉及其他:OPPO 賬號服務開通。5 踩坑記錄
負一屏的 UA 和快應用中不同如果有與 UA 相關的配置需要注意。對於除錯時更新了 rpk 之後,實際開啟對應更改沒有體現時,可以嘗試清除對應卡片容器的 cache,同時保證該容器有相應的讀取儲存的許可權。對於同一個業務,由於各廠商適配不同及平臺不同,需要多處程式碼編寫,但基本業務邏輯基本一致,唯一不同是 UI 展示,所以在一開始還是需要抽離資料邏輯,不同廠商給不一樣的 UI 展示即可。四 淘票票小程式構建演進
我們做了很多的小程式,對多端同構也做了一些嘗試。
1 從一端到多端
1) 起步:小程式原生開發
這種開發方式輕快,但是同時也暴露出了很多問題:
包體積很難控制。原生 DSL 沒有任何複用性,並且需要重新學習。無法使用 NPM,一些很常用的社群包,團隊基礎工具鏈無法使用。機型相容性不好,沒有 babel 支援。2) 摸索:兩個端,一套程式碼?
在開發百度小程式的過程中,吸取了第一次的教訓,加入了 webpack 來做一層編譯,一是解決了包引入問題,二是加入了 babel 外掛,解決 JS 相容性問題,開啟 CommonChunk 外掛,解決包大小問題。
脫離了刀耕火種,開發效率明顯提升,但是還不夠好,檢視層還是兩份,而且以後每新增一端就要新拉出來一份。
3) 優化:走向社群,跨多端
2019 年進軍微信小程式,再次看市面上的框架,發展的很快,同時也注意到跨端開發這個需求點,選擇了 Taro 作為主力框架。這種框架橫評就不展開了,市面上很多,簡單說幾個選擇 Taro 的原因:社群相對活躍、支援漸進式切換、TS、react like。
a) 平滑遷移
Taro 支援漸進式切換,也就是 Taro 和 DSL 混寫的能力,所以遷移成本可以接受。我們先將首頁 Taro 化,後面慢慢迭代將所有的頁面都切換為了 Taro,這裡值得一提的是,Taro 的跨端差異化處理和我們之前的處理思路一樣,因此 Util 遷移起來幾乎 0 成本,成本主要集中在檢視層。
b) 好處是什麼,缺點在哪裡
使用 Taro 的好處是解決了我們之前遇到的主要問題,是一個一攬子解決方案。
同時這種上層框架在擴充套件新端時成本低,機動性很高,框架提供了新平臺包,適配成本低。
當然也遇到了一些新的問題,比較嚴重的是除錯,因為程式碼被轉譯過一次,同時不支援 Soucemap,導致 debug 時體驗很差。
2 多端差異
多端必然會有一些差異,業務的差別、端上 API 的差異等,比如微信上的分享能力,抖音上的抖音拍攝器,百度的 feed 流等。最終落在業務上,差別可以分為三部分,輸出不同的頁面、不使用同的元件(有的端使用原生元件),細到不同的邏輯。
1) 輸出不同的頁面
在使用 Taro 時發現不支援,想到可以使用 babel-preval 來編譯時輸出頁面配置,這樣包體積也不會受影響,最後我們也反哺回社群。
使用不同的元件,不同的邏輯。根據端上不同的元件我們使用的最多的是多型模式,底層元件對外暴露相同的介面,端上呼叫時不需要考慮端上的差異,在 import 層會根據不同的端來引入不同的具體元件。
2) 端上邏輯
如果是一些簡單的邏輯差異,可以直接使用環境變數來做控制,走不同的邏輯。這種方式針對小一些的邏輯還可以,不過這種程式碼一多,就不容易維護。
3) 針對維護性的建議
這裡推薦幾種維護性比較強的差異處理方式:
設計元件時外掛化:比如路由,不同端在跳轉前後需要有一些不同的操作,實現了外掛化後,每一個端只需掛載不同的外掛即可。配置抽離:針對一些端上不同的配置,比如一些文案、固定內容等,可以抽離到一個統一的地方維護,可以少很多 ifelse 邏輯。用好函式 hook:針對不同端相同的邏輯放在函式中,有差異的邏輯可以單拆函式作為 beforeHook 和 afterHook。3 專案維護策略
專案輸出多端後,每次改動迴歸就成為一個比較重要的問題,如何保證自己的程式碼不會再其它端上出問題?每次改一個小程式其他都要立即迴歸嗎?如何快速整理其他端的改動?下面針對多端專案的維護總結了一些經驗。
1) 單測
針對核心邏輯編寫測試,unit test 和 snapshot test,我們內部維護了一個針對端上 API 的 mock 測試庫,整個測試可以在 node 環境中執行,保證執行效率。
2) Commit 規範
指定一個 commit message 規範,可一眼看出你在做什麼,在改哪一個端,以及後面迴歸策略時用到。
3) git-hook
使用 githook 能保證上面的規範能夠真正的遵循,保證每次提交的品質。pre-commit 時跑一下 Eslint,然後校驗一下 commit-message 是否符合規則,最後 push 時會跑一次整體的測試。
4) 多端的迴歸策略
沒有做 E2E 的主要原因是小程式限制,case 編寫難度比較大,並且維護性低,無法自動化。
目前我們是人工迴歸的,如何保證程式碼不會再其他端上出問題?難道每一次改一個小程式其它都要立即迴歸嗎?回答下這兩個問題,編寫程式碼時考慮影響面,提交時提供足夠的改動資訊,合併時主要測當前端即可,不需要回歸所有端。等另一個端需要釋出時,拉出版本的 commit-message,然後梳理出變更範圍,在該端做迴歸即可。這樣做減少對測試的集中消耗,保障品質。
4 展望
以上是我們對跨端專案的經驗總結,包含技術演進歷史以及差異控制策略。跨端專案的難點就是處理差異。
端上能力的參差不齊、業務針對不同場景的定製,一旦控制不好,整個人專案的維護性就會大大降低。業務方面要思考清楚,不同的端,是相似的更多,還是差異多。框架方面,最近看到有開發者已經給 W3C 提小程式的白皮書了,總體朝著良性方向發展,這是一個好的開始,期待能夠標準化小程式框架。