微信小程序兼容性問題

本文我們來談?wù)勎⑿判〕绦蛳到y(tǒng)兼容性的那些坑。

微信小程序兼容性問題

微信小程序發(fā)布一周多了,兼容性問題塘装,特別是 Android 平臺(tái)兼容性問題特別嚴(yán)重急迂。據(jù)我觀察,好多小程序掉到兼容性的坑里蹦肴。掉坑里不要緊僚碎,更讓人捉急的是,從坑里爬上來的時(shí)候阴幌,手剛抓到坑沿勺阐,又被微信官方踩到(緊急修復(fù)兼容性的版本沒審核通過,被微信打回重審)矛双,再次跌落坑底渊抽,然后眼睜睜地看著后臺(tái)用戶在破口大罵“什么東西都沒有啊~,什么破小程序”议忽。

微信小程序的兼容性問題除了微信本身的 Bug 外懒闷,大部分是目標(biāo)平臺(tái)對(duì) JavaScript 標(biāo)準(zhǔn)庫支持程度不同造成的。

微信本身的 Bug 引起的

微信本身的 Bug 引發(fā)的兼容性問題有個(gè)現(xiàn)成的例子徙瓶,就是 wx.request() 返回的狀態(tài)碼 res.statusCode 的值在 iOS 下是 int 型數(shù)據(jù)毛雇,而在 Android 6.0.1 上卻是 String 型數(shù)據(jù)。如果你判斷服務(wù)器的返回狀態(tài)碼方法不當(dāng)侦镇,可能就踩到坑里了灵疮。

wx.request({
    url: 'http://api.example.com',
    success: function (res) {
        if (res.statusCode === 200) {
            // success
        } else {
            // server failure
        }
    }
})

上述代碼就踩坑了,正確的做法是使用 == 而不是使用 === 來判斷壳繁。另外一個(gè)更規(guī)范的方法是使用 parseInt(res.statusCode) === 200 來實(shí)現(xiàn)震捣。

Javascript 標(biāo)準(zhǔn)庫兼容性問題

比如 Array.find() 方法在 iOS 10.2/Android 7.0 上完美支持,但在 Android 6.0.1 上卻不支持闹炉。如果代碼里用到了這個(gè)接口蒿赢,就會(huì)導(dǎo)致在 Android 6.0.1 上無法正常工作。通過對(duì)比發(fā)現(xiàn)渣触,這類接口不支持的個(gè)數(shù)還是比較多的羡棵。特別是 Android 平臺(tái)版本眾多,兼容性問題就更嚴(yán)重嗅钻,可能一不小小心就掉到坑里皂冰。

解決方法

微信本身 Bug 只能繞過去,但對(duì) JavaScript 引擎的兼容性养篓,可以有更優(yōu)雅的解決方法秃流。比如,我們可以打補(bǔ)丁柳弄,使用 polyfill 來實(shí)現(xiàn)這些不支持的標(biāo)準(zhǔn)庫方法舶胀。比如,修復(fù) Android 6.0.1 平臺(tái)不支持 String.startsWith() 的問題,可以使用下面的 polyfill 代碼:

if (!String.prototype.startsWith) {
    console.warn('define polyfill for Array.prototype.startsWith');
    String.prototype.startsWith = function (searchString, position) {
      position = position || 0;
      return this.substr(position, searchString.length) === searchString;
  };
}

推而廣之嚣伐,我們可以把平臺(tái)不支持的標(biāo)準(zhǔn)庫方法糖赔,使用 polyfill 實(shí)現(xiàn)。這就是 minapp-polyfill 這個(gè)項(xiàng)目的目的纤控。

使用方法很簡(jiǎn)單挂捻,把 minapp-polyfill 項(xiàng)目里的 polyfill.js 拷貝到小程序源碼目錄下,在需要打補(bǔ)丁的 JavaScript 源文件頭部引入如下代碼即可:

import 'path/to/polyfill.js'

目前這個(gè)項(xiàng)目只是搭了個(gè)骨架船万,還有很多方法需要實(shí)現(xiàn)刻撒。PRs is welcome。

各個(gè)平臺(tái)對(duì) JavaScript 標(biāo)準(zhǔn)庫支持情況

條件限制耿导,這里統(tǒng)計(jì)了四個(gè)平臺(tái)對(duì) JavaScript 標(biāo)準(zhǔn)庫的支持情況声怔,分別是 iOS 10.2, Android 6.0.1, Android 7.0, 微信開發(fā)者工具,具體數(shù)據(jù)如下:

Component.apiName iOS 10.2 Android 6.0.1 Android 7.0 devtool
Array.toString YES YES YES YES
Array.values YES N/A YES N/A
Array.toLocaleString YES YES YES YES
Array.concat YES YES YES YES
Array.fill YES N/A YES YES
Array.join YES YES YES YES
Array.pop YES YES YES YES
Array.push YES YES YES YES
Array.reverse YES YES YES YES
Array.shift YES YES YES YES
Array.slice YES YES YES YES
Array.sort YES YES YES YES
Array.splice YES YES YES YES
Array.unshift YES YES YES YES
Array.every YES YES YES YES
Array.forEach YES YES YES YES
Array.some YES YES YES YES
Array.indexOf YES YES YES YES
Array.lastIndexOf YES YES YES YES
Array.filter YES YES YES YES
Array.reduce YES YES YES YES
Array.reduceRight YES YES YES YES
Array.map YES YES YES YES
Array.entries YES N/A YES YES
Array.keys YES N/A YES YES
Array.find YES N/A YES YES
Array.findIndex YES N/A YES YES
Array.includes YES N/A N/A YES
Array.copyWithin YES N/A YES YES
Array.constructor YES YES YES YES
Buffer N/A N/A N/A N/A
DataView.getInt8 YES YES YES YES
DataView.getUint8 YES YES YES YES
DataView.getInt16 YES YES YES YES
DataView.getUint16 YES YES YES YES
DataView.getInt32 YES YES YES YES
DataView.getUint32 YES YES YES YES
DataView.getFloat32 YES YES YES YES
DataView.getFloat64 YES YES YES YES
DataView.setInt8 YES YES YES YES
DataView.setUint8 YES YES YES YES
DataView.setInt16 YES YES YES YES
DataView.setUint16 YES YES YES YES
DataView.setInt32 YES YES YES YES
DataView.setUint32 YES YES YES YES
DataView.setFloat32 YES YES YES YES
DataView.setFloat64 YES YES YES YES
DataView.constructor YES YES YES YES
Date.toString YES YES YES YES
Date.toISOString YES YES YES YES
Date.toDateString YES YES YES YES
Date.toTimeString YES YES YES YES
Date.toLocaleString YES YES YES YES
Date.toLocaleDateString YES YES YES YES
Date.toLocaleTimeString YES YES YES YES
Date.valueOf YES YES YES YES
Date.getTime YES YES YES YES
Date.getFullYear YES YES YES YES
Date.getUTCFullYear YES YES YES YES
Date.getMonth YES YES YES YES
Date.getUTCMonth YES YES YES YES
Date.getDate YES YES YES YES
Date.getUTCDate YES YES YES YES
Date.getDay YES YES YES YES
Date.getUTCDay YES YES YES YES
Date.getHours YES YES YES YES
Date.getUTCHours YES YES YES YES
Date.getMinutes YES YES YES YES
Date.getUTCMinutes YES YES YES YES
Date.getSeconds YES YES YES YES
Date.getUTCSeconds YES YES YES YES
Date.getMilliseconds YES YES YES YES
Date.getUTCMilliseconds YES YES YES YES
Date.getTimezoneOffset YES YES YES YES
Date.setTime YES YES YES YES
Date.setMilliseconds YES YES YES YES
Date.setUTCMilliseconds YES YES YES YES
Date.setSeconds YES YES YES YES
Date.setUTCSeconds YES YES YES YES
Date.setMinutes YES YES YES YES
Date.setUTCMinutes YES YES YES YES
Date.setHours YES YES YES YES
Date.setUTCHours YES YES YES YES
Date.setDate YES YES YES YES
Date.setUTCDate YES YES YES YES
Date.setMonth YES YES YES YES
Date.setUTCMonth YES YES YES YES
Date.setFullYear YES YES YES YES
Date.setUTCFullYear YES YES YES YES
Date.setYear YES YES YES YES
Date.getYear YES YES YES YES
Date.toJSON YES YES YES YES
Date.toUTCString YES YES YES YES
Date.toGMTString YES YES YES YES
Date.constructor YES YES YES YES
Error.toString YES YES YES YES
Error.constructor YES YES YES YES
Float32Array.constructor YES YES YES YES
Float64Array.constructor YES YES YES YES
Function.constructor YES YES YES YES
Int16Array.constructor YES YES YES YES
Int32Array.constructor YES YES YES YES
Int8Array.constructor YES YES YES YES
Map.forEach YES N/A YES YES
Map.clear YES N/A YES YES
Map.delete YES N/A YES YES
Map.get YES N/A YES YES
Map.has YES N/A YES YES
Map.set YES N/A YES YES
Map.keys YES N/A YES YES
Map.values YES N/A YES YES
Map.entries YES N/A YES YES
Map.constructor YES N/A YES YES
Math.abs YES YES YES YES
Math.acos YES YES YES YES
Math.asin YES YES YES YES
Math.atan YES YES YES YES
Math.acosh YES N/A YES YES
Math.asinh YES N/A YES YES
Math.atanh YES N/A YES YES
Math.atan2 YES YES YES YES
Math.cbrt YES N/A YES YES
Math.ceil YES YES YES YES
Math.clz32 YES N/A YES YES
Math.cos YES YES YES YES
Math.cosh YES N/A YES YES
Math.exp YES YES YES YES
Math.expm1 YES N/A YES YES
Math.floor YES YES YES YES
Math.fround YES N/A YES YES
Math.hypot YES N/A YES YES
Math.log YES YES YES YES
Math.log10 YES N/A YES YES
Math.log1p YES N/A YES YES
Math.log2 YES N/A YES YES
Math.max YES YES YES YES
Math.min YES YES YES YES
Math.pow YES YES YES YES
Math.random YES YES YES YES
Math.round YES YES YES YES
Math.sign YES N/A YES YES
Math.sin YES YES YES YES
Math.sinh YES N/A YES YES
Math.sqrt YES YES YES YES
Math.tan YES YES YES YES
Math.tanh YES N/A YES YES
Math.trunc YES N/A YES YES
Math.imul YES YES YES YES
Object.toString YES YES YES YES
Object.toLocaleString YES YES YES YES
Object.valueOf YES YES YES YES
Object.hasOwnProperty YES YES YES YES
Object.propertyIsEnumerable YES YES YES YES
Object.isPrototypeOf YES YES YES YES
Object._defineGetter_ YES YES YES YES
Object._defineSetter_ YES YES YES YES
Object._lookupGetter_ YES YES YES YES
Object._lookupSetter_ YES YES YES YES
Object.constructor YES YES YES YES
Promise.then YES YES YES YES
Promise.catch YES YES YES YES
Promise.constructor YES YES YES YES
RegExp.compile YES YES YES YES
RegExp.exec YES YES YES YES
RegExp.toString YES YES YES YES
RegExp.test YES YES YES YES
RegExp.constructor YES YES YES YES
Set.forEach YES N/A YES YES
Set.add YES N/A YES YES
Set.clear YES N/A YES YES
Set.delete YES N/A YES YES
Set.has YES N/A YES YES
Set.entries YES N/A YES YES
Set.values YES N/A YES YES
Set.keys YES N/A YES YES
Set.constructor YES N/A YES YES
String.match YES YES YES YES
String.padStart YES N/A N/A N/A
String.padEnd YES N/A N/A N/A
String.repeat YES N/A YES YES
String.replace YES YES YES YES
String.search YES YES YES YES
String.split YES YES YES YES
String.toString YES YES YES YES
String.valueOf YES YES YES YES
String.charAt YES YES YES YES
String.charCodeAt YES YES YES YES
String.codePointAt YES N/A YES YES
String.concat YES YES YES YES
String.indexOf YES YES YES YES
String.lastIndexOf YES YES YES YES
String.slice YES YES YES YES
String.substr YES YES YES YES
String.substring YES YES YES YES
String.toLowerCase YES YES YES YES
String.toUpperCase YES YES YES YES
String.localeCompare YES YES YES YES
String.toLocaleLowerCase YES YES YES YES
String.toLocaleUpperCase YES YES YES YES
String.big YES YES YES YES
String.small YES YES YES YES
String.blink YES YES YES YES
String.bold YES YES YES YES
String.fixed YES YES YES YES
String.italics YES YES YES YES
String.strike YES YES YES YES
String.sub YES YES YES YES
String.sup YES YES YES YES
String.fontcolor YES YES YES YES
String.fontsize YES YES YES YES
String.anchor YES YES YES YES
String.link YES YES YES YES
String.trim YES YES YES YES
String.trimLeft YES YES YES YES
String.trimRight YES YES YES YES
String.startsWith YES N/A YES YES
String.endsWith YES N/A YES YES
String.includes YES N/A YES YES
String.normalize YES YES YES YES
String.constructor YES YES YES YES
Symbol.toString YES N/A YES YES
Symbol.valueOf YES N/A N/A YES
Symbol.constructor YES N/A YES YES
TypeError.toString YES N/A N/A YES
TypeError.constructor YES YES YES YES
Uint16Array.constructor YES YES YES YES
Uint32Array.constructor YES YES YES YES
Uint8Array.constructor YES YES YES YES
Uint8ClampedArray.constructor YES YES YES YES
WeakMap.delete YES YES YES YES
WeakMap.get YES YES YES YES
WeakMap.has YES YES YES YES
WeakMap.set YES YES YES YES
WeakMap.constructor YES YES YES YES

N/A 表示這個(gè)標(biāo)準(zhǔn)庫方法在平臺(tái)上不支持

Q: 這些數(shù)據(jù)是怎么來的舱呻,靠譜嗎醋火?
A: 這些數(shù)據(jù)是在真實(shí)小程序運(yùn)行環(huán)境下運(yùn)行,然后把 API 支持情況發(fā)送到服務(wù)器后臺(tái)箱吕,再寫個(gè)腳本把數(shù)據(jù)整理匯總后得來的芥驳。

Q: 其他平臺(tái),比如 Android 5.0 的支持情況怎么樣茬高?
A: 由于條件限制兆旬,手上沒有 Android 5.0 的手機(jī),有愿意配合收集數(shù)據(jù)的怎栽,私信留言丽猬。配合的方法很簡(jiǎn)單,用指定型號(hào)的手機(jī)打開一個(gè)微信小程序熏瞄,按一個(gè)按鈕即可脚祟。

Q: 為什么不使用 lodash 之類效率更高的庫,而使用的標(biāo)準(zhǔn)庫强饮?
A: 使用 lodash 之類的確實(shí)效率更高由桌,兼容性也更好∮史幔基于兩個(gè)原因沒有使用行您,一是 lodash 太大,而微信小程序限制在 1MB 以內(nèi)柠座。當(dāng)然邑雅,可以用 lodash 模塊化的版本來解決片橡,但還有第二個(gè)原因妈经,即 lodash 的一些 API 也有兼容性問題,比如我試過 lodash.findIndex 這個(gè)包,結(jié)果在 Android 6.0.1 上也無法成功運(yùn)行 (這一點(diǎn)未做深入驗(yàn)證吹泡,感興趣的同學(xué)可以驗(yàn)證一下)骤星。

總結(jié)

從后臺(tái)數(shù)據(jù)來看,小程序剛發(fā)布的前三天爆哑,確實(shí)帶來了非扯茨眩可觀的流量紅利,但這部分償鮮的用戶揭朝,很快就消失了队贱。三天過后,基本上保持了平衡的訪問量潭袱。流量紅利和廣告一樣柱嫌,是催化劑,真正有價(jià)值的還是要做用戶需要的產(chǎn)品屯换。

在此順手安利一下開發(fā)的兩個(gè)小程序 360好書推薦51經(jīng)典電影编丘,偶爾想用的時(shí)候打開,可能會(huì)偶遇一些小驚喜彤悔。但坦白講嘉抓,這兩個(gè)小程序都和微信倡導(dǎo)的小程序價(jià)值觀不符。微信還是希望通過小程序把線下低頻的晕窑,服務(wù)成本高(這里應(yīng)該主要是時(shí)間成本抑片,即便利性)的場(chǎng)景,轉(zhuǎn)化為線上快捷的使用方式幕屹。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末蓝丙,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子望拖,更是在濱河造成了極大的恐慌渺尘,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件说敏,死亡現(xiàn)場(chǎng)離奇詭異鸥跟,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)盔沫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門医咨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人架诞,你說我怎么就攤上這事拟淮。” “怎么了谴忧?”我有些...
    開封第一講書人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵很泊,是天一觀的道長(zhǎng)角虫。 經(jīng)常有香客問我,道長(zhǎng)委造,這世上最難降的妖魔是什么戳鹅? 我笑而不...
    開封第一講書人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮昏兆,結(jié)果婚禮上枫虏,老公的妹妹穿的比我還像新娘。我一直安慰自己爬虱,他們只是感情好隶债,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著跑筝,像睡著了一般燃异。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上继蜡,一...
    開封第一講書人閱讀 49,144評(píng)論 1 285
  • 那天回俐,我揣著相機(jī)與錄音,去河邊找鬼稀并。 笑死仅颇,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的碘举。 我是一名探鬼主播忘瓦,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼引颈!你這毒婦竟也來了耕皮?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤蝙场,失蹤者是張志新(化名)和其女友劉穎凌停,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體售滤,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡罚拟,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了完箩。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片赐俗。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖弊知,靈堂內(nèi)的尸體忽然破棺而出阻逮,到底是詐尸還是另有隱情,我是刑警寧澤秩彤,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布叔扼,位于F島的核電站皆尔,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏币励。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一珊拼、第九天 我趴在偏房一處隱蔽的房頂上張望食呻。 院中可真熱鬧伶唯,春花似錦妙黍、人聲如沸薄辅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽哭尝。三九已至斥杜,卻和暖如春涕俗,著一層夾襖步出監(jiān)牢的瞬間妹蔽,已是汗流浹背椎眯。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留胳岂,地道東北人编整。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像乳丰,于是被迫代替她去往敵國和親掌测。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,522評(píng)論 25 707
  • 給提問的開發(fā)者的建議:提問之前先查詢 文檔产园、通過社區(qū)右上角搜索搜索已經(jīng)存在的問題汞斧。 寫一個(gè)簡(jiǎn)明扼要的標(biāo)題,并且...
    極樂叔閱讀 13,388評(píng)論 0 3
  • 圖片發(fā)自簡(jiǎn)書App 文/楓丹白露 01 他 中元節(jié)什燕,濕冷的街道粘勒,雨水默無聲息的撒在頭上、肩上屎即;街兩邊店家稀稀疏疏透...
    楓丹白露_閱讀 664評(píng)論 4 21
  • 第七章 運(yùn)用結(jié)構(gòu)思考力來表達(dá)目標(biāo)時(shí)常用到一個(gè)AB法則:A代表受眾仲义,B代表行為。如你是公司的培訓(xùn)經(jīng)理剑勾,想讓高層發(fā)動(dòng)員...
    小魚的世界閱讀 3,292評(píng)論 0 1
  • R:
    炬無霸閱讀 172評(píng)論 0 0