記一次 Spine 動畫導致的 WebView 卡死和 APP 閃退

163 阅读3分钟

現象

WebView 打開頁面,頁面中使用了 Spine web 動畫,當僅僅是加載動畫,執行動畫的初始化過程,持續在頁面等待一段時間,就會導致 APP 閃退。在 OPPO 的部分機型上復現,比如 OPPO R17。

資源加載問題

json 文件 74K,圖片 1M 左右,其他頁面還有更小的圖片。應該不存在資源加載時間過長的問題。

设备兼容性问题

查了一下,webgl 的支持度很廣,WebGL 2.0  chrome 56 就支持了。

版本兼容性問題

Spine player 是遵循 en.esotericsoftware.com/spine-versi… 要求,和 editor 主要版本一致。

至於 Spine player 實現上是否不兼容某些版本的安卓 WebView,就不知道了。

內存不足、內存洩漏

有可能 Spine player 在實例化的過程中,佔用了大量內存。以及沒有正確銷毀實例對象。

期間調試,OPPO R17 WebView 可以打開打包後的頁面,本地開發頁面白屏,應該是不支持 Vite 的開發模式。只能通過本地打包然後 preview 的方式調試,不方便。剛好有 Vivo 手機也會出現問題,於是用 Vivo 手機調試。但是這裡有點問題,也是後面需要注意的一點。OPPO 的表現是頁面會卡一下APP直接閃退;Vivo 的表現大部分是 WebView 卡死,但還能關閉 WebView,APP 中的文字渲染有問題,重新打開WebView頁面,頁面加載異常,有時也是直接導致 APP 閃退。

頁面內存分析

使用 Chrome DevTools

使用 USB 數據線將安卓設備連接到電腦,在設備上打開開發者模式,打開 USB 調試。

在電腦 Chrome 上打開:chrome://inspect,頁面會顯示已連接的設備,在遠程目標下會顯示已打開的頁面,就可以開始調試了。

通過 Memory 面板,可以記錄當前堆內存使用情況。但是使用了下,頁面內存使用也就十幾M ,應該不算多啊。

使用最新版本的 Spine player

官網 demo 復現

<template>  <div id="container" class="container"></div></template><script setup>const spine = window.spineonMounted(() => {  const player = new spine.SpinePlayer('container', {    jsonUrl:      'https://esotericsoftware.com/files/examples/4.2/spineboy/export/spineboy-pro.json',    atlasUrl:      'https://esotericsoftware.com/files/examples/4.2/spineboy/export/spineboy-pma.atlas',    alpha: true,    nimation: 'walk',    backgroundColor: '#00000000',    showControls: true,  })  console.log('player: ', player)})</script>

使用以上 demo 也能在 Vivo 上復現,只是在頁面停留,就會導致卡死。

內存管理優化,確保頁面卸載時,銷毀 Spine 對象和相關資源。

onBeforeUnmount(() => {  player?.dispose()  player = null  spineContainer.value = null})onUnmounted(() => {  player?.dispose()  player = null  spineContainer.value = null})

兼容模式,針對特定機型不應用 Spine 動畫,這種方式處理,簡單粗暴。動畫是次要的,以實現功能為主。畢竟要解決這個問題,需要深入第三方庫實現的原理,其次,還要結合特定 WebView 的分析,這方面我並不擅長。

兼容處理就是通過 userAgent 判斷特定機型是否可以使用 Spine 動畫,具體頁面區分進行處理。

後來測試,通過增加銷毀 Spine 優化後,似乎 OPPO 的問題得到了解決(只是之後看了一下測試環境的頁面,沒有詳細測試),但是 Vivo 的還是不行。我是用 Vivo 進行的調試。