在上一篇,我們已經(jīng)知道了如何創(chuàng)建一個(gè)簡(jiǎn)單的插件,這一節(jié)將在此基礎(chǔ)上繼續(xù)說(shuō)說(shuō)如何配置自己的Transform。
1 轉(zhuǎn)換器 Transform
轉(zhuǎn)換器Transform是由Google提供,讓開(kāi)發(fā)者可以在編譯后,打包前這段時(shí)期,進(jìn)行額外干預(yù)操作,從而提供操作字節(jié)碼的時(shí)機(jī)。
2 創(chuàng)建 Transform
創(chuàng)建自定義的FreeCoderTransform類,然后繼承至Transform。
public class FreeCoderTransform extends Transform {
// 1
@Override
public String getName() {
return "freecoder";
}
// 2
@Override
public Set<QualifiedContent.ContentType> getInputTypes() {
return TransformManager.CONTENT_CLASS;
}
// 3
@Override
public Set<? super QualifiedContent.Scope> getScopes() {
return TransformManager.SCOPE_FULL_PROJECT;
}
// 4
@Override
public boolean isIncremental() {
return false;
}
// 5
@Override
public void transform(TransformInvocation transformInvocation) throws TransformException, InterruptedException, IOException {
Collection<TransformInput> inputs = transformInvocation.getInputs();
TransformOutputProvider outputProvider = transformInvocation.getOutputProvider();
inputs.forEach(transformInput -> {
transformInput.getJarInputs().forEach(jarInput -> {
File dest = outputProvider.getContentLocation(jarInput.getName(), jarInput.getContentTypes(), jarInput.getScopes(), Format.JAR);
try {
FileUtils.copyFile(jarInput.getFile(), dest);
} catch (IOException e) {
e.printStackTrace();
}
});
transformInput.getDirectoryInputs().forEach(directoryInput -> {
File dest = outputProvider.getContentLocation(directoryInput.getName(), directoryInput.getContentTypes(), directoryInput.getScopes(), Format.DIRECTORY);
try {
FileUtils.copyFile(directoryInput.getFile(), dest);
} catch (IOException e) {
e.printStackTrace();
}
});
});
}
}
標(biāo)記1處:對(duì)應(yīng)自定義Transform的Task名稱,同步完成后,會(huì)顯示在Gradle控制面板上,比如:transformClassesWithXXXForDebug。
標(biāo)記2、3處:定義了我們將要操作的編譯過(guò)程中具體哪些類型的文件,其中 2 的類型:
CONTENT_CLASS://class 文件
CONTENT_JARS: //jar包,包括class文件與resource資源文件
CONTENT_RESOURCES // resource資源文件
CONTENT_NATIVE_LIBS // 本地libs
CONTENT_DEX // dex文件
CONTENT_DEX_WITH_RESOURCES // dex文件與resource資源文件
標(biāo)記 3 處:表示作用的項(xiàng)目范圍,SCOPE_FULL_PROJECT表示整個(gè)項(xiàng)目。
標(biāo)記 4 處:表示是否支持增量編譯。
標(biāo)記 5 處:這里是個(gè)核心方法,需要覆蓋重寫(xiě),并且按Google提供的輸出目錄outputProvider上輸出,否則將這個(gè)Transform引入會(huì)報(bào)錯(cuò)。
transformInvocation.getInputs()獲取編譯后的所有class文件,transformInvocation.getOutputProvider()獲取Google提供的輸出目錄,我們把這些編譯后的文件做完處理后,然后再扔向該目錄,最終參與到打dex包的過(guò)程。
而后就是簡(jiǎn)單的復(fù)制工作,至于處理,我們下一節(jié)講,這個(gè)過(guò)程可以實(shí)現(xiàn)面向切面的編程。
3 引入 Transform
如下:(接上一節(jié)代碼)
public class FreeCoderPlugin implements Plugin<Project> {
@Override
public void apply(Project project) {
final FreeCoderExtension extension = project.getExtensions()
.create("freecoder", FreeCoderExtension.class);
project.afterEvaluate(innerProject -> System.out.println("extension: " + extension.name));
// 創(chuàng)建轉(zhuǎn)換器
FreeCoderTransform freeCoder = new FreeCoderTransform();
// 1
BaseExtension baseExtension = project.getExtensions().getByType(BaseExtension.class);
// 2
baseExtension.registerTransform(freeCoder);
}
}
標(biāo)記1處:BaseExtension指的就是Android打包過(guò)程中,com.android.application這個(gè)插件所包含的擴(kuò)展,方便開(kāi)發(fā)者在打包過(guò)程中進(jìn)行相應(yīng)的干預(yù)。
標(biāo)記2處:把我們的Transform注冊(cè)進(jìn)入該擴(kuò)展中。
到此為止,我們就配置好了自己的Transform,下一節(jié),就來(lái)講講如果通過(guò)更改字節(jié)碼達(dá)到面向切面編程的效果。