[Android][Framework]系統(tǒng)jar包擂找,sdk的制作及引用【轉(zhuǎn)】
原文鏈接為:http://wossoneri.github.io/2018/12/09/%5BAndroid%5D%5BFramework%5Dmastering-system-jar-and-sdk/
原文作者: Wossoneri
需求
因為我是開發(fā)ROM的,所以系統(tǒng)的一些改動需要暴露給我們自己的APP患雇。比如:
之前在PowerManager里面添加過一個新接口妈经,用來釋放所有的wake lock淮野,接口調(diào)用如下:
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
pm.releaseAll();
現(xiàn)在我們的系統(tǒng)APK需要調(diào)用這個方法,但是因為SDK不包含該方法吹泡,導(dǎo)致APK編譯不通過骤星。所以需要我編譯一個包含新接口方法的jar包交給APK編譯。(生成jar包的方法見該文章)
其實編譯系統(tǒng)jar包很簡單
make framework
即可得到framework.jar爆哑。
這時候把jar包導(dǎo)入到項目里洞难,發(fā)現(xiàn)缺找不到j(luò)ar包里的方法。這是因為揭朝,Android N使用了Jack編譯队贱。所以編出來的jar包里面沒有class文件,取而代之的是一個優(yōu)化過的dex文件萝勤。
如果要得到包含class文件的jar包露筒,只需要將Jack編譯關(guān)閉即可。
#include $(BUILD_JAVA_LIBRARY)
include $(BUILD_STATIC_JAVA_LIBRARY)
LOCAL_JACK_ENABLED := disabled
這樣再次編譯出來的jar包就是包含class文件的jar包敌卓。
Android Studio導(dǎo)入framework.jar
拷貝framework.jar包到app/libs目錄下
右鍵點擊framework.jar慎式,選擇add as library,作為庫添加到項目趟径。此時看到我們的gradle里dependencies多了一行瘪吏。
implementation files('libs/framework.jar')
因為我們希望這個包只在編譯時起作用,所以需要把implementation改為compileOnly蜗巧,幫助通過編譯掌眠,不打包到apk。
compileOnly files('libs/framework.jar')
也可以通過打開項目的File->Project structure幕屹,界面左側(cè)選擇app蓝丙,右側(cè)選擇Dependencies。引用列表里找到libs/classes.jar望拖,右側(cè)scope選擇compileOnly即可渺尘。
還在Project structure同樣的界面,把
{include=[*.jar], dir=libs}
刪掉说敏∨父或者把dependencies中的一行刪掉:
// implementation fileTree(include: ['*.jar'], dir: 'libs')
目的是明確classes.jar所在的libs目錄不作為一般的庫導(dǎo)入。
在build.gradle添加如下內(nèi)容,使其加入編譯
allprojects {
? ? repositories {
maven{url'https://maven.aliyun.com/repository/public'}
? ? ? ? google()
? ? ? ? jcenter()
? ? }
// 添加下面代碼
? ? gradle.projectsEvaluated {
? ? ? ? tasks.withType(JavaCompile) {
options.compilerArgs <<'-Xbootclasspath/p:app/libs/framework.jar'
? ? ? ? }
? ? }
}
在model的build.gradle里面加入自動更改model.iml文件的代碼医咨。這個代碼的作用是將classes.jar放在索引的第一個枫匾,這樣編譯的時候就會先從我們的jar包查找API,而不是從SDK加載拟淮。
preBuild {
? ? doLast {
defimlFile = file(project.name +".iml")
println'Change '+ project.name +'.iml order'
try{
defparsedXml = (newXmlParser()).parse(imlFile)
defjdkNode = parsedXml.component[1].orderEntry.find { it.'@type'=='jdk'}
parsedXml.component[1].remove(jdkNode)
defsdkString ="Android API "+ android.compileSdkVersion.substring("android-".length()) +" Platform"
newNode(parsedXml.component[1],'orderEntry', ['type':'jdk','jdkName': sdkString,'jdkType':'Android SDK'])
groovy.xml.XmlUtil.serialize(parsedXml,newFileOutputStream(imlFile))
}catch(FileNotFoundException e) {
// nop, iml not found
? ? ? ? }
? ? }
}
至此干茉,需要的操作都已經(jīng)完成。現(xiàn)在在Activity里使用我們的新接口:
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
pm.releaseAll();
此時惩歉,releaseAll雖然顯示為紅色等脂,但是編譯時可以通過的。編譯完成放在我們的系統(tǒng)里就可以運行了撑蚌。
此方法也可以解決@hide方法無法訪問的問題上遥,自己做一個去掉@hide注解的jar包調(diào)用即可。但是你的App必須有系統(tǒng)簽名争涌。
前面的方法粉楚,雖然可以讓App訪問系統(tǒng)自定義的API,但是亮垫,有些APP做了很多的外部庫引用模软,我們的jar包因為包含很多系統(tǒng)方法,會導(dǎo)致正常的類引用出現(xiàn)奇怪的錯誤饮潦。這些錯誤很難解決燃异,所以就討論了另外一個方案:做一個SDK,在SDK中調(diào)用系統(tǒng)的方法继蜡,然后讓APP調(diào)用我的SDK回俐。
下面是Android Studio制作SDK的步驟:
創(chuàng)建一個新項目
右鍵項目new module->Android Library->輸入庫名 mysdk
在module內(nèi)創(chuàng)建一個新的class文件,嘗試調(diào)用系統(tǒng)內(nèi)部的方法
publicclassMySDK{
publicstaticvoidforceStopPackage(Context context, String packageName){
? ? ? ? ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
? ? ? ? am.forceStopPackage(packageName);
? ? }
}
我在SDK暴露出來一個系統(tǒng)方法稀并,這樣App要殺掉應(yīng)用就不需要使用反射仅颇,直接調(diào)用我的SDK就可以。
把framework.jar放到module的lib目錄下碘举,在module內(nèi)的gradle添加以下代碼以編譯出module:
dependencies {
compileOnly files('libs/framework.jar')
...
}
gradle.projectsEvaluated {
? ? tasks.withType(JavaCompile) {
? ? ? ? options.compilerArgs.add('-Xbootclasspath/p:libs/framework.jar')
? ? }
}
task makeJar(type: Copy){
? ? delete 'build/libs/MySdk.jar'
? ? from('build/intermediates/bundles/default/')
? ? into('build/libs/')
? ? include('classes.jar')
? ? rename('classes.jar','MySdk.jar')
}
makeJar.dependsOn(build)
在Gradle菜單雙擊makeJar進行模塊編譯忘瓦,會在sdk里的build/outputs/aar出現(xiàn)
mysdk-debug.aar和mysdk-release.aar兩個庫文件。
將aar文件拷貝到App項目的lib目錄下引颈,gradle添加
android {
repositories {
? ? ? ? flatDir {
? ? ? ? ? ? dirs 'libs'
? ? ? ? }
? ? }
}
dependencies {
...
? ? compile(name:'mysdk', ext:'aar')
}
然后就可以在對應(yīng)Activity里快樂地使用MySDK.forceStopPackage()調(diào)用系統(tǒng)方法了耕皮。而且這還有個好處,一些系統(tǒng)API調(diào)用需要在Manifest添加對應(yīng)權(quán)限蝙场,這樣調(diào)用后就不需要添加權(quán)限了明场。
gradle版本變化報錯:
Invoke-customs are only supported starting with android 0 --min-api 26
解決辦法:在build.gradle下添加如下代碼
android {
? ? compileOptions {
? ? ? ? sourceCompatibility JavaVersion.VERSION_1_8
? ? ? ? targetCompatibility JavaVersion.VERSION_1_8
? ? }
}
https://stackoverflow.com/a/50198499/4522227
Ref:https://blog.csdn.net/zhonghe1114/article/details/80923730