你們好,我叫祥子😊; java
本人15年畢業於廣東藥科大學,於2018年8月加入37手遊安卓團隊,曾經就任於網易擔任安卓開發工程師; git
目前是37手遊安卓團隊負責人,除平常團隊相關管理外,空閒喜歡專研安卓相關技術,由於始終堅信 「技術管理" 是必定要持續關注技術,保持對技術的熱情,這樣纔不會是空中樓閣...程序員
(1)正常App開發中,在寫Activity或者Fragment時,沒法避免的會用到findViewById
這類的代碼,而後強制類型轉換出咱們所須要的控件類型,說實話,對於追求代碼簡潔,高可讀,而且想偷懶的程序員來講,寫這樣的重複代碼,簡直就是災難;github
因此咱們會用到控件註解框架(如:butterknife),來解決上面的困擾,具體細節網上不少博客能夠查到(如:butterknife系列),這裏就不展開講。編程
(2)遊戲發行SDK開發中,咱們並不能愉快的直接使用網上的框架,爲何?接下來咱們來看看;markdown
上面圖是發行行業的常規流程,其中能夠看到:app
若是咱們遊戲發行商SDK中,用經過ID找控件(findViewById方式),走上面的流程以後,輸出的渠道包,會有找不到控件崩潰的異常,具體緣由以下:框架
接入咱們發行商的SDK輸出母包,這個SDK中已經有findViewById(R.id.sqBtn),此次編譯假設ID的值爲0x7f070001,而且對應的資源類爲R1類ide
從新(二次)打包-反編譯母包,此時根據resource.arsc文件產生public.xml文件,這個public.xml會固定住ID的值,也就是R.id.sqBtn的值始終爲0x7f070001(resource.arsc文件和public.xml文件不瞭解的同窗能夠看之前的博客)oop
從新(二次)打包-準備渠道和SDK材料,關於《渠道和SDK材料》這裏不展開,相信發行的同窗是知道的,這裏在生成《渠道和SDK材料》的時候,實際上是通過了編譯和從新生成了R類的,假設此次生成的R.id.sqBtn的值爲0x7f070002,而且對應的資源類爲R2類
從新(二次)打包-融合/回編譯,融合過程當中,會把R2類覆蓋R1類
從新(二次)打包-渠道包,因爲包之前的R1類變爲了R2類,R.id.sqBtn的值變爲了0x7f070002;而後app運行,到resource.arsc中查找資源的時候,由於resource.arsc中的值爲之前的0x7f070001(因public.xml固定做用),值不同致使程序異常。
由於不能使用findViewById去找控件,因此大部分狀況下,發行行業安卓找控件通常採起的是getIdentifier的方式;例如:getIdentifier(「sqBtn」, 」id」 ,pkgName),這樣作的弊端是:
效率方面,程序員編碼的效率有提升空間(沒有編碼的自動提示等)
隱患方面,編譯的時候不像id寫法那樣,會檢查資源是否存在,若是不當心單詞寫錯,而後又沒有測試出來,會出現毀滅性的崩潰,致使線上事故
(1)關鍵點一:既然系統的R.id在發行流程中不能用,只能用getIdentifier(「sqBtn」, 」id」 ,pkgName)的方式,那麼咱們就要看看怎麼利用資源名 + getIdentifier, 經過某種方式轉換爲相似ID那樣能夠提示編程,怎麼辦呢?
37手遊有這麼一句話 「方法總比困難多」,經過gradle的插件能力能夠製造出本身的SqR,這裏咱們叫它《自制資源SqR技術》
(2)關鍵點二:有了符合咱們發行領域的SqR資源了,那麼接下來就是相似 butterknife 那樣利用註解技術實現控件注入框架,這裏咱們叫它**《自定義註解技術》**
備註:因爲涉及的知識點比較多,因此會分開來說,本章主要講關鍵點1
1)編譯時候校驗:
2)編碼時候提示:
1)新增長資源,如:圖片/字符串等(通常狀況是批量先弄好,再走到第2步)
2)生成SqR資源(除了這樣點擊以外,也能夠弄成AS的快捷鍵更加方便使用)
3)愉快的使用
1)首先須要先構建一個gradle工程,因爲這個不是本章重點,故不在這裏展開;不瞭解的同窗能夠去查相關資料,這裏推薦一個淺顯易懂的例子,戳這裏>>>
2)而後是開始寫咱們的生成SqR代碼了,寫以前先看下咱們要構造的文件最終模樣:
寫的核心思想是經過對R.java(工程爲app模塊)文件或者R.txt(工程爲lib模塊)文件進行改造
關鍵代碼簡析:
//rPackage:得到包名,以便獲取路徑
//例子:com.sq.mobile.sqinject_gradle_plugin
def rPackage = this.getPackageName(variant)println(rPackage)rPackage = rPackage.replace(".", "/")
//得到資源任務(the Android Resources processing task)
def variantOutput = variant.outputs.first()
def processResources = variantOutput.processResourcesProvider.get()
def rFiles = project.files(processResources.textSymbolOutputFile).builtBy(processResources)
//得到R.txt路徑
//R.txt路徑:sqinjectgradleplugin/app/build/intermediates/symbols/debug/R.txt
def RFilePath = rFiles.singleFile.absolutePath
//得到輸出路徑
//sqinjectgradleplugin/app/build/generated/not_namespaced_r_class_sources/debug/r
def outputDir = processResources.getSourceOutputDir()
//將原先的R文件的int換成String,並將其值使用變量名賦值
//tempFile = sqinjectgradleplugin/app/build/generated/not_namespaced_r_class_sources/debug/r/com/sq/mobile/sqinject_gradle_plugin/R.javaFile
tempFile = new File(outputDir.absolutePath + File.separator + rPackage + File.separator + "R.java");
println("R file path: " + tempFile.absolutePath)
rFileContent = tempFile.textPattern
pattern = Pattern.compile("public static(.*?) int (.*?)=(.*?);")
Matcher matcher = pattern.matcher(rFileContent);
while (matcher.find()) {
String replace = "public static final String " + matcher.group(2) + " = \"" + matcher.group(2) + "\";";
rFileContent = rFileContent.replaceAll(matcher.group(), replace)
}
rFileContent = rFileContent.replaceAll("class R", "class SqR")
複製代碼
關鍵代碼簡析:
文章主要介紹了控件注入框架的關鍵點1,利用插件方式實現getIdentifier的ID化;
下一篇將介紹關鍵點2,利用註解技術實現SqR的註解使用,最後實現相似 butterknife 框架
;這個框架目前在咱們內部已經普遍使用,它命名爲《SqInject》框架,目前申請專利中;
後續咱們除了會講解關鍵點2以外,會一併把框架開源出來,敬請期待>>>
過程當中有問題或者須要交流的同窗,能夠掃描二維碼加好友,而後進羣進行問題和技術的交流等;