日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android构建流程——篇二

發布時間:2024/9/30 Android 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android构建流程——篇二 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

    • 預操作
    • 任務列表
    • 如何查看一個task類
    • Task1: checkDebugClasspath
      • 1. input/output
      • 2. 如何找到任務實現類
      • 3. 核心類(AppClasspathCheckTask)
    • Task2: preDebugBuild
      • 1. input/ouput
      • 2. 核心類(AppPreBuildTask)
    • Task3: compileDebugAidl
      • 1. input/output
      • 2. 核心類(AidlCompile)
      • 3. 映射文件
    • Task4: compileDebugRenderscript
      • 1. RenderScript 概覽
      • 2. input/ouput
      • 3. 核心類(RenderscriptCompile)
    • 參考鏈接

預操作

為說明Android構建過程中gradle執行的各task,寫了簡單demo

git clone https://github.com/xiaobaoyihao/AndroidGradleTaskDemo.git

先羅列下Android構建流程中任務有哪些,本系列講解都是基于gradle plugin 3.2.0源碼

任務列表

clone下demo,終端執行

./gradlew assembleDebug --console=plain

輸出如下任務鏈

:app:checkDebugClasspath UP-TO-DATE :app:preBuild UP-TO-DATE :app:preDebugBuild UP-TO-DATE :app:compileDebugAidl UP-TO-DATE :app:compileDebugRenderscript UP-TO-DATE :app:checkDebugManifest UP-TO-DATE :app:generateDebugBuildConfig UP-TO-DATE :app:prepareLintJar UP-TO-DATE :app:mainApkListPersistenceDebug UP-TO-DATE :app:generateDebugResValues UP-TO-DATE :app:generateDebugResources UP-TO-DATE :app:mergeDebugResources UP-TO-DATE :app:createDebugCompatibleScreenManifests UP-TO-DATE :app:processDebugManifest UP-TO-DATE :app:splitsDiscoveryTaskDebug UP-TO-DATE :app:processDebugResources UP-TO-DATE :app:generateDebugSources UP-TO-DATE :app:javaPreCompileDebug UP-TO-DATE :app:compileDebugJavaWithJavac UP-TO-DATE :app:compileDebugNdk NO-SOURCE :app:compileDebugSources UP-TO-DATE :app:mergeDebugShaders UP-TO-DATE :app:compileDebugShaders UP-TO-DATE :app:generateDebugAssets UP-TO-DATE :app:mergeDebugAssets UP-TO-DATE :app:transformClassesWithDexBuilderForDebug UP-TO-DATE :app:transformDexArchiveWithExternalLibsDexMergerForDebug UP-TO-DATE :app:transformDexArchiveWithDexMergerForDebug UP-TO-DATE :app:mergeDebugJniLibFolders UP-TO-DATE :app:transformNativeLibsWithMergeJniLibsForDebug UP-TO-DATE :app:checkDebugLibraries UP-TO-DATE :app:processDebugJavaRes NO-SOURCE :app:transformResourcesWithMergeJavaResForDebug UP-TO-DATE :app:validateSigningDebug UP-TO-DATE :app:packageDebug UP-TO-DATE :app:assembleDebug UP-TO-DATE

為了更清楚觀察各任務,我們可以對每個任務的輸入和輸出添加日志打印,在demo中放開build.gradle中任務打印區域代碼

如何查看一個task類

可以通過taskname來查找,一般任務路徑大部分都是在

com.android.build.gradle.internal.tasks com.android.build.gradle.tasks

目錄下,任務名稱基本和類名一致

Task1: checkDebugClasspath

1. input/output

input:/Users/apple/.gradle/caches/transforms-1/files-1.1/appcompat-v7-26.1.0.aar/2774ea4f1cf1e83a6ad8e8d3c8b463b6/jars/classes.jar input:/Users/apple/.gradle/caches/transforms-1/files-1.1/constraint-layout-1.1.3.aar/f43c0ba95b6494825ed940fc4f04662b/jars/classes.jar input:/Users/apple/.gradle/caches/transforms-1/files-1.1/animated-vector-drawable-26.1.0.aar/559112320064089dfaf6780e71d5b44f/jars/classes.jar input:/Users/apple/.gradle/caches/transforms-1/files-1.1/support-vector-drawable-26.1.0.aar/c2c3ad4abfd49316f6769b8238b0f010/jars/classes.jar input:/Users/apple/.gradle/caches/transforms-1/files-1.1/support-v4-26.1.0.aar/9ac5f97e8ccb24c52b7cbb6202c12ad0/jars/classes.jar input:/Users/apple/.gradle/caches/transforms-1/files-1.1/support-media-compat-26.1.0.aar/53ab5ad72634f3497309a8788f3ca200/jars/classes.jar input:/Users/apple/.gradle/caches/transforms-1/files-1.1/support-fragment-26.1.0.aar/7e6a4ce6591d722d47aafc36d980f8b4/jars/classes.jar input:/Users/apple/.gradle/caches/transforms-1/files-1.1/support-core-utils-26.1.0.aar/4c474caa9ac1f01c4936bd96905ecacd/jars/classes.jar input:/Users/apple/.gradle/caches/transforms-1/files-1.1/support-core-ui-26.1.0.aar/868eaa7e0c620cd85d72ad4f340e8bb1/jars/classes.jar input:/Users/apple/.gradle/caches/transforms-1/files-1.1/support-compat-26.1.0.aar/4ec3c1c46e5bad9ac3b91f45a2afec3e/jars/classes.jar input:/Users/apple/.gradle/caches/modules-2/files-2.1/com.android.support/support-annotations/26.1.0/814258103cf26a15fcc26ecce35f5b7d24b73f8/support-annotations-26.1.0.jar input:/Users/apple/.gradle/caches/modules-2/files-2.1/com.android.support.constraint/constraint-layout-solver/1.1.3/bde0667d7414c16ed62d3cfe993cff7f9d732373/constraint-layout-solver-1.1.3.jar input:/Users/apple/.gradle/caches/transforms-1/files-1.1/runtime-1.0.0.aar/5b2333922ba05b1f174de51739b24d14/jars/classes.jar input:/Users/apple/.gradle/caches/modules-2/files-2.1/android.arch.lifecycle/common/1.0.0/e414a4cb28434e25c4f6aa71426eb20cf4874ae9/common-1.0.0.jar input:/Users/apple/.gradle/caches/modules-2/files-2.1/android.arch.core/common/1.0.0/a2d487452376193fc8c103dd2b9bd5f2b1b44563/common-1.0.0.jar ========================================================= output:/Users/apple/work/project/AndroidGradleTaskDemo/app/build/intermediates/checkDebugClasspath/debug

從task字面可以猜測出該任務是對app classpath做校驗,具體是在那個類呢?
我們找到到AppClasspathCheckTask.java,如何確定是正確的呢?
我們發現該類中有個ConfigAction.getName方法


其實這個方法的返回字符串就是執行的任務名(checkDebugClasspath),具體怎么流程大家直接看代碼就知道了

ConfigAction被調用的地方

核心入口代碼

//ApplicationTaskManager.java @Overrideprotected Task createVariantPreBuildTask(@NonNull VariantScope scope) {final VariantType variantType = scope.getVariantConfiguration().getType();if (variantType.isApk()) {AppClasspathCheckTask classpathCheck =taskFactory.create(new AppClasspathCheckTask.ConfigAction(scope));return (variantType.isTestComponent()? taskFactory.create(new TestPreBuildTask.ConfigAction(scope)): taskFactory.create(new AppPreBuildTask.ConfigAction(scope))).dependsOn(classpathCheck);}return super.createVariantPreBuildTask(scope);}

有人會問中間的debug怎么多出來?追蹤getName方法內部實現發現最終調用BaseVariantData.getTaskName方法

public String getTaskName(@NonNull String prefix, @NonNull String suffix) {return StringHelper.appendCapitalized(prefix, variantConfiguration.getFullName(), suffix); }// VariantConfiguration.javapublic String getFullName() {if (mFullName == null) {mFullName =computeFullName(getFlavorName(),mBuildType,mType,mTestedConfig == null ? null : mTestedConfig.getType());}return mFullName;}/*** Returns the full, unique name of the variant in camel case (starting with a lower case),* including BuildType, Flavors and Test (if applicable).** @param flavorName the flavor name, as computed by {@link #computeFlavorName(List)}* @param buildType the build type* @param type the variant type* @return the name of the variant*/public static <B extends BuildType> String computeFullName(@NonNull String flavorName,@NonNull B buildType,@NonNull VariantType type,@Nullable VariantType testedType) {StringBuilder sb = new StringBuilder();if (!flavorName.isEmpty()) {sb.append(flavorName);StringHelper.appendCapitalized(sb, buildType.getName());} else {sb.append(buildType.getName());}if (type.isHybrid()) {sb.append("Feature");}if (type.isTestComponent()) {if (testedType != null && testedType.isHybrid()) {sb.append("Feature");}sb.append(type.getSuffix());}return sb.toString();}

可以看到computeFullName是返回variant相關的名字,和我們輸入的assembleDebug相匹配,所以我們后期直接通過任務名就能準確找到對應ConfigAction類了這樣真正的Task類名也就找到了

2. 如何找到任務實現類

確定任務名 -> 在所有TaskConfigAction的子類中尋找getName返回值是否與其task名匹配 -> 對應Task實現類

3. 核心類(AppClasspathCheckTask)

//AppClasspathCheckTask.java @TaskAction void run() {compareClasspaths();}//ClasspathComparisionTask.java void compareClasspaths() {//com.android.support:appcompat-v7:23.3.0//group:module/artifact:versionSet<ResolvedArtifactResult> runtimeArtifacts = runtimeClasspath.getArtifacts();Set<ResolvedArtifactResult> compileArtifacts = compileClasspath.getArtifacts();// Store a map of groupId -> (artifactId -> versions)Map<String, Map<String, String>> runtimeIds =Maps.newHashMapWithExpectedSize(runtimeArtifacts.size());//1. 存儲runtime依賴版本信息到map中groupId -> (artifactId -> versions)for (ResolvedArtifactResult artifact : runtimeArtifacts) {// only care about external dependencies to compare versions.final ComponentIdentifier componentIdentifier =artifact.getId().getComponentIdentifier();if (componentIdentifier instanceof ModuleComponentIdentifier) {ModuleComponentIdentifier moduleId =(ModuleComponentIdentifier) componentIdentifier;// get the sub-map, creating it if needed.Map<String, String> subMap =runtimeIds.computeIfAbsent(moduleId.getGroup(), s -> new HashMap<>());subMap.put(moduleId.getModule(), moduleId.getVersion());}}//對compileArtifacts集合進行遍歷,并和compileArtifacts中相同的group.module比較,如何發現版本不一致,調用onDifferentVersionsFound方法for (ResolvedArtifactResult artifact : compileArtifacts) {// only care about external dependencies to compare versions.final ComponentIdentifier componentIdentifier =artifact.getId().getComponentIdentifier();if (componentIdentifier instanceof ModuleComponentIdentifier) {ModuleComponentIdentifier moduleId =(ModuleComponentIdentifier) componentIdentifier;Map<String, String> subMap = runtimeIds.get(moduleId.getGroup());if (subMap == null) {continue;}String runtimeVersion = subMap.get(moduleId.getModule());if (runtimeVersion == null) {continue;}if (runtimeVersion.equals(moduleId.getVersion())) {continue;}onDifferentVersionsFound(moduleId.getGroup(),moduleId.getModule(),runtimeVersion,moduleId.getVersion());}}}//AppClasspathCheckTask.java @Override void onDifferentVersionsFound(@NonNull String group,@NonNull String module,@NonNull String runtimeVersion,@NonNull String compileVersion) {//這個方法很簡單,就是比較版本不一樣的話,會提示依賴有沖突,運行時可能導致crashString suggestedVersion;try {GradleVersion runtime = GradleVersion.parse(runtimeVersion);GradleVersion compile = GradleVersion.parse(compileVersion);if (runtime.compareTo(compile) > 0) {suggestedVersion = runtimeVersion;} else {suggestedVersion = compileVersion;}} catch (Throwable e) {// in case we are unable to parse versions for some reason, choose runtimesuggestedVersion = runtimeVersion;}String message =String.format("Conflict with dependency '%1$s:%2$s' in project '%3$s'. Resolved versions for "+ "runtime classpath (%4$s) and compile classpath (%5$s) differ. This "+ "can lead to runtime crashes. To resolve this issue follow "+ "advice at https://developer.android.com/studio/build/gradle-tips#configure-project-wide-properties. "+ "Alternatively, you can try to fix the problem "+ "by adding this snippet to %6$s:\n"+ "dependencies {\n"+ " implementation(\"%1$s:%2$s:%7$s\")\n"+ "}\n",group,module,getProject().getPath(),runtimeVersion,compileVersion,getProject().getBuildFile(),suggestedVersion);reporter.reportWarning(EvalIssueReporter.Type.GENERIC, message);}

簡單總結:

該任務就是對編譯類路徑和運行時類路徑進行校驗,如果相同的group.module中存在不同version,則提示用戶依賴有沖突,會導致運行是crash

沖突解決方案參見官網

Task2: preDebugBuild

1. input/ouput

taskName:preDebugBuild input:/Users/apple/.gradle/caches/transforms-1/files-1.1/appcompat-v7-26.1.0.aar/2774ea4f1cf1e83a6ad8e8d3c8b463b6/AndroidManifest.xml input:/Users/apple/.gradle/caches/transforms-1/files-1.1/constraint-layout-1.1.3.aar/f43c0ba95b6494825ed940fc4f04662b/AndroidManifest.xml input:/Users/apple/.gradle/caches/transforms-1/files-1.1/animated-vector-drawable-26.1.0.aar/559112320064089dfaf6780e71d5b44f/AndroidManifest.xml input:/Users/apple/.gradle/caches/transforms-1/files-1.1/support-vector-drawable-26.1.0.aar/c2c3ad4abfd49316f6769b8238b0f010/AndroidManifest.xml input:/Users/apple/.gradle/caches/transforms-1/files-1.1/support-v4-26.1.0.aar/9ac5f97e8ccb24c52b7cbb6202c12ad0/AndroidManifest.xml input:/Users/apple/.gradle/caches/transforms-1/files-1.1/support-media-compat-26.1.0.aar/53ab5ad72634f3497309a8788f3ca200/AndroidManifest.xml input:/Users/apple/.gradle/caches/transforms-1/files-1.1/support-fragment-26.1.0.aar/7e6a4ce6591d722d47aafc36d980f8b4/AndroidManifest.xml input:/Users/apple/.gradle/caches/transforms-1/files-1.1/support-core-utils-26.1.0.aar/4c474caa9ac1f01c4936bd96905ecacd/AndroidManifest.xml input:/Users/apple/.gradle/caches/transforms-1/files-1.1/support-core-ui-26.1.0.aar/868eaa7e0c620cd85d72ad4f340e8bb1/AndroidManifest.xml input:/Users/apple/.gradle/caches/transforms-1/files-1.1/support-compat-26.1.0.aar/4ec3c1c46e5bad9ac3b91f45a2afec3e/AndroidManifest.xml input:/Users/apple/.gradle/caches/transforms-1/files-1.1/runtime-1.0.0.aar/5b2333922ba05b1f174de51739b24d14/AndroidManifest.xml ========================================================= output:/Users/apple/work/project/AndroidGradleTaskDemo/app/build/intermediates/prebuild/debug

輸入都為依賴庫的清單文件,輸出為空;這個任務簡單說也是對應用變體做校驗

2. 核心類(AppPreBuildTask)

@TaskAction void run() {Set<ResolvedArtifactResult> compileArtifacts = new HashSet<>();compileArtifacts.addAll(compileManifests.getArtifacts());compileArtifacts.addAll(compileNonNamespacedManifests.getArtifacts());Set<ResolvedArtifactResult> runtimeArtifacts = new HashSet<>();runtimeArtifacts.addAll(runtimeManifests.getArtifacts());runtimeArtifacts.addAll(runtimeNonNamespacedManifests.getArtifacts());// create a map where the key is either the sub-project path, or groupId:artifactId for// external dependencies.// For external libraries, the value is the version.Map<String, String> runtimeIds = Maps.newHashMapWithExpectedSize(runtimeArtifacts.size());// build a list of the runtime artifactsfor (ResolvedArtifactResult artifact : runtimeArtifacts) {handleArtifact(artifact.getId().getComponentIdentifier(), runtimeIds::put);}// run through the compile ones to check for provided only.for (ResolvedArtifactResult artifact : compileArtifacts) {final ComponentIdentifier compileId = artifact.getId().getComponentIdentifier();handleArtifact(compileId,(key, value) -> {//校驗代碼邏輯String runtimeVersion = runtimeIds.get(key);if (runtimeVersion == null) {if (isBaseModule) {String display = compileId.getDisplayName();throw new RuntimeException("Android dependency '"+ display+ "' is set to compileOnly/provided which is not supported");}} else if (!runtimeVersion.isEmpty()) {// compare versions.if (!runtimeVersion.equals(value)) {throw new RuntimeException(String.format("Android dependency '%s' has different version for the compile (%s) and runtime (%s) classpath. You should manually set the same version via DependencyResolution",key, value, runtimeVersion));}}});} }private void handleArtifact(@NonNull ComponentIdentifier id, @NonNull BiConsumer<String, String> consumer) {if (id instanceof ProjectComponentIdentifier) {consumer.accept(((ProjectComponentIdentifier) id).getProjectPath().intern(), "");} else if (id instanceof ModuleComponentIdentifier) {ModuleComponentIdentifier moduleComponentId = (ModuleComponentIdentifier) id;consumer.accept(moduleComponentId.getGroup() + ":" + moduleComponentId.getModule(),moduleComponentId.getVersion());} else if (id instanceof OpaqueComponentArtifactIdentifier) {// skip those for now.// These are file-based dependencies and it's unlikely to be an AAR.} else {getLogger().warn("Unknown ComponentIdentifier type: "+ id.getClass().getCanonicalName());}}

如果用compileOnly、provider修飾aar則會失敗

驗證下我們的想法,add 如下代碼到app.build.gradle中

compileOnly 'com.facebook.stetho:stetho:1.5.0'

執行

./gradlew preDebugBuild

執行結果

可以反推compileOnly不支持修飾aar只支持jar
補充下AppClasspathCheckTask是AppPreBuildTask任務前置條件,在👇的圖可以體現出來

Task3: compileDebugAidl

1. input/output

taskName:compileDebugAidl input:/Users/apple/.gradle/caches/transforms-1/files-1.1/support-media-compat-26.1.0.aar/53ab5ad72634f3497309a8788f3ca200/aidl input:/Users/apple/.gradle/caches/transforms-1/files-1.1/support-compat-26.1.0.aar/4ec3c1c46e5bad9ac3b91f45a2afec3e/aidl input:/Users/apple/work/project/AndroidGradleTaskDemo/app/src/main/aidl/com/gradle/task/demo/IHelloAidlInterface.aidl ========================================================= output:/Users/apple/work/project/AndroidGradleTaskDemo/app/build/intermediates/incremental/compileDebugAidl output:/Users/apple/work/project/AndroidGradleTaskDemo/app/build/generated/source/aidl/debug
  • 可以看出該任務是掃描工程下依賴的所有aidl文件,并生成對應的java文件
  • 在生成dependency.store文件
  • inputoutput備注
    *.aidlbuild/*.javajava源文件
    -dependency.store.aidl -> .java映射文件表

    2. 核心類(AidlCompile)

    先來看下該類繼承關系
    AidlCompile -> IncrementalTask(abstract)

    //IncrementalTask.java /*** Gradle's entry-point into this task. Determines whether or not it's possible to do this task* incrementally and calls either doIncrementalTaskAction() if an incremental build is possible,* and doFullTaskAction() if not.*/ @TaskAction void taskAction(IncrementalTaskInputs inputs) throws Exception {//如果是非增量操作,直接走全量操作方法if (!isIncremental() || !inputs.isIncremental()) {getProject().getLogger().info("Unable do incremental execution: full task run");//交給子類實現doFullTaskAction();return;}//走增量操作方法,并攜帶變更的輸入文件,交給子類實現doIncrementalTaskAction(getChangedInputs(inputs)); }private Map<File, FileStatus> getChangedInputs(IncrementalTaskInputs inputs) {final Map<File, FileStatus> changedInputs = Maps.newHashMap();inputs.outOfDate(change -> {FileStatus status = change.isAdded() ? FileStatus.NEW : FileStatus.CHANGED;changedInputs.put(change.getFile(), status);});inputs.removed(change -> changedInputs.put(change.getFile(), FileStatus.REMOVED));return changedInputs; }

    可以看到該任務主流程邏輯還是比較簡單,如果是全量動作,走doFullTaskAction方法,否則走doIncrementalTaskAction增量操作,我們先來看下全量操作

    doFullTaskAction

    /** Task to compile aidl files. Supports incremental update. */ @CacheableTask public class AidlCompile extends IncrementalTask {private static final String DEPENDENCY_STORE = "dependency.store";private static final PatternSet PATTERN_SET = new PatternSet().include("**/*.aidl");@Overrideprotected void doFullTaskAction() throws IOException {//1. 全量操作前,先對輸出目錄做下清理操作// this is full run, clean the previous outputFile destinationDir = getSourceOutputDir();File parcelableDir = getPackagedDir();FileUtils.cleanOutputDir(destinationDir);if (parcelableDir != null) {FileUtils.cleanOutputDir(parcelableDir);}//2. 編譯所有aidl文件DepFileProcessor processor = new DepFileProcessor();try {compileAllFiles(processor);} catch (Exception e) {throw new RuntimeException(e);}//3. 生成aid->java映射文件List<DependencyData> dataList = processor.getDependencyDataList();DependencyDataStore store = new DependencyDataStore();store.addData(dataList);try {store.saveTo(new File(getIncrementalFolder(), DEPENDENCY_STORE));} catch (IOException e) {throw new RuntimeException(e);}}@InputFiles@SkipWhenEmpty@PathSensitive(PathSensitivity.RELATIVE)public FileTree getSourceFiles() {// this is because aidl may be in the same folder as Java and we want to restrict to// .aidl files and not java files.return getProject().files(sourceDirs.get()).getAsFileTree().matching(PATTERN_SET);} }@InputFiles @SkipWhenEmpty @PathSensitive(PathSensitivity.RELATIVE) public FileTree getSourceFiles() {// this is because aidl may be in the same folder as Java and we want to restrict to// .aidl files and not java files.return getProject().files(sourceDirs.get()).getAsFileTree().matching(PATTERN_SET); }

    可以看到關鍵方法是compileAllFiles它是調用aidl工具生成了java源文件,進去看下

    public void compileAllAidlFiles(@NonNull Collection<File> sourceFolders,@NonNull File sourceOutputDir,@Nullable File packagedOutputDir,@Nullable Collection<String> packageWhiteList,@NonNull Collection<File> importFolders,@Nullable DependencyFileProcessor dependencyFileProcessor,@NonNull ProcessOutputHandler processOutputHandler)throws IOException, InterruptedException, ProcessException {//1. 校驗輸入參數checkNotNull(sourceFolders, "sourceFolders cannot be null.");checkNotNull(sourceOutputDir, "sourceOutputDir cannot be null.");checkNotNull(importFolders, "importFolders cannot be null.");checkState(mTargetInfo != null,"Cannot call compileAllAidlFiles() before setTargetInfo() is called.");IAndroidTarget target = mTargetInfo.getTarget();BuildToolInfo buildToolInfo = mTargetInfo.getBuildTools();//2. 關鍵點,獲取aidl工具路徑(先確定buildTool版本,在從buildTool工具包中找aidl工具包,見下圖);便于以后調用String aidl = buildToolInfo.getPath(BuildToolInfo.PathId.AIDL);if (aidl == null || !new File(aidl).isFile()) {throw new IllegalStateException("aidl is missing from '" + aidl + "'");}List<File> fullImportList = Lists.newArrayListWithCapacity(sourceFolders.size() + importFolders.size());fullImportList.addAll(sourceFolders);fullImportList.addAll(importFolders);//3. 構建一個aidl處理器,用來生成java文件AidlProcessor processor = new AidlProcessor(aidl,target.getPath(IAndroidTarget.ANDROID_AIDL),fullImportList,sourceOutputDir,packagedOutputDir,packageWhiteList,dependencyFileProcessor != null ?dependencyFileProcessor : DependencyFileProcessor.NO_OP,mProcessExecutor,processOutputHandler);//4. 對輸入的aidl文件集合進行遍歷,一次執行編譯操作for (File dir : sourceFolders) {DirectoryWalker.builder().root(dir.toPath()).extensions("aidl").action(processor).build().walk();} }

    操作流程

    DirectoryWalker.walk -> AidlProcessor.call -> GradleProcessExecutor.execute

    貼下AidlProcessor.call部分代碼

    public void call(@NonNull Path startDir, @NonNull Path path) throws IOException {ProcessInfoBuilder builder = new ProcessInfoBuilder();builder.setExecutable(mAidlExecutable);builder.addArgs("-p" + mFrameworkLocation);builder.addArgs("-o" + mSourceOutputDir.getAbsolutePath());// add all the library aidl folders to access parcelables that are in librariesfor (File f : mImportFolders) {builder.addArgs("-I" + f.getAbsolutePath());}// create a temp file for the dependencyFile depFile = File.createTempFile("aidl", ".d");builder.addArgs("-d" + depFile.getAbsolutePath());builder.addArgs(path.toAbsolutePath().toString());ProcessResult result = mProcessExecutor.execute(builder.createProcess(), mProcessOutputHandler);... }

    3. 映射文件

    簡單梳理下,第三部就是生成dependency.store文件了,這個就過了,大家有興趣自己看好啦。
    增量操作這里簡單說下主要分幾步操作

  • 讀取dependency.store文件,如果讀取失敗,直接走全量操作,并刪除dependency.store文件
  • 對changedInputs文件進行遍歷判斷
  • 文件新增 -> 直接進行編譯處理
  • 文件是刪除 -> 直接進行清理操作
  • 文件修改 -> 讀取文件依賴的所有選項,并對其進行編譯處理
  • 依賴任務:preBuildTask

    public AidlCompile createAidlTask(@NonNull VariantScope scope) {AidlCompile aidlCompileTask = taskFactory.create(new AidlCompile.ConfigAction(scope));scope.getTaskContainer().setAidlCompileTask(aidlCompileTask);scope.getTaskContainer().getSourceGenTask().dependsOn(aidlCompileTask);//依賴preBuildTaskaidlCompileTask.dependsOn(scope.getTaskContainer().getPreBuildTask());return aidlCompileTask; }

    Task4: compileDebugRenderscript

    1. RenderScript 概覽

    RenderScript 是用于在 Android 上以高性能運行計算密集型任務的框架。RenderScript 主要用于數據并行計算,不過串行工作負載也可以從中受益。RenderScript 運行時可在設備上提供的多個處理器(如多核 CPU 和 GPU)間并行調度工作。這樣您就能夠專注于表達算法而不是調度工作。RenderScript 對于執行圖像處理、計算攝影或計算機視覺的應用來說尤其有用。

    2. input/ouput

    taskName:compileDebugRenderscript input:/Users/apple/work/project/AndroidGradleTaskDemo/app/src/debug/rs input:/Users/apple/work/project/AndroidGradleTaskDemo/app/src/main/rs ========================================================= output:/Users/apple/work/project/AndroidGradleTaskDemo/app/build/intermediates/rs/debug/lib output:/Users/apple/work/project/AndroidGradleTaskDemo/app/build/intermediates/rs/debug/obj output:/Users/apple/work/project/AndroidGradleTaskDemo/app/build/generated/res/rs/debug output:/Users/apple/work/project/AndroidGradleTaskDemo/app/build/generated/source/rs/debug

    3. 核心類(RenderscriptCompile)

    套路和任務3差不多,調用工具(llvm-rs-cc)生成源文件

    核心代碼

    @TaskAction void taskAction() throws IOException, InterruptedException, ProcessException {// 1.預操作,清理作用// this is full run (always), clean the previous outputsFile sourceDestDir = getSourceOutputDir();FileUtils.cleanOutputDir(sourceDestDir);File resDestDir = getResOutputDir();FileUtils.cleanOutputDir(resDestDir);File objDestDir = getObjOutputDir();FileUtils.cleanOutputDir(objDestDir);File libDestDir = getLibOutputDir();FileUtils.cleanOutputDir(libDestDir);Set<File> sourceDirectories = sourceDirs.getFiles();//2. 編譯所有rs文件,套路和aidl差不多getBuilder().compileAllRenderscriptFiles(sourceDirectories,getImportFolders(),sourceDestDir,resDestDir,objDestDir,libDestDir,getTargetApi(),isDebugBuild(),getOptimLevel(),isNdkMode(),isSupportMode(),useAndroidX(),getNdkConfig() == null ? null : getNdkConfig().getAbiFilters(),new LoggedProcessOutputHandler(getILogger()));}

    編譯關鍵代碼

    具體細節不再闡述了,大家有興趣自己看源碼

    👇
    Android構建流程——上篇
    Android構建流程——下篇

    參考鏈接

    https://developer.android.com/studio/build/dependencies#resolution_errors

    compileOnly的限制

    Android新配置說明

    https://developer.android.com/guide/topics/renderscript/compute?hl=zh-cn

    總結

    以上是生活随笔為你收集整理的Android构建流程——篇二的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。