Android Studio 運(yùn)行 Apk,不會采用最新構(gòu)建的 Cocos 內(nèi)容問題
每次在Cocos構(gòu)建項(xiàng)目后亿柑,在Android Studio上點(diǎn)擊 Run邢疙,「可能」會發(fā)現(xiàn)這次Run望薄,并不會采用剛剛構(gòu)建的Cocos內(nèi)容!痕支?颁虐?
劃重點(diǎn): 「可能」
- 有些人/電腦/AndroidStudio版本 會 立即采用剛剛構(gòu)建的 Cocos 內(nèi)容
- 有些人/電腦/AndroidStudio版本 不會 立即采用剛剛構(gòu)建的 Cocos 內(nèi)容
如果這個(gè)能引起你的共鳴,那么不妨試著看下去~
Cocos & Android 構(gòu)建原理
解決這個(gè)問題卧须,我們可以先大概了解一下 Cocos & Android 的一些構(gòu)建原理:
1.Cocos 構(gòu)建資源會放在 Android 項(xiàng)目的 assets 資源目錄中
2.app 運(yùn)行時(shí)另绩,讀取 assets 資源目錄花嘶,從而獲取到 Cocos 構(gòu)建后的資源
這里面,我們重點(diǎn)探究的是 Cocos 是怎么將構(gòu)建的內(nèi)容放到 Android 的 assets 資源目錄中呢车海?
這個(gè)操作其實(shí)在構(gòu)建后的 app/build.gradle
中隘击,關(guān)鍵代碼如下:
android.applicationVariants.all { variant ->
// delete previous files first
delete "${buildDir}/intermediates/merged_assets/${variant.dirName}"
// 復(fù)制 Cocos 資源到 Assets 目錄中
variant.mergeAssets.doLast {
// ....
copy {
from "${sourceDir}/res"
into "${outputDir}/res"
}
copy {
from "${sourceDir}/subpackages"
into "${outputDir}/subpackages"
}
copy {
from "${sourceDir}/src"
into "${outputDir}/src"
}
copy {
from "${sourceDir}/jsb-adapter"
into "${outputDir}/jsb-adapter"
}
copy {
from "${sourceDir}/main.js"
from "${sourceDir}/project.json"
into outputDir
}
}
//....
}
怎么理解上面這段代碼呢?
首先 Android 打包 Apk 是由 Google 開發(fā)的一套 Gradle 插件去完成打包的埋同。實(shí)際上莺禁,每次打包會有很多構(gòu)建任務(wù)窄赋,比如:編譯java,編譯C++等等忆绰。各個(gè)任務(wù)之間存在依賴關(guān)系,插件根據(jù)依賴關(guān)系執(zhí)行對應(yīng)任務(wù)翰灾,最后就生成了APK。
而其中有一個(gè)插件內(nèi)置的 Android 構(gòu)建任務(wù) mergeAssets
平斩,其目的在于將 Android 項(xiàng)目及各個(gè)依賴 Library 的 Assets 資源文件合并到構(gòu)建緩存目錄咽块,方便最后打包。
而 Cocos 就是在 這個(gè)任務(wù)最后(variant.mergeAssets.doLast
)侈沪,添加了一些復(fù)制任務(wù),將 Cocos 的腳本資源等等內(nèi)容復(fù)制到 Android Apk 的 Assets 資源目錄中瘦馍。
現(xiàn)在应役,你應(yīng)該(必須)能很好地理解上面這段代碼以及 Cocos & Android 的構(gòu)建過程了~
問題成因
那么問題來了?
為什么有些人呻惕,他們構(gòu)建Cocos的游戲后滥比,在Android Studio中運(yùn)行,每次都能更新 Cocos 構(gòu)建后的資源濒持,而有些人卻不會更新 Cocos 構(gòu)建后的資源呢寺滚?
實(shí)際上,這里用有些人不是很恰當(dāng)村视,只是大家習(xí)慣于這樣子描述問題蚁孔。這個(gè)問題的差異化在于所用的引擎版本和Android構(gòu)建Gradle版本,在不同人/PC上可能會采用不同Android Studio版本杠氢,不同的構(gòu)建Gradle版本
鼻百。
問題代碼具體為上面的此行代碼
delete "${buildDir}/intermediates/merged_assets/${variant.dirName}"
這個(gè)代碼的意圖在于每次復(fù)制 Cocos 的資源到 assets 目錄時(shí)摆尝,先刪除Android之前有可能構(gòu)建過的 assets 構(gòu)建暫存目錄因悲,以實(shí)現(xiàn)每次打包都能 Copy 最新的 Cocos 構(gòu)建后的內(nèi)容進(jìn)去。
為什么要先刪除 assets 構(gòu)建暫存目錄呢臼朗?這里面蝎土,還得插入一個(gè)知識點(diǎn)。
Groovy 的 Copy 任務(wù)會自動識別本次是否應(yīng)該執(zhí)行復(fù)制誊涯。比如:復(fù)制文件A到一個(gè)目錄兩次暴构,在第二次執(zhí)行的時(shí)候,同名文件則不會復(fù)制取逾,而是會 UP-TO-DATE 不會再執(zhí)行。
因此為了避免 Cocos 二次構(gòu)建后的(同名文件)內(nèi)容也能在 Android Studio 中 Run 的時(shí)候也能用上误阻,那么就需要先刪除目錄晴埂,讓復(fù)制后的目錄沒有同名文件,這樣子在執(zhí)行復(fù)制的時(shí)候就會真的是觸發(fā)復(fù)制邏輯精耐,從而更新最新的 Cocos 構(gòu)建內(nèi)容到 Apk 包中琅锻。
嗯,這個(gè)意圖很清晰沫浆,但是上述代碼并不完美滚秩。
首先淮捆,這種 Hard Code 寫法很容易出現(xiàn)問題本股,如果路徑換了一下桐腌,那么實(shí)際上就不能很好的執(zhí)行這個(gè)刪除意圖了案站。而問題恰好就是這個(gè)路徑問題。
實(shí)際上蟆盐,有些同學(xué)可能會用不同版本的 Android Studio 石挂,用了不同版本的 Gradle Plugin。而不同版本的 Gradle Plugin 的 mergeAssets
Task 的暫存目錄并不全是上面的絕對路徑痹愚。
事實(shí)上,不同 Gradle Plugin 版本的 mergeAssets 的輸出路徑有哪些窖式,我也不知道有哪些路徑动壤,并且我們也不應(yīng)該去固化這個(gè)路徑。Android 在持續(xù)發(fā)展蜒灰,打包工具也在持續(xù)更新肩碟,構(gòu)建任務(wù)也可能會修改升級,但這種 Hard Code 路徑的寫法卻極有可能不會能持續(xù)用下去翅溺。
我們更應(yīng)該用的是 variant.mergeAssets.outputDir
變量去表示 mergeAssets 的輸出路徑髓抑,而不是某個(gè) Hard Code 的字符串。
而 Cocos 恰好是用了 Hard Code 的路徑字符串褪猛,從而導(dǎo)致了這個(gè)小問題:有些(版本)每次運(yùn)行都能拿到最新的 Cocos 構(gòu)建資源羹饰,而有些版本缺不可以
解決方案
至此碳却,修復(fù)起來就很簡單了昼浦,只需要一個(gè)很簡單的修改就可以修復(fù):
-- delete "${buildDir}/intermediates/merged_assets/${variant.dirName}"
++ delete variant.mergeAssets.outputDir
當(dāng)然筒主,這個(gè)寫法能持續(xù)兼容多久,不能保證使兔,但是相信到時(shí)候你已經(jīng)知道應(yīng)該怎么解決了