diff --git a/.gitignore b/.gitignore index 20c8c87..fa5f81f 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ /DexKnifePlugin/.idea/qaplug_profiles.xml /DexKnifePlugin/.idea/runConfigurations.xml /DexKnifePlugin/.idea/vcs.xml +.idea/ diff --git a/DexKnifePlugin/app/build.gradle b/DexKnifePlugin/app/build.gradle index 6a761f9..aa8d0ba 100644 --- a/DexKnifePlugin/app/build.gradle +++ b/DexKnifePlugin/app/build.gradle @@ -2,18 +2,28 @@ apply plugin: 'com.android.application' apply plugin: 'dexknifePlus' android { - compileSdkVersion Integer.parseInt(project.COMPILE_SDK_VER) - buildToolsVersion project.BUILD_TOOLS_VER + compileSdkVersion 23 + buildToolsVersion '23.0.3' defaultConfig { - minSdkVersion Integer.parseInt(project.MIN_SDK_VER) - targetSdkVersion Integer.parseInt(project.TARGET_SDK_VERSION) + minSdkVersion 14 + targetSdkVersion 23 versionCode 1 versionName "1.0" multiDexEnabled true } + //签名 + signingConfigs { + key { + storeFile file('mutidex.jks') + storePassword '123456' + keyAlias 'king' + keyPassword '123456' + } + } + productFlavors{ dev{ @@ -26,12 +36,13 @@ android { buildTypes { release { - minifyEnabled false + minifyEnabled true + signingConfig signingConfigs.key proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } debug { -// minifyEnabled true + minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } @@ -48,7 +59,7 @@ dexKnife{ //1.如果没有可选参数,将根据enabled决定是否分包。 //2.如果有可选参数,需满足必选参数和可选参数的条件才允许分包 productFlavor 'mock' - buildType 'debug' + //buildType 'debug' /* *eg:当前productFlavors = dev,buildType = debug, diff --git a/DexKnifePlugin/app/dexknife.txt b/DexKnifePlugin/app/dexknife.txt index a377126..c6e76f4 100644 --- a/DexKnifePlugin/app/dexknife.txt +++ b/DexKnifePlugin/app/dexknife.txt @@ -1,10 +1,10 @@ #为注释符 -#-----------主Dex中必要依赖的脚本配置----------- -#默认保留四大组件中其他三大组件(并计算其依赖树),Activity组件选择性保留(使用-just activity 选项),若为空不保留任何Activity +#-----------主Dex中必要依赖的脚本配置-----------(支持依赖检测) +#默认保留四大组件中Service,ContentProvider,BroadcastReceiver三大组件,Activity组件选择性保留,若为空不保留任何Activity -just activity com.ceabie.demo.MainActivity -#-----------附加类----------- +#-----------附加类-----------(不支持依赖检测) # 如果你想要某个包路径在maindex中,则使用 -keep 选项,即使他已经在分包的路径中.若为空,不保留任意类 #-keep com.ceabie.demo.** @@ -24,7 +24,7 @@ # 表明限制的方法数小于main dex的必要方法数,调大到合适数值即可 -dex-param --set-max-idx-number=4000 -# 不进行dex分包, 直到 dex 的id数量超过 65536.(设置自动执行分包策略) +# 注释掉将执行自定义dex分包,否则执行默认分包. #-auto-maindex # 显示miandex的日志. diff --git a/DexKnifePlugin/app/mutidex.jks b/DexKnifePlugin/app/mutidex.jks new file mode 100644 index 0000000..ed54544 Binary files /dev/null and b/DexKnifePlugin/app/mutidex.jks differ diff --git a/DexKnifePlugin/app/src/main/res/values/strings.xml b/DexKnifePlugin/app/src/main/res/values/strings.xml index 8d40eb8..0a5576f 100644 --- a/DexKnifePlugin/app/src/main/res/values/strings.xml +++ b/DexKnifePlugin/app/src/main/res/values/strings.xml @@ -1,5 +1,5 @@ - demo + MultiDexPluginApp Hello world! Settings diff --git a/DexKnifePlugin/build.gradle b/DexKnifePlugin/build.gradle index d88678c..0e9a366 100644 --- a/DexKnifePlugin/build.gradle +++ b/DexKnifePlugin/build.gradle @@ -1,12 +1,13 @@ buildscript { repositories { + //maven { url uri('./repo') } jcenter() mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:2.2.0' - classpath 'com.library.tangxiaolv:dexknife-plus:1.0.1' + classpath 'com.android.tools.build:gradle:2.2.3' + classpath 'com.library.tangxiaolv:dexknife-plus:1.0.3' } } diff --git a/DexKnifePlugin/dexknife-plus/build.gradle b/DexKnifePlugin/dexknife-plus/build.gradle index 3aafa1b..02e3c83 100644 --- a/DexKnifePlugin/dexknife-plus/build.gradle +++ b/DexKnifePlugin/dexknife-plus/build.gradle @@ -25,6 +25,7 @@ configurations { dependencies { compile gradleApi() compile localGroovy() + compile 'com.ceabie.dextools:gradle-dexknife-plugin:1.6.2' provided 'com.android.tools.build:builder:2.1.3' provided 'com.android.tools.build:gradle-core:2.1.3' } diff --git a/DexKnifePlugin/dexknife-plus/gradle.properties b/DexKnifePlugin/dexknife-plus/gradle.properties index 184c457..2f24490 100644 --- a/DexKnifePlugin/dexknife-plus/gradle.properties +++ b/DexKnifePlugin/dexknife-plus/gradle.properties @@ -1,6 +1,6 @@ #Gradle:groupId:libraryName:publicVersion LOCAL_VERSION=0.0.5 -PUBLIC_VERSION=1.0.1 +PUBLIC_VERSION=1.0.4 GROUP_ID=com.library.tangxiaolv #Modelһ LIBRARY_NAME=dexknife-plus diff --git a/DexKnifePlugin/dexknife-plus/src/main/groovy/com/ceabie/dexknife/ClassFileTreeElement.java b/DexKnifePlugin/dexknife-plus/src/main/groovy/com/ceabie/dexknife/ClassFileTreeElement.java deleted file mode 100644 index f08b325..0000000 --- a/DexKnifePlugin/dexknife-plus/src/main/groovy/com/ceabie/dexknife/ClassFileTreeElement.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (C) 2016 ceabie (https://github.com/ceabie/) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ceabie.dexknife; - -import org.gradle.api.file.FileTreeElement; -import org.gradle.api.file.RelativePath; -import org.gradle.internal.nativeintegration.filesystem.FileSystem; - -import java.io.File; -import java.io.InputStream; -import java.io.OutputStream; - -/** - * Mock the file tree element of Filter. - * - * @author ceabie - */ -public class ClassFileTreeElement implements FileTreeElement { - private RelativePath mRelativePath; - private File mFile; - - public void setClassPath(String name) { - mFile = new File(name); - mRelativePath = RelativePath.parse(!isDirectory(), name); - } - - @Override - public File getFile() { - return mFile; - } - - @Override - public boolean isDirectory() { - return false; - } - - @Override - public long getLastModified() { - return 0; - } - - @Override - public long getSize() { - return 0; - } - - @Override - public InputStream open() { -// try { -// return mZipFile.getInputStream(mZipEntry); -// } catch (IOException e) { -// e.printStackTrace(); -// } - - return null; - } - - @Override - public void copyTo(OutputStream outputStream) { - } - - @Override - public boolean copyTo(File file) { - return true; - } - - @Override - public String getName() { - return mFile.getName(); - } - - @Override - public String getPath() { - return mFile.getPath(); - } - - @Override - public RelativePath getRelativePath() { - return mRelativePath; - } - - @Override - public int getMode() { - return isDirectory() - ? FileSystem.DEFAULT_DIR_MODE - : FileSystem.DEFAULT_FILE_MODE; - } -} diff --git a/DexKnifePlugin/dexknife-plus/src/main/groovy/com/ceabie/dexknife/DexKnifeConfig.java b/DexKnifePlugin/dexknife-plus/src/main/groovy/com/ceabie/dexknife/DexKnifeConfig.java deleted file mode 100644 index 8fc9018..0000000 --- a/DexKnifePlugin/dexknife-plus/src/main/groovy/com/ceabie/dexknife/DexKnifeConfig.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2016 ceabie (https://github.com/ceabie/) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ceabie.dexknife; - -import org.gradle.api.tasks.util.PatternSet; - -import java.util.Set; - -/** - * The type Dex knife config. - * - * @author ceabie - */ -public class DexKnifeConfig { - PatternSet patternSet; - PatternSet suggestPatternSet; - boolean useSuggest = true; - boolean filterSuggest = false; - boolean logMainList = false; - boolean logFilterSuggest = false; - Set additionalParameters; -} diff --git a/DexKnifePlugin/dexknife-plus/src/main/groovy/com/ceabie/dexknife/DexSplitTools.java b/DexKnifePlugin/dexknife-plus/src/main/groovy/com/ceabie/dexknife/DexSplitTools.java deleted file mode 100644 index a545af3..0000000 --- a/DexKnifePlugin/dexknife-plus/src/main/groovy/com/ceabie/dexknife/DexSplitTools.java +++ /dev/null @@ -1,486 +0,0 @@ -/* - * Copyright (C) 2016 ceabie (https://github.com/ceabie/) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.ceabie.dexknife; - -import org.gradle.api.Project; -import org.gradle.api.file.FileTreeElement; -import org.gradle.api.specs.Spec; -import org.gradle.api.specs.Specs; -import org.gradle.api.tasks.util.PatternSet; - -import java.io.*; -import java.util.*; -import java.util.regex.Pattern; -import java.util.zip.ZipEntry; -import java.util.zip.ZipFile; - -/** - * the base of spilt tools. - * - * @author ceabie - */ -public class DexSplitTools { - - public static final String DEX_KNIFE_CFG_TXT = "dexknife.txt"; - - private static final String DEX_MINIMAL_MAIN_DEX = "--minimal-main-dex"; - - private static final String DEX_KNIFE_CFG_DEX_PARAM = "-dex-param"; - private static final String DEX_KNIFE_CFG_SPLIT = "-split"; - private static final String DEX_KNIFE_CFG_KEEP = "-keep"; - private static final String DEX_KNIFE_CFG_AUTO_MAINDEX = "-auto-maindex"; - private static final String DEX_KNIFE_CFG_DONOT_USE_SUGGEST = "-donot-use-suggest"; - private static final String DEX_KNIFE_CFG_LOG_MAIN_DEX = "-log-mainlist"; - private static final String DEX_KNIFE_CFG_FILTER_SUGGEST = "-filter-suggest"; - private static final String DEX_KNIFE_CFG_SUGGEST_SPLIT = "-suggest-split"; - private static final String DEX_KNIFE_CFG_SUGGEST_KEEP = "-suggest-keep"; - private static final String DEX_KNIFE_CFG_LOG_FILTER_SUGGEST = "-log-filter-suggest"; - - private static final String MAINDEXLIST_TXT = "maindexlist.txt"; - private static final String MAPPING_FLAG = " -> "; - private static final int MAPPING_FLAG_LEN = MAPPING_FLAG.length(); - private static final String CLASS_SUFFIX = ".class"; - - private static long StartTime = 0; - - protected static void startDexKnife() { - System.out.println("DexKnife Processing ..."); - StartTime = System.currentTimeMillis(); - } - - protected static void endDexKnife() { - String time; - long internal = System.currentTimeMillis() - StartTime; - if (internal > 1000) { - float i = internal / 1000; - if (i >= 60) { - i = i / 60; - int min = (int) i; - time = min + " min " + (i - min) + " s"; - } else { - time = i + "s"; - } - } else { - time = internal + "ms"; - } - - System.out.println("DexKnife Finished: " + time); - } - - public static boolean processMainDexList(Project project, boolean minifyEnabled, - File mappingFile, - File jarMergingOutputFile, File andMainDexList, - DexKnifeConfig dexKnifeConfig) throws Exception { - - if (!minifyEnabled && jarMergingOutputFile == null) { - System.out.println( - "DexKnife Error: jarMerging is Null! Skip DexKnife. Please report All Gradle Log."); - return false; - } - - return genMainDexList(project, minifyEnabled, mappingFile, jarMergingOutputFile, - andMainDexList, dexKnifeConfig); - } - - /** - * get the config of dex knife - * - * @param project project - * @return DexKnifeConfig - * @throws Exception exception - */ - protected static DexKnifeConfig getDexKnifeConfig(Project project) throws Exception { - BufferedReader reader = new BufferedReader(new FileReader(project.file(DEX_KNIFE_CFG_TXT))); - DexKnifeConfig dexKnifeConfig = new DexKnifeConfig(); - - String line; - boolean matchCmd; - boolean minimalMainDex = true; - Set addParams = new HashSet<>(); - - Set splitToSecond = new HashSet<>(); - Set keepMain = new HashSet<>(); - Set splitSuggest = new HashSet<>(); - Set keepSuggest = new HashSet<>(); - - while ((line = reader.readLine()) != null) { - line = line.trim(); - if (line.length() == 0) { - continue; - } - - int rem = line.indexOf('#'); - if (rem != -1) { - if (rem == 0) { - continue; - } else { - line = line.substring(0, rem).trim(); - } - } - - String cmd = line.toLowerCase(); - matchCmd = true; - - if (DEX_KNIFE_CFG_AUTO_MAINDEX.equals(cmd)) { - minimalMainDex = false; - } else if (matchCommand(cmd, DEX_KNIFE_CFG_DEX_PARAM)) { - String param = line.substring(DEX_KNIFE_CFG_DEX_PARAM.length()).trim(); - if (!param.toLowerCase().startsWith("--main-dex-list")) { - addParams.add(param); - } - - } else if (matchCommand(cmd, DEX_KNIFE_CFG_SPLIT)) { - String sPattern = line.substring(DEX_KNIFE_CFG_SPLIT.length()).trim(); - addClassFilePath(sPattern, splitToSecond); - - } else if (matchCommand(cmd, DEX_KNIFE_CFG_KEEP)) { - String sPattern = line.substring(DEX_KNIFE_CFG_KEEP.length()).trim(); - addClassFilePath(sPattern, keepMain); - - } else if (DEX_KNIFE_CFG_DONOT_USE_SUGGEST.equals(cmd)) { - dexKnifeConfig.useSuggest = false; - - } else if (DEX_KNIFE_CFG_FILTER_SUGGEST.equals(cmd)) { - dexKnifeConfig.filterSuggest = true; - - } else if (DEX_KNIFE_CFG_LOG_MAIN_DEX.equals(cmd)) { - dexKnifeConfig.logMainList = true; - - } else if (DEX_KNIFE_CFG_LOG_FILTER_SUGGEST.equals(cmd)) { - dexKnifeConfig.logFilterSuggest = true; - - } else if (matchCommand(cmd, DEX_KNIFE_CFG_SUGGEST_SPLIT)) { - String sPattern = line.substring(DEX_KNIFE_CFG_SUGGEST_SPLIT.length()).trim(); - addClassFilePath(sPattern, splitSuggest); - - } else if (matchCommand(cmd, DEX_KNIFE_CFG_SUGGEST_KEEP)) { - String sPattern = line.substring(DEX_KNIFE_CFG_SUGGEST_KEEP.length()).trim(); - addClassFilePath(sPattern, keepSuggest); - - } else if (!cmd.startsWith("-")) { - addClassFilePath(line, splitToSecond); - } else { - matchCmd = false; - } - - if (matchCmd) { - System.out.println("DexKnife Config: " + line); - } - } - - reader.close(); - - if (minimalMainDex) { - addParams.add(DEX_MINIMAL_MAIN_DEX); - } - - if (dexKnifeConfig.useSuggest) { - if (dexKnifeConfig.filterSuggest) { - splitSuggest.addAll(splitToSecond); - keepSuggest.addAll(keepMain); - } - - // for (String s : splitSuggest) { - // System.out.println("Suggest: " + s); - // } - - if (!splitSuggest.isEmpty() || !keepSuggest.isEmpty()) { - dexKnifeConfig.suggestPatternSet = new PatternSet() - .exclude(splitSuggest) - .include(keepSuggest); - } - } - - if (!splitToSecond.isEmpty() || !keepMain.isEmpty()) { - // for (String s : splitToSecond) { - // System.out.println(s); - // } - dexKnifeConfig.patternSet = new PatternSet() - .exclude(splitToSecond) - .include(keepMain); - } else { - dexKnifeConfig.useSuggest = true; - System.err.println("DexKnife Warning: NO SET split Or keep path, it will use Suggest!"); - } - - dexKnifeConfig.additionalParameters = addParams; - - return dexKnifeConfig; - } - - private static boolean matchCommand(String text, String cmd) { - Pattern pattern = Pattern.compile("^" + cmd + "\\s+"); - return pattern.matcher(text).find(); - } - - /** - * add the class path to pattern list, and the single class pattern can work. - */ - private static void addClassFilePath(String classPath, Set patternList) { - if (classPath != null && classPath.length() > 0) { - if (classPath.endsWith(CLASS_SUFFIX)) { - classPath = classPath.substring(0, classPath.length() - CLASS_SUFFIX.length()) - .replace('.', '/') + CLASS_SUFFIX; - } else { - classPath = classPath.replace('.', '/'); - } - - patternList.add(classPath); - } - } - - private static Spec getMaindexSpec(PatternSet patternSet) { - Spec maindexSpec = null; - - if (patternSet != null) { - Spec includeSpec = null; - Spec excludeSpec = null; - - if (!patternSet.getIncludes().isEmpty()) { - includeSpec = patternSet.getAsIncludeSpec(); - } - - if (!patternSet.getExcludes().isEmpty()) { - excludeSpec = patternSet.getAsExcludeSpec(); - } - - if (includeSpec != null && excludeSpec != null) { - maindexSpec = Specs.or(includeSpec, Specs.not(excludeSpec)); - } else { - if (excludeSpec == null) { - maindexSpec = Specs.satisfyAll(); - } else { - maindexSpec = Specs.not(excludeSpec); - } - } - } - - if (maindexSpec == null) { - maindexSpec = Specs.satisfyAll(); - } - - return maindexSpec; - } - - /** - * generate the main dex list - */ - private static boolean genMainDexList(Project project, boolean minifyEnabled, - File mappingFile, File jarMergingOutputFile, - File andMainDexList, DexKnifeConfig dexKnifeConfig) throws Exception { - - System.out.println(":" + project.getName() + ":genMainDexList"); - - // get the adt's maindexlist - HashSet mainCls = null; - if (dexKnifeConfig.useSuggest) { - - PatternSet patternSet = dexKnifeConfig.suggestPatternSet; - if (dexKnifeConfig.filterSuggest && patternSet == null) { - patternSet = dexKnifeConfig.patternSet; - } - - mainCls = getAdtMainDexClasses(andMainDexList, patternSet, - dexKnifeConfig.logFilterSuggest); - System.out.println("DexKnife: use suggest"); - } - - File keepFile = project.file(MAINDEXLIST_TXT); - keepFile.delete(); - - ArrayList mainClasses = null; - if (minifyEnabled) { - System.err.println("DexKnife: From Mapping"); - // get classes from mapping - mainClasses = getMainClassesFromMapping(mappingFile, dexKnifeConfig.patternSet, - mainCls); - } else { - System.out.println("DexKnife: From MergedJar: " + jarMergingOutputFile); - if (jarMergingOutputFile != null) { - // get classes from merged jar - mainClasses = getMainClassesFromJar(jarMergingOutputFile, dexKnifeConfig.patternSet, - mainCls); - } else { - System.err.println("DexKnife: The Merged Jar is not exist! Can't be processed!"); - } - } - - if (mainClasses != null && mainClasses.size() > 0) { - BufferedWriter writer = new BufferedWriter(new FileWriter(keepFile)); - - for (String mainClass : mainClasses) { - writer.write(mainClass); - writer.newLine(); - - if (dexKnifeConfig.logMainList) { - System.out.println(mainClass); - } - } - - writer.close(); - - return true; - } - - throw new Exception("DexKnife Warning: Main dex is EMPTY ! Check your config and project!"); - } - - private static ArrayList getMainClassesFromJar( - File jarMergingOutputFile, PatternSet mainDexPattern, HashSet mainCls) - throws Exception { - ZipFile clsFile = new ZipFile(jarMergingOutputFile); - Spec asSpec = getMaindexSpec(mainDexPattern); - ClassFileTreeElement treeElement = new ClassFileTreeElement(); - - ArrayList mainDexList = new ArrayList<>(); - Enumeration entries = clsFile.entries(); - while (entries.hasMoreElements()) { - ZipEntry entry = entries.nextElement(); - String entryName = entry.getName(); - - if (entryName.endsWith(CLASS_SUFFIX)) { - treeElement.setClassPath(entryName); - - if (asSpec.isSatisfiedBy(treeElement) - || (mainCls != null && mainCls.contains(entryName))) { - mainDexList.add(entryName); - } - } - } - - clsFile.close(); - - return mainDexList; - } - - /** - * Gets main classes from mapping. - * - * @param mapping the mapping file - * @param mainDexPattern the main dex pattern - * @param mainCls the main cls - * @return the main classes from mapping - * @throws Exception the exception - * @author ceabie - */ - private static ArrayList getMainClassesFromMapping( - File mapping, - PatternSet mainDexPattern, - HashSet mainCls) throws Exception { - - String line; - ArrayList mainDexList = new ArrayList<>(); - BufferedReader reader = new BufferedReader(new FileReader(mapping)); - - ClassFileTreeElement treeElement = new ClassFileTreeElement(); - Spec asSpec = getMaindexSpec(mainDexPattern); - - while ((line = reader.readLine()) != null) { - line = line.trim(); - - if (line.endsWith(":")) { - int flagPos = line.indexOf(MAPPING_FLAG); - if (flagPos != -1) { - - String sOrg = line.substring(0, flagPos).replace('.', '/') + CLASS_SUFFIX; - treeElement.setClassPath(sOrg); - - if (asSpec.isSatisfiedBy(treeElement) - || (mainCls != null && mainCls.contains(sOrg))) { - String sMap = line.substring(flagPos + MAPPING_FLAG_LEN, line.length() - 1) - .replace('.', '/') + CLASS_SUFFIX; - - mainDexList.add(sMap); - } - } - } - } - - reader.close(); - - return mainDexList; - } - - /** - * get the maindexlist of android gradle plugin - */ - private static HashSet getAdtMainDexClasses(File outputDir, PatternSet mainDexPattern, - boolean logFilter) - throws Exception { - if (outputDir == null || !outputDir.exists()) { - System.err.println( - "DexKnife Warning: Android recommand Main dex is no exist, try run again!"); - return null; - } - - HashSet mainCls = new HashSet<>(); - BufferedReader reader = new BufferedReader(new FileReader(outputDir)); - - ClassFileTreeElement treeElement = new ClassFileTreeElement(); - Spec asSpec = mainDexPattern != null ? getMaindexSpec(mainDexPattern) - : null; - - String line, clsPath; - while ((line = reader.readLine()) != null) { - line = line.trim(); - int clsPos = line.lastIndexOf(CLASS_SUFFIX); - if (clsPos != -1) { - if (asSpec != null) { - clsPath = line.substring(0, clsPos).replace('.', '/') + CLASS_SUFFIX; - treeElement.setClassPath(clsPath); - - boolean satisfiedBy = asSpec.isSatisfiedBy(treeElement); - if (!satisfiedBy) { - if (logFilter) - System.out.println("DexKnife-Suggest: [Split] " + clsPath); - continue; - } - - if (logFilter) - System.out.println("DexKnife-Suggest: [Keep] " + clsPath); - } - - mainCls.add(line); - } - } - - reader.close(); - - if (mainCls.size() == 0) { - mainCls = null; - } - - return mainCls; - } - - static int getAndroidPluginVersion(String version) { - int size = version.length(); - int ver = 0; - for (int i = 0; i < size; i++) { - char c = version.charAt(i); - if (Character.isDigit(c) || c == '.') { - if (c != '.') { - ver = ver * 10 + c - '0'; - } - } else { - break; - } - } - - return ver; - } -} diff --git a/DexKnifePlugin/dexknife-plus/src/main/groovy/com/ceabie/dexknife/InjectAndroidBuilder.groovy b/DexKnifePlugin/dexknife-plus/src/main/groovy/com/ceabie/dexknife/InjectAndroidBuilder.groovy deleted file mode 100644 index 5651173..0000000 --- a/DexKnifePlugin/dexknife-plus/src/main/groovy/com/ceabie/dexknife/InjectAndroidBuilder.groovy +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright (C) 2016 ceabie (https://github.com/ceabie/) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ceabie.dexknife - -import com.android.build.gradle.internal.transforms.DexTransform -import com.android.builder.core.AndroidBuilder -import com.android.builder.core.DexOptions -import com.android.builder.core.ErrorReporter -import com.android.builder.sdk.TargetInfo -import com.android.ide.common.process.JavaProcessExecutor -import com.android.ide.common.process.ProcessException -import com.android.ide.common.process.ProcessExecutor -import com.android.ide.common.process.ProcessOutputHandler -import com.android.utils.ILogger -import groovy.transform.CompileStatic - -import java.lang.reflect.Field - -/** - * proxy the androidBuilder that plugin 1.5.0 to add '--minimal-main-dex' options. - * - * @author ceabie - */ -public class InjectAndroidBuilder extends AndroidBuilder { - - Collection mAddParams; - AndroidBuilder mAndroidBuilder; - - public InjectAndroidBuilder(String projectId, - String createdBy, - ProcessExecutor processExecutor, - JavaProcessExecutor javaProcessExecutor, - ErrorReporter errorReporter, - ILogger logger, - boolean verboseExec) { - super(projectId, createdBy, processExecutor, javaProcessExecutor, errorReporter, logger, verboseExec) - } - -// @Override // for < 2.2.0 - public void convertByteCode(Collection inputs, - File outDexFolder, - boolean multidex, - File mainDexList, - DexOptions dexOptions, - List additionalParameters, - boolean incremental, - boolean optimize, - ProcessOutputHandler processOutputHandler) - throws IOException, InterruptedException, ProcessException { - - println("DexKnife: convertByteCode before 2.2.0") - if (mAddParams != null) { - if (additionalParameters == null) { - additionalParameters = new ArrayList<>() - } - - mergeParams(additionalParameters, mAddParams) - } - - // groovy call super has bug - mAndroidBuilder.convertByteCode(inputs, outDexFolder, multidex, mainDexList, dexOptions, - additionalParameters, incremental, optimize, processOutputHandler); - } - -// @Override for >= 2.2.0 - public void convertByteCode(Collection inputs, - File outDexFolder, - boolean multidex, - File mainDexList, - final DexOptions dexOptions, - boolean optimize, - ProcessOutputHandler processOutputHandler) - throws IOException, InterruptedException, ProcessException { - - println("DexKnife:convertByteCode after 2.2.0") - - DexOptions dexOptionsProxy = dexOptions - - if (mAddParams != null) { - List additionalParameters = dexOptions.getAdditionalParameters() - if (additionalParameters == null) { - additionalParameters = new ArrayList<>() - } - - mergeParams(additionalParameters, mAddParams) - } - - mAndroidBuilder.convertByteCode(inputs, outDexFolder, multidex, mainDexList, dexOptionsProxy, - optimize, processOutputHandler); - } - - @CompileStatic - @Override - List getBootClasspath(boolean includeOptionalLibraries) { - return mAndroidBuilder.getBootClasspath(includeOptionalLibraries) - } - - @CompileStatic - @Override - List getBootClasspathAsStrings(boolean includeOptionalLibraries) { - return mAndroidBuilder.getBootClasspathAsStrings(includeOptionalLibraries) - } - - - @CompileStatic - static void mergeParams(List additionalParameters, Collection addParams) { - List mergeParam = new ArrayList<>() - for (String param : addParams) { - if (!additionalParameters.contains(param)) { - mergeParam.add(param) - } - } - - if (mergeParam.size() > 0) { - additionalParameters.addAll(mergeParam) - } - } - - - public static void proxyAndroidBuilder(DexTransform transform, Collection addParams) { - if (addParams != null && addParams.size() > 0) { - accessibleField(DexTransform.class, "androidBuilder") - .set(transform, getProxyAndroidBuilder(transform.androidBuilder, addParams)) - } - } - - private static AndroidBuilder getProxyAndroidBuilder(AndroidBuilder orgAndroidBuilder, - Collection addParams) { - InjectAndroidBuilder myAndroidBuilder = new InjectAndroidBuilder( - orgAndroidBuilder.mProjectId, - orgAndroidBuilder.mCreatedBy, - orgAndroidBuilder.getProcessExecutor(), - orgAndroidBuilder.mJavaProcessExecutor, - orgAndroidBuilder.getErrorReporter(), - orgAndroidBuilder.getLogger(), - orgAndroidBuilder.mVerboseExec) - - // if >= 2.2.0 - def to = myAndroidBuilder.respondsTo("setTargetInfo", TargetInfo.class) - if (to.size() > 0) { - myAndroidBuilder.setTargetInfo(orgAndroidBuilder.getTargetInfo()) - myAndroidBuilder.setSdkInfo(orgAndroidBuilder.getSdkInfo()) - myAndroidBuilder.setLibraryRequests(orgAndroidBuilder.mLibraryRequests) - } else { - myAndroidBuilder.setTargetInfo( - orgAndroidBuilder.getSdkInfo(), - orgAndroidBuilder.getTargetInfo(), - orgAndroidBuilder.mLibraryRequests) - } - - myAndroidBuilder.mAddParams = addParams - myAndroidBuilder.mAndroidBuilder = orgAndroidBuilder -// myAndroidBuilder.mBootClasspathFiltered = orgAndroidBuilder.mBootClasspathFiltered -// myAndroidBuilder.mBootClasspathAll = orgAndroidBuilder.mBootClasspathAll - - return myAndroidBuilder - } - - @CompileStatic - private static Field accessibleField(Class cls, String field) { - Field f = cls.getDeclaredField(field) - f.setAccessible(true) - return f - } -} diff --git a/DexKnifePlugin/dexknife-plus/src/main/groovy/com/ceabie/dexknife/SplitToolsFor130.groovy b/DexKnifePlugin/dexknife-plus/src/main/groovy/com/ceabie/dexknife/SplitToolsFor130.groovy deleted file mode 100644 index 58fdba5..0000000 --- a/DexKnifePlugin/dexknife-plus/src/main/groovy/com/ceabie/dexknife/SplitToolsFor130.groovy +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (C) 2016 ceabie (https://github.com/ceabie/) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ceabie.dexknife - -import org.gradle.api.Project - -/** - * the spilt tools for plugin 1.3.0. - * - * @author ceabie - */ -public class SplitToolsFor130 extends DexSplitTools { - - public static boolean isCompat(Object variant) { - try { - if (variant != null) { - variant.dex - - return true - } - } catch (RuntimeException e) { -// e.printStackTrace() - } - - return false - } - - public static void processSplitDex(Project project, Object variant) { - def dex = variant.dex - if (dex.multiDexEnabled) { - dex.inputs.file DEX_KNIFE_CFG_TXT - - dex.doFirst { - startDexKnife() - - DexKnifeConfig dexKnifeConfig = getDexKnifeConfig(project) - - def scope = variant.getVariantData().getScope() - File mergedJar = scope.jarMergingOutputFile - File mappingFile = variant.mappingFile - File andMainDexList = scope.mainDexListFile - boolean minifyEnabled = variant.buildType.minifyEnabled - - if (processMainDexList(project, minifyEnabled, mappingFile, mergedJar, - andMainDexList, dexKnifeConfig)) { - if (dex.additionalParameters == null) { - dex.additionalParameters = [] - } - - dex.additionalParameters += '--main-dex-list=maindexlist.txt' - dex.additionalParameters += dexKnifeConfig.additionalParameters - } - - endDexKnife() - } - } - } -} \ No newline at end of file diff --git a/DexKnifePlugin/dexknife-plus/src/main/groovy/com/ceabie/dexknife/SplitToolsFor150.groovy b/DexKnifePlugin/dexknife-plus/src/main/groovy/com/ceabie/dexknife/SplitToolsFor150.groovy deleted file mode 100644 index e555460..0000000 --- a/DexKnifePlugin/dexknife-plus/src/main/groovy/com/ceabie/dexknife/SplitToolsFor150.groovy +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright (C) 2016 ceabie (https://github.com/ceabie/) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ceabie.dexknife - -import com.android.build.api.transform.Format -import com.android.build.api.transform.Transform -import com.android.build.gradle.api.ApplicationVariant -import com.android.build.gradle.internal.incremental.InstantRunBuildContext -import com.android.build.gradle.internal.pipeline.TransformTask -import com.android.build.gradle.internal.transforms.DexTransform -import org.gradle.api.Project - -/** - * the spilt tools for plugin 1.5.0. - * - * @author ceabie - */ -public class SplitToolsFor150 extends DexSplitTools { - - public static boolean isCompat() { -// if (getAndroidPluginVersion() < 200) { -// return true; -// } - - return true; - } - - public static void processSplitDex(Project project, ApplicationVariant variant) { - if (isInInstantRunMode(variant)) { - System.err.println("DexKnife: Instant Run mode, DexKnife is auto disabled!") - return - } - - TransformTask dexTask -// TransformTask proGuardTask - TransformTask jarMergingTask - - String name = variant.name.capitalize() - boolean minifyEnabled = variant.buildType.minifyEnabled - - // find the task we want to process - project.tasks.matching { - ((it instanceof TransformTask) && it.name.endsWith(name)) // TransformTask - }.each { TransformTask theTask -> - Transform transform = theTask.transform - String transformName = transform.name - -// if (minifyEnabled && "proguard".equals(transformName)) { // ProGuardTransform -// proGuardTask = theTask -// } else - if ("jarMerging".equalsIgnoreCase(transformName)) { - jarMergingTask = theTask - } else if ("dex".equalsIgnoreCase(transformName)) { // DexTransform - dexTask = theTask - } - } - - if (dexTask != null && ((DexTransform) dexTask.transform).multiDex) { - dexTask.inputs.file DEX_KNIFE_CFG_TXT - - dexTask.doFirst { - startDexKnife() - - File mergedJar = null - File mappingFile = variant.mappingFile - DexTransform dexTransform = it.transform - File fileAdtMainList = dexTransform.mainDexListFile - - println("DexKnife Adt Main: " + fileAdtMainList) - - DexKnifeConfig dexKnifeConfig = getDexKnifeConfig(project) - - // 非混淆的,从合并后的jar文件中提起mainlist; - // 混淆的,直接从mapping文件中提取 - if (minifyEnabled) { - println("DexKnife-From Mapping: " + mappingFile) - } else { - if (jarMergingTask != null) { - Transform transform = jarMergingTask.transform - def outputProvider = jarMergingTask.outputStream.asOutput() - mergedJar = outputProvider.getContentLocation("combined", - transform.getOutputTypes(), - transform.getScopes(), Format.JAR) - } - - println("DexKnife-From MergedJar: " + mergedJar) - } - - if (processMainDexList(project, minifyEnabled, mappingFile, mergedJar, - fileAdtMainList, dexKnifeConfig)) { - - int version = getAndroidPluginVersion(getAndroidGradlePluginVersion()) - println("DexKnife: AndroidPluginVersion: " + version) - - // after 2.2.0, it can additionalParameters, but it is a copy in task - - // 替换 AndroidBuilder - InjectAndroidBuilder.proxyAndroidBuilder(dexTransform, - dexKnifeConfig.additionalParameters) - - // 替换这个文件 - fileAdtMainList.delete() - project.copy { - from 'maindexlist.txt' - into fileAdtMainList.parentFile - } - } - - endDexKnife() - } - } - } - - private static boolean isInInstantRunMode(Object variant) { - try { - def scope = variant.getVariantData().getScope() - InstantRunBuildContext instantRunBuildContext = scope.getInstantRunBuildContext() - return instantRunBuildContext.isInInstantRunMode() - } catch (Throwable e) { - } - - return false - } -} \ No newline at end of file diff --git a/DexKnifePlugin/dexknife-plus/src/main/groovy/com/ceabie/dexknife/DexKnifeExtension.groovy b/DexKnifePlugin/dexknife-plus/src/main/groovy/com/tangxiaolv/dexknife/DexKnifeExtension.groovy similarity index 77% rename from DexKnifePlugin/dexknife-plus/src/main/groovy/com/ceabie/dexknife/DexKnifeExtension.groovy rename to DexKnifePlugin/dexknife-plus/src/main/groovy/com/tangxiaolv/dexknife/DexKnifeExtension.groovy index dffcbf0..31795a9 100644 --- a/DexKnifePlugin/dexknife-plus/src/main/groovy/com/ceabie/dexknife/DexKnifeExtension.groovy +++ b/DexKnifePlugin/dexknife-plus/src/main/groovy/com/tangxiaolv/dexknife/DexKnifeExtension.groovy @@ -1,4 +1,4 @@ -package com.ceabie.dexknife +package com.tangxiaolv.dexknife class DexKnifeExtension { boolean enabled = false diff --git a/DexKnifePlugin/dexknife-plus/src/main/groovy/com/ceabie/dexknife/DexKnifePlugin.groovy b/DexKnifePlugin/dexknife-plus/src/main/groovy/com/tangxiaolv/dexknife/DexKnifePlusPlugin.groovy similarity index 75% rename from DexKnifePlugin/dexknife-plus/src/main/groovy/com/ceabie/dexknife/DexKnifePlugin.groovy rename to DexKnifePlugin/dexknife-plus/src/main/groovy/com/tangxiaolv/dexknife/DexKnifePlusPlugin.groovy index c7086b6..c19971b 100644 --- a/DexKnifePlugin/dexknife-plus/src/main/groovy/com/ceabie/dexknife/DexKnifePlugin.groovy +++ b/DexKnifePlugin/dexknife-plus/src/main/groovy/com/tangxiaolv/dexknife/DexKnifePlusPlugin.groovy @@ -13,15 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.ceabie.dexknife +package com.tangxiaolv.dexknife +import com.ceabie.dexknife.DexKnifePlugin +import com.ceabie.dexknife.DexSplitTools import org.gradle.api.Plugin import org.gradle.api.Project /** * the spilt tools plugin. */ -public class DexKnifePlugin implements Plugin { +public class DexKnifePlusPlugin implements Plugin { @Override void apply(Project project) { @@ -48,21 +50,11 @@ public class DexKnifePlugin implements Plugin { filterActivity(project); - if (isMultiDexEnabled(variant)) { - if (SplitToolsFor130.isCompat(variant)) { - System.err.println("DexKnife: Compat 1.3.0."); - SplitToolsFor130.processSplitDex(project, variant) - } else if (SplitToolsFor150.isCompat()) { - SplitToolsFor150.processSplitDex(project, variant) - } else { - System.err.println("DexKnife Error: DexKnife is not compatible your Android gradle plugin."); - } - } else { - System.err.println("DexKnife : MultiDexEnabled is false, it's not work."); - } + DexKnifePlugin.dexKnifeProcessVariant(project, variant) } + } else { + printf "-DexKnifePlugin Enable = false\n"; } - printf "-DexKnifePlugin Enable = false\n"; } } } @@ -103,19 +95,4 @@ public class DexKnifePlugin implements Plugin { } } } - - private static boolean isMultiDexEnabled(variant) { - def is = variant.buildType.multiDexEnabled - if (is != null) { - return is; - } - - is = variant.mergedFlavor.multiDexEnabled - if (is != null) { - return is; - } - - return false - } - } \ No newline at end of file diff --git a/DexKnifePlugin/dexknife-plus/src/main/resources/META-INF/gradle-plugins/dexknifePlus.properties b/DexKnifePlugin/dexknife-plus/src/main/resources/META-INF/gradle-plugins/dexknifePlus.properties index 24abf7f..c2ec48d 100644 --- a/DexKnifePlugin/dexknife-plus/src/main/resources/META-INF/gradle-plugins/dexknifePlus.properties +++ b/DexKnifePlugin/dexknife-plus/src/main/resources/META-INF/gradle-plugins/dexknifePlus.properties @@ -1 +1 @@ -implementation-class=com.ceabie.dexknife.DexKnifePlugin +implementation-class=com.tangxiaolv.dexknife.DexKnifePlusPlugin diff --git a/DexKnifePlugin/gradle/wrapper/gradle-wrapper.properties b/DexKnifePlugin/gradle/wrapper/gradle-wrapper.properties index e5ad1b4..e17444a 100644 --- a/DexKnifePlugin/gradle/wrapper/gradle-wrapper.properties +++ b/DexKnifePlugin/gradle/wrapper/gradle-wrapper.properties @@ -1,4 +1,4 @@ -#Tue Sep 20 15:06:11 CST 2016 +#Mon Dec 26 17:59:14 CST 2016 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME diff --git a/README.md b/README.md index da9dcf6..28cdf90 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,25 @@ -#Android傻瓜式分包插件 +# Deprecated +Please use [multiDexKeepProguard](https://developer.android.com/studio/build/multidex?hl=zh-cn) to splite main dex classes. + +# Android傻瓜式分包插件 +[ ![Download](https://api.bintray.com/packages/tangxiaolv/maven/dexknife-plus/images/download.svg?version=1.0.4) ](https://bintray.com/tangxiaolv/maven/dexknife-plus/1.0.4/link) + 注1:不想看前半部分的话可以直接跳过到最下面配置部分。 -注2:本插件是基于[DexKnifePlugin 1.5.6](https://github.com/ceabie/DexKnifePlugin)优化改造而来,感谢ceabie的无私奉献。 +注2:本插件是基于[DexKnifePlugin 1.6.2](https://github.com/ceabie/DexKnifePlugin)优化改造而来,感谢ceabie的无私奉献。 -##填坑之路 -###坑1:65536 ,So easy! +## 填坑之路 +### 坑1:65536 ,So easy! **原因:**Dalvik 的 invoke-kind 指令集中,method reference index 只留了 16 bits,最多能引用 65535 个方法。 参考=>[由Android 65K方法数限制引发的思考](http://jayfeng.com/2016/03/10/%E7%94%B1Android-65K%E6%96%B9%E6%B3%95%E6%95%B0%E9%99%90%E5%88%B6%E5%BC%95%E5%8F%91%E7%9A%84%E6%80%9D%E8%80%83/). **解决:** ``` +android{ + defaultConfig { + multiDexEnabled true + } +} + dependencies { compile 'com.android.support:MultiDex:1.0.1' } @@ -22,7 +33,7 @@ protected void attachBaseContext(Context base) { } ``` -###坑2:Too many classes in –main-dex-list ,what? +### 坑2:Too many classes in –main-dex-list ,what? **原因:**通过上面的官方分包,已经把原Dex分为1主Dex加多从Dex。主Dex包含所有4大组件,Application,Annotation,multidex等及其必要的直接依赖。由于我们方法数已达到16W之巨,上百个Activity全部塞进主Dex,又成功的把主Dex撑爆了。 **解决:** @@ -41,17 +52,17 @@ afterEvaluate { ``` 参考=>[Android Dex分包之旅](http://yydcdut.com/2016/03/20/split-dex/index.html) -###坑3:gradle 1.5.0之后不支持这种写法 ,what the fuck? +### 坑3:gradle 1.5.0之后不支持这种写法 ,what the fuck? **原因:**官方解释Gralde`1.5.0`以上已经将(jacoco, progard, multi-dex)统一移到[Transform API](http://tools.android.com/tech-docs/new-build-system/transform-api)里,然而Transform API并没有想象的那么简单好用,翻遍Google终于找到一个兼容Gradle `1.5.0`以上的分包插件[DexKnifePlugin](https://github.com/ceabie/DexKnifePlugin)。 扩展=>这篇[Android 热修复使用Gradle Plugin1.5改造Nuwa插件](http://blog.csdn.net/sbsujjbcy/article/details/50839263)比较好的介绍了Transform API的使用。 -###坑4:NoClassDefFoundError ,are you kiding me? +### 坑4:NoClassDefFoundError ,are you kiding me? **原因:**通过插件手动指定main dex中要保留的类,虽然分包成功,但是main dex中的类及其直接引用类很难通过手动的方式指定。 **解决方式:** [美团Android DEX自动拆包及动态加载简介](http://tech.meituan.com/mt-android-auto-split-dex.html),他们是通过编写了一个能够自动分析Class依赖的脚本去算出主Dex需要包含的所有必要依赖。看来写脚本是跑不掉了。 -###坑5:自定义脚本 ,read the fuck source! +### 坑5:自定义脚本 ,read the fuck source! **问题一:**哪些类是需要放入主Dex中? 查看sdk\build-tools\platform-version\mainDexClasses.rules发现放入主Dex相关类有Instrumentation,Application,Activity,Service,ContentProvider,BroadcastReceiver,BackupAgent的所有子类。 @@ -95,31 +106,50 @@ afterEvaluate { } ``` -###坑6:主dex依然爆表,shit again! +### 坑6:主dex依然爆表,shit again! 其实上面那段脚本已经成功筛选出我们想要放入主Dex的`manifest_keep列表`和`maindexlist列表`,但是在打包的时候还是把所有类打进主Dex(已无语)。这个时候就需要跟[DexKnifePlugin](https://github.com/ceabie/DexKnifePlugin)插件配合使用,首先在gradle中加上上述脚本,然后使用插件时在配置文件中加上 `-split **.**`和`#-donot-use-suggest`。DexKnifePlugin插件运行原理很简单,在生成Dex任务之前首先读取自己的配置文件(包含前面我们通过Gradle脚本生成的`maindexlist`列表),然后扫描combined.jar(包含工程中所有.class文件)匹配出我们自定义的maindexlist.txt,再替换掉build/multi-dex/maindexlist.txt,和build实例。这样分包的时候就会基于我们的规则生成主Dex。 -###坑7:ANR,HAHAHA! +### 坑7:ANR,HAHAHA! 我们最低API=16,测试并未发现ANR问题,所以暂时没考虑景上添花,这个问题比较好解决。 参考=>[Android Dex分包之旅](http://yydcdut.com/2016/03/20/split-dex/index.html) -###Congratulation +### Congratulation 恭喜,填坑终于结束,不过还有点不爽的是需要同时维护Gradle脚本和插件的配置。 于是乎就将Gradle脚本整合进了插件,这样只需维护一个配置文件就行了。读者可以根据自己需求自行选择分开配置还是整合配置。通过这种方式我们把主Dex的方法数维持在15000左右,从此再也不用担心方法数问题了!!! -##配置部分 -**第一步:添加根目录Gradle** +## 配置部分 +**第一步:添加分包支持** +``` +android{ + defaultConfig { + multiDexEnabled true + } +} + +dependencies { + compile 'com.android.support:MultiDex:1.0.1' +} + +在继承的 Application中重写 attachBaseContext(Context) +@Override +protected void attachBaseContext(Context base) { + super.attachBaseContext(base); + MultiDex.install(this); +} +``` +**第二步:添加根目录Gradle** ``` buildscript { dependencies { - classpath 'com.library.tangxiaolv:dexknife-plus:1.0.1' + classpath 'com.library.tangxiaolv:dexknife-plus:1.0.4' } } ``` -**第二步:在你的App模块的build.gradle添加插件** +**第三步:在你的App模块的build.gradle添加插件** ``` apply plugin: 'dexknifePlus' ``` -**第三步:配置参数** +**第四步:配置参数**   ``` dexKnife{ //必选参数 @@ -139,15 +169,15 @@ dexKnife{ * */ } ``` -**第四步:在你的App模块目录下新建dexknife.txt,并自定义配置** +**第五步:在你的App模块目录下新建dexknife.txt,并自定义配置** ``` #为注释符 -#-----------主Dex中必要依赖的脚本配置----------- -#默认保留四大组件中其他三大组件(并计算其依赖树),Activity组件选择性保留(使用-just activity 选项),若为空不保留任何Activity +#-----------主Dex中必要依赖的脚本配置-----------(支持依赖检测) +#默认保留四大组件中Service,ContentProvider,BroadcastReceiver三大组件,Activity组件选择性保留,若为空不保留任何Activity -just activity com.ceabie.demo.MainActivity -#-----------附加类----------- +#-----------附加类-----------(不支持依赖检测) # 如果你想要某个包路径在maindex中,则使用 -keep 选项,即使他已经在分包的路径中.若为空,不保留任意类 #-keep com.ceabie.demo.** @@ -167,16 +197,18 @@ dexKnife{ # 表明限制的方法数小于main dex的必要方法数,调大到合适数值即可 -dex-param --set-max-idx-number=4000 -# 不进行dex分包, 直到 dex 的id数量超过 65536.(设置自动执行分包策略) +# 注释掉将执行自定义dex分包,否则执行默认分包. #-auto-maindex # 显示miandex的日志. #-log-mainlist ``` -**第五步:在 defaultConfig 或者 buildTypes中打开 multiDexEnabled true,否则不起作用** +**第六步:在 defaultConfig 或者 buildTypes中打开 multiDexEnabled true,否则不起作用** + +**使用前先参阅 DexKnife 的[特性部分](https://github.com/ceabie/DexKnifePlugin#特性重要)** -##已知错误 +## 已知错误 注:分包的时候如果发现一些莫名的错误,可以关掉instant run,一般都能解决 pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy