[Framework]系統jar包,sdk的製作及引用
因為我是開發ROM的,所以系統的一些改動需要暴露給我們自己的APP。比如:
之前在PowerManager裡面新增過一個新介面,用來釋放所有的wake lock,介面呼叫如下:
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); pm.releaseAll();
現在我們的系統APK需要呼叫這個方法,但是因為SDK不包含該方法,導致APK編譯不通過。所以需要我編譯一個包含新介面方法的jar包交給APK編譯。(生成jar包的方法見該文章 )
編譯Jar包
其實編譯系統jar包很簡單
make framework
即可得到framework.jar。
這時候把jar包匯入到專案裡,發現缺找不到jar包裡的方法。這是因為,Android N使用了Jack編譯。所以編出來的jar包裡面沒有class檔案,取而代之的是一個優化過的dex檔案。
如果要得到包含class檔案的jar包,只需要將Jack編譯關閉即可。
#include $(BUILD_JAVA_LIBRARY) include $(BUILD_STATIC_JAVA_LIBRARY) LOCAL_JACK_ENABLED := disabled
這樣再次編譯出來的jar包就是包含class檔案的jar包。
Android Studio匯入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,介面左側選擇
app
,右側選擇Dependencies
。引用列表裡找到libs/classes.jar,右側scope選擇compileOnly即可。 -
還在Project structure同樣的介面,把
{include=[*.jar], dir=libs}
刪掉。或者把dependencies中的一行刪掉:
// implementation fileTree(include: ['*.jar'], dir: 'libs')
目的是明確classes.jar所在的libs目錄不作為一般的庫匯入。
-
在build.gradle新增如下內容,使其加入編譯
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 { def imlFile = file(project.name + ".iml") println 'Change ' + project.name + '.iml order' try { def parsedXml = (new XmlParser()).parse(imlFile) def jdkNode = parsedXml.component[1].orderEntry.find { it.'@type' == 'jdk' } parsedXml.component[1].remove(jdkNode) def sdkString = "Android API " + android.compileSdkVersion.substring("android-".length()) + " Platform" new Node(parsedXml.component[1], 'orderEntry', ['type': 'jdk', 'jdkName': sdkString, 'jdkType': 'Android SDK']) groovy.xml.XmlUtil.serialize(parsedXml, new FileOutputStream(imlFile)) } catch (FileNotFoundException e) { // nop, iml not found } } }
至此,需要的操作都已經完成。現在在Activity裡使用我們的新介面:
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); pm.releaseAll();
此時,releaseAll
雖然顯示為紅色,但是編譯時可以通過的。編譯完成放在我們的系統裡就可以運行了。
此方法也可以解決@hide方法無法訪問的問題,自己做一個去掉@hide註解的jar包呼叫即可。但是你的App必須有系統簽名。
SDK製作
前面的方法,雖然可以讓App訪問系統自定義的API,但是,有些APP做了很多的外部庫引用,我們的jar包因為包含很多系統方法,會導致正常的類引用出現奇怪的錯誤。這些錯誤很難解決,所以就討論了另外一個方案:做一個SDK,在SDK中呼叫系統的方法,然後讓APP呼叫我的SDK。
下面是Android Studio製作SDK的步驟:
-
建立一個新專案
-
右鍵專案new module->Android Library->輸入庫名 mysdk
-
在module內建立一個新的class檔案,嘗試呼叫系統內部的方法
public class MySDK { public static void forceStopPackage(Context context, String packageName) { ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); am.forceStopPackage(packageName); } }
我在SDK暴露出來一個系統方法,這樣App要殺掉應用就不需要使用反射,直接呼叫我的SDK就可以。
-
把framework.jar放到module的lib目錄下,在module內的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出現
mysdk-debug.aar
和mysdk-release.aar
兩個庫檔案。 -
將aar檔案拷貝到App專案的lib目錄下,gradle新增
android { repositories { flatDir { dirs 'libs' } } } dependencies { ... compile(name:'mysdk', ext:'aar') }
然後就可以在對應Activity裡快樂地使用
MySDK.forceStopPackage()
呼叫系統方法了。而且這還有個好處,一些系統API呼叫需要在Manifest新增對應許可權,這樣呼叫後就不需要新增許可權了。
問題
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 } }
ofollow,noindex">https://stackoverflow.com/a/50198499/4522227
Ref:https://blog.csdn.net/zhonghe1114/article/details/80923730