├── .gitignore ├── LICENSE ├── README.md ├── README_CHINESE.md ├── app ├── .gitignore ├── build.gradle ├── libs │ └── gson-2.8.4.jar ├── maindexlist.txt ├── proguard-rules.pro ├── src │ ├── androidTest │ │ └── java │ │ │ └── com │ │ │ └── iqiyi │ │ │ └── splitdexapk │ │ │ └── ExampleInstrumentedTest.java │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ │ └── com │ │ │ │ └── iqiyi │ │ │ │ └── dexsplitter │ │ │ │ ├── HostProjectClass1.java │ │ │ │ ├── MainActivity.java │ │ │ │ └── TestClassForMainDex.java │ │ └── res │ │ │ ├── drawable-v24 │ │ │ └── ic_launcher_foreground.xml │ │ │ ├── drawable │ │ │ └── ic_launcher_background.xml │ │ │ ├── layout │ │ │ └── activity_main.xml │ │ │ ├── mipmap-anydpi-v26 │ │ │ ├── ic_launcher.xml │ │ │ └── ic_launcher_round.xml │ │ │ ├── mipmap-hdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-mdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xhdpi │ │ │ ├── host_pic_01.png │ │ │ ├── host_pic_02.png │ │ │ ├── host_pic_03.png │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ └── values │ │ │ ├── colors.xml │ │ │ ├── strings.xml │ │ │ └── styles.xml │ └── test │ │ └── java │ │ └── com │ │ └── iqiyi │ │ └── splitdexapk │ │ └── ExampleUnitTest.java └── subdexeslist.txt ├── boo ├── .gitignore ├── build.gradle ├── libs │ └── universal-image-loader-1.9.5.jar ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── example │ │ └── moduletwo │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── boo │ │ │ ├── BooActivity.java │ │ │ └── BooClass1.java │ └── res │ │ ├── drawable │ │ └── android_logo.png │ │ ├── layout │ │ └── activity_moduletwo.xml │ │ ├── mipmap-xhdpi │ │ ├── boo_pic_01.png │ │ ├── boo_pic_02.png │ │ └── boo_pic_03.png │ │ └── values │ │ └── strings.xml │ └── test │ └── java │ └── com │ └── example │ └── moduletwo │ └── ExampleUnitTest.java ├── build.gradle ├── extra ├── .gitkeep ├── DexIncrementalRenameManager.java ├── TestClassForMainDex.java ├── dx.jar ├── hack_description.txt ├── hack_dx │ ├── Makefile │ ├── README.md │ ├── buildJar.sh │ ├── etc │ │ └── manifest.txt │ └── src │ │ └── com │ │ └── android │ │ ├── dex │ │ ├── Annotation.java │ │ ├── ClassData.java │ │ ├── ClassDef.java │ │ ├── Code.java │ │ ├── Dex.java │ │ ├── DexException.java │ │ ├── DexFormat.java │ │ ├── DexIndexOverflowException.java │ │ ├── EncodedValue.java │ │ ├── EncodedValueCodec.java │ │ ├── EncodedValueReader.java │ │ ├── FieldId.java │ │ ├── Leb128.java │ │ ├── MethodId.java │ │ ├── Mutf8.java │ │ ├── ProtoId.java │ │ ├── SizeOf.java │ │ ├── TableOfContents.java │ │ ├── TypeList.java │ │ └── util │ │ │ ├── ByteArrayByteInput.java │ │ │ ├── ByteInput.java │ │ │ ├── ByteOutput.java │ │ │ ├── ExceptionWithContext.java │ │ │ ├── FileUtils.java │ │ │ └── Unsigned.java │ │ ├── dx │ │ ├── Version.java │ │ ├── cf │ │ │ ├── attrib │ │ │ │ ├── AttAnnotationDefault.java │ │ │ │ ├── AttCode.java │ │ │ │ ├── AttConstantValue.java │ │ │ │ ├── AttDeprecated.java │ │ │ │ ├── AttEnclosingMethod.java │ │ │ │ ├── AttExceptions.java │ │ │ │ ├── AttInnerClasses.java │ │ │ │ ├── AttLineNumberTable.java │ │ │ │ ├── AttLocalVariableTable.java │ │ │ │ ├── AttLocalVariableTypeTable.java │ │ │ │ ├── AttRuntimeInvisibleAnnotations.java │ │ │ │ ├── AttRuntimeInvisibleParameterAnnotations.java │ │ │ │ ├── AttRuntimeVisibleAnnotations.java │ │ │ │ ├── AttRuntimeVisibleParameterAnnotations.java │ │ │ │ ├── AttSignature.java │ │ │ │ ├── AttSourceDebugExtension.java │ │ │ │ ├── AttSourceFile.java │ │ │ │ ├── AttSynthetic.java │ │ │ │ ├── BaseAnnotations.java │ │ │ │ ├── BaseAttribute.java │ │ │ │ ├── BaseLocalVariables.java │ │ │ │ ├── BaseParameterAnnotations.java │ │ │ │ ├── InnerClassList.java │ │ │ │ ├── RawAttribute.java │ │ │ │ └── package.html │ │ │ ├── code │ │ │ │ ├── BaseMachine.java │ │ │ │ ├── BasicBlocker.java │ │ │ │ ├── ByteBlock.java │ │ │ │ ├── ByteBlockList.java │ │ │ │ ├── ByteCatchList.java │ │ │ │ ├── ByteOps.java │ │ │ │ ├── BytecodeArray.java │ │ │ │ ├── ConcreteMethod.java │ │ │ │ ├── ExecutionStack.java │ │ │ │ ├── Frame.java │ │ │ │ ├── LineNumberList.java │ │ │ │ ├── LocalVariableList.java │ │ │ │ ├── LocalsArray.java │ │ │ │ ├── LocalsArraySet.java │ │ │ │ ├── Machine.java │ │ │ │ ├── Merger.java │ │ │ │ ├── OneLocalsArray.java │ │ │ │ ├── ReturnAddress.java │ │ │ │ ├── Ropper.java │ │ │ │ ├── RopperMachine.java │ │ │ │ ├── SimException.java │ │ │ │ ├── Simulator.java │ │ │ │ ├── SwitchList.java │ │ │ │ ├── ValueAwareMachine.java │ │ │ │ └── package.html │ │ │ ├── cst │ │ │ │ ├── ConstantPoolParser.java │ │ │ │ └── ConstantTags.java │ │ │ ├── direct │ │ │ │ ├── AnnotationParser.java │ │ │ │ ├── AttributeFactory.java │ │ │ │ ├── AttributeListParser.java │ │ │ │ ├── ClassPathOpener.java │ │ │ │ ├── CodeObserver.java │ │ │ │ ├── DirectClassFile.java │ │ │ │ ├── FieldListParser.java │ │ │ │ ├── MemberListParser.java │ │ │ │ ├── MethodListParser.java │ │ │ │ ├── StdAttributeFactory.java │ │ │ │ └── package.html │ │ │ └── iface │ │ │ │ ├── Attribute.java │ │ │ │ ├── AttributeList.java │ │ │ │ ├── ClassFile.java │ │ │ │ ├── Field.java │ │ │ │ ├── FieldList.java │ │ │ │ ├── HasAttribute.java │ │ │ │ ├── Member.java │ │ │ │ ├── Method.java │ │ │ │ ├── MethodList.java │ │ │ │ ├── ParseException.java │ │ │ │ ├── ParseObserver.java │ │ │ │ ├── StdAttributeList.java │ │ │ │ ├── StdField.java │ │ │ │ ├── StdFieldList.java │ │ │ │ ├── StdMember.java │ │ │ │ ├── StdMethod.java │ │ │ │ ├── StdMethodList.java │ │ │ │ └── package.html │ │ ├── command │ │ │ ├── Main.java │ │ │ ├── UsageException.java │ │ │ ├── annotool │ │ │ │ ├── AnnotationLister.java │ │ │ │ └── Main.java │ │ │ ├── dexer │ │ │ │ ├── DxContext.java │ │ │ │ └── Main.java │ │ │ ├── dump │ │ │ │ ├── Args.java │ │ │ │ ├── BaseDumper.java │ │ │ │ ├── BlockDumper.java │ │ │ │ ├── ClassDumper.java │ │ │ │ ├── DotDumper.java │ │ │ │ ├── Main.java │ │ │ │ └── SsaDumper.java │ │ │ ├── findusages │ │ │ │ ├── FindUsages.java │ │ │ │ └── Main.java │ │ │ └── grep │ │ │ │ ├── Grep.java │ │ │ │ └── Main.java │ │ ├── dex │ │ │ ├── DexOptions.java │ │ │ ├── cf │ │ │ │ ├── AttributeTranslator.java │ │ │ │ ├── CfOptions.java │ │ │ │ ├── CfTranslator.java │ │ │ │ ├── CodeStatistics.java │ │ │ │ ├── OptimizerOptions.java │ │ │ │ └── package.html │ │ │ ├── code │ │ │ │ ├── ArrayData.java │ │ │ │ ├── BlockAddresses.java │ │ │ │ ├── CatchBuilder.java │ │ │ │ ├── CatchHandlerList.java │ │ │ │ ├── CatchTable.java │ │ │ │ ├── CodeAddress.java │ │ │ │ ├── CstInsn.java │ │ │ │ ├── DalvCode.java │ │ │ │ ├── DalvInsn.java │ │ │ │ ├── DalvInsnList.java │ │ │ │ ├── Dop.java │ │ │ │ ├── Dops.java │ │ │ │ ├── FixedSizeInsn.java │ │ │ │ ├── HighRegisterPrefix.java │ │ │ │ ├── InsnFormat.java │ │ │ │ ├── LocalList.java │ │ │ │ ├── LocalSnapshot.java │ │ │ │ ├── LocalStart.java │ │ │ │ ├── MultiCstInsn.java │ │ │ │ ├── OddSpacer.java │ │ │ │ ├── OutputCollector.java │ │ │ │ ├── OutputFinisher.java │ │ │ │ ├── PositionList.java │ │ │ │ ├── RopToDop.java │ │ │ │ ├── RopTranslator.java │ │ │ │ ├── SimpleInsn.java │ │ │ │ ├── StdCatchBuilder.java │ │ │ │ ├── SwitchData.java │ │ │ │ ├── TargetInsn.java │ │ │ │ ├── VariableSizeInsn.java │ │ │ │ ├── ZeroSizeInsn.java │ │ │ │ └── form │ │ │ │ │ ├── Form10t.java │ │ │ │ │ ├── Form10x.java │ │ │ │ │ ├── Form11n.java │ │ │ │ │ ├── Form11x.java │ │ │ │ │ ├── Form12x.java │ │ │ │ │ ├── Form20t.java │ │ │ │ │ ├── Form21c.java │ │ │ │ │ ├── Form21h.java │ │ │ │ │ ├── Form21s.java │ │ │ │ │ ├── Form21t.java │ │ │ │ │ ├── Form22b.java │ │ │ │ │ ├── Form22c.java │ │ │ │ │ ├── Form22s.java │ │ │ │ │ ├── Form22t.java │ │ │ │ │ ├── Form22x.java │ │ │ │ │ ├── Form23x.java │ │ │ │ │ ├── Form30t.java │ │ │ │ │ ├── Form31c.java │ │ │ │ │ ├── Form31i.java │ │ │ │ │ ├── Form31t.java │ │ │ │ │ ├── Form32x.java │ │ │ │ │ ├── Form35c.java │ │ │ │ │ ├── Form3rc.java │ │ │ │ │ ├── Form45cc.java │ │ │ │ │ ├── Form4rcc.java │ │ │ │ │ ├── Form51l.java │ │ │ │ │ └── SpecialFormat.java │ │ │ └── file │ │ │ │ ├── AnnotationItem.java │ │ │ │ ├── AnnotationSetItem.java │ │ │ │ ├── AnnotationSetRefItem.java │ │ │ │ ├── AnnotationUtils.java │ │ │ │ ├── AnnotationsDirectoryItem.java │ │ │ │ ├── CatchStructs.java │ │ │ │ ├── ClassDataItem.java │ │ │ │ ├── ClassDefItem.java │ │ │ │ ├── ClassDefsSection.java │ │ │ │ ├── CodeItem.java │ │ │ │ ├── DebugInfoConstants.java │ │ │ │ ├── DebugInfoDecoder.java │ │ │ │ ├── DebugInfoEncoder.java │ │ │ │ ├── DebugInfoItem.java │ │ │ │ ├── DexFile.java │ │ │ │ ├── EncodedArrayItem.java │ │ │ │ ├── EncodedField.java │ │ │ │ ├── EncodedMember.java │ │ │ │ ├── EncodedMethod.java │ │ │ │ ├── FieldAnnotationStruct.java │ │ │ │ ├── FieldIdItem.java │ │ │ │ ├── FieldIdsSection.java │ │ │ │ ├── HeaderItem.java │ │ │ │ ├── HeaderSection.java │ │ │ │ ├── IdItem.java │ │ │ │ ├── IndexedItem.java │ │ │ │ ├── Item.java │ │ │ │ ├── ItemType.java │ │ │ │ ├── MapItem.java │ │ │ │ ├── MemberIdItem.java │ │ │ │ ├── MemberIdsSection.java │ │ │ │ ├── MethodAnnotationStruct.java │ │ │ │ ├── MethodIdItem.java │ │ │ │ ├── MethodIdsSection.java │ │ │ │ ├── MixedItemSection.java │ │ │ │ ├── OffsettedItem.java │ │ │ │ ├── ParameterAnnotationStruct.java │ │ │ │ ├── ProtoIdItem.java │ │ │ │ ├── ProtoIdsSection.java │ │ │ │ ├── Section.java │ │ │ │ ├── Statistics.java │ │ │ │ ├── StringDataItem.java │ │ │ │ ├── StringIdItem.java │ │ │ │ ├── StringIdsSection.java │ │ │ │ ├── TypeIdItem.java │ │ │ │ ├── TypeIdsSection.java │ │ │ │ ├── TypeListItem.java │ │ │ │ ├── UniformItemSection.java │ │ │ │ ├── UniformListItem.java │ │ │ │ └── ValueEncoder.java │ │ ├── io │ │ │ ├── CodeReader.java │ │ │ ├── DexIndexPrinter.java │ │ │ ├── IndexType.java │ │ │ ├── OpcodeInfo.java │ │ │ ├── Opcodes.java │ │ │ └── instructions │ │ │ │ ├── AddressMap.java │ │ │ │ ├── BaseCodeCursor.java │ │ │ │ ├── CodeCursor.java │ │ │ │ ├── CodeInput.java │ │ │ │ ├── CodeOutput.java │ │ │ │ ├── DecodedInstruction.java │ │ │ │ ├── FillArrayDataPayloadDecodedInstruction.java │ │ │ │ ├── FiveRegisterDecodedInstruction.java │ │ │ │ ├── FourRegisterDecodedInstruction.java │ │ │ │ ├── InstructionCodec.java │ │ │ │ ├── OneRegisterDecodedInstruction.java │ │ │ │ ├── PackedSwitchPayloadDecodedInstruction.java │ │ │ │ ├── RegisterRangeDecodedInstruction.java │ │ │ │ ├── ShortArrayCodeInput.java │ │ │ │ ├── ShortArrayCodeOutput.java │ │ │ │ ├── SparseSwitchPayloadDecodedInstruction.java │ │ │ │ ├── ThreeRegisterDecodedInstruction.java │ │ │ │ ├── TwoRegisterDecodedInstruction.java │ │ │ │ └── ZeroRegisterDecodedInstruction.java │ │ ├── merge │ │ │ ├── CollisionPolicy.java │ │ │ ├── DexMerger.java │ │ │ ├── IndexMap.java │ │ │ ├── InstructionTransformer.java │ │ │ └── SortableType.java │ │ ├── rop │ │ │ ├── annotation │ │ │ │ ├── Annotation.java │ │ │ │ ├── AnnotationVisibility.java │ │ │ │ ├── Annotations.java │ │ │ │ ├── AnnotationsList.java │ │ │ │ └── NameValuePair.java │ │ │ ├── code │ │ │ │ ├── AccessFlags.java │ │ │ │ ├── BasicBlock.java │ │ │ │ ├── BasicBlockList.java │ │ │ │ ├── ConservativeTranslationAdvice.java │ │ │ │ ├── CstInsn.java │ │ │ │ ├── DexTranslationAdvice.java │ │ │ │ ├── Exceptions.java │ │ │ │ ├── FillArrayDataInsn.java │ │ │ │ ├── Insn.java │ │ │ │ ├── InsnList.java │ │ │ │ ├── InvokePolymorphicInsn.java │ │ │ │ ├── LocalItem.java │ │ │ │ ├── LocalVariableExtractor.java │ │ │ │ ├── LocalVariableInfo.java │ │ │ │ ├── PlainCstInsn.java │ │ │ │ ├── PlainInsn.java │ │ │ │ ├── RegOps.java │ │ │ │ ├── RegisterSpec.java │ │ │ │ ├── RegisterSpecList.java │ │ │ │ ├── RegisterSpecSet.java │ │ │ │ ├── Rop.java │ │ │ │ ├── RopMethod.java │ │ │ │ ├── Rops.java │ │ │ │ ├── SourcePosition.java │ │ │ │ ├── SwitchInsn.java │ │ │ │ ├── ThrowingCstInsn.java │ │ │ │ ├── ThrowingInsn.java │ │ │ │ ├── TranslationAdvice.java │ │ │ │ └── package.html │ │ │ ├── cst │ │ │ │ ├── Constant.java │ │ │ │ ├── ConstantPool.java │ │ │ │ ├── CstAnnotation.java │ │ │ │ ├── CstArray.java │ │ │ │ ├── CstBaseMethodRef.java │ │ │ │ ├── CstBoolean.java │ │ │ │ ├── CstByte.java │ │ │ │ ├── CstChar.java │ │ │ │ ├── CstDouble.java │ │ │ │ ├── CstEnumRef.java │ │ │ │ ├── CstFieldRef.java │ │ │ │ ├── CstFloat.java │ │ │ │ ├── CstInteger.java │ │ │ │ ├── CstInterfaceMethodRef.java │ │ │ │ ├── CstKnownNull.java │ │ │ │ ├── CstLiteral32.java │ │ │ │ ├── CstLiteral64.java │ │ │ │ ├── CstLiteralBits.java │ │ │ │ ├── CstLong.java │ │ │ │ ├── CstMemberRef.java │ │ │ │ ├── CstMethodRef.java │ │ │ │ ├── CstNat.java │ │ │ │ ├── CstProtoRef.java │ │ │ │ ├── CstShort.java │ │ │ │ ├── CstString.java │ │ │ │ ├── CstType.java │ │ │ │ ├── StdConstantPool.java │ │ │ │ ├── TypedConstant.java │ │ │ │ ├── Zeroes.java │ │ │ │ └── package.html │ │ │ ├── package-info.java │ │ │ └── type │ │ │ │ ├── Prototype.java │ │ │ │ ├── StdTypeList.java │ │ │ │ ├── Type.java │ │ │ │ ├── TypeBearer.java │ │ │ │ ├── TypeList.java │ │ │ │ └── package.html │ │ ├── ssa │ │ │ ├── BasicRegisterMapper.java │ │ │ ├── ConstCollector.java │ │ │ ├── DeadCodeRemover.java │ │ │ ├── DomFront.java │ │ │ ├── Dominators.java │ │ │ ├── EscapeAnalysis.java │ │ │ ├── InterferenceRegisterMapper.java │ │ │ ├── LiteralOpUpgrader.java │ │ │ ├── LocalVariableExtractor.java │ │ │ ├── LocalVariableInfo.java │ │ │ ├── MoveParamCombiner.java │ │ │ ├── NormalSsaInsn.java │ │ │ ├── Optimizer.java │ │ │ ├── PhiInsn.java │ │ │ ├── PhiTypeResolver.java │ │ │ ├── RegisterMapper.java │ │ │ ├── SCCP.java │ │ │ ├── SetFactory.java │ │ │ ├── SsaBasicBlock.java │ │ │ ├── SsaConverter.java │ │ │ ├── SsaInsn.java │ │ │ ├── SsaMethod.java │ │ │ ├── SsaRenamer.java │ │ │ ├── back │ │ │ │ ├── FirstFitAllocator.java │ │ │ │ ├── FirstFitLocalCombiningAllocator.java │ │ │ │ ├── IdenticalBlockCombiner.java │ │ │ │ ├── InterferenceGraph.java │ │ │ │ ├── LivenessAnalyzer.java │ │ │ │ ├── NullRegisterAllocator.java │ │ │ │ ├── RegisterAllocator.java │ │ │ │ └── SsaToRop.java │ │ │ └── package-info.java │ │ └── util │ │ │ ├── AnnotatedOutput.java │ │ │ ├── BitIntSet.java │ │ │ ├── Bits.java │ │ │ ├── ByteArray.java │ │ │ ├── ByteArrayAnnotatedOutput.java │ │ │ ├── FixedSizeList.java │ │ │ ├── Hex.java │ │ │ ├── HexParser.java │ │ │ ├── IndentingWriter.java │ │ │ ├── IntIterator.java │ │ │ ├── IntList.java │ │ │ ├── IntSet.java │ │ │ ├── LabeledItem.java │ │ │ ├── LabeledList.java │ │ │ ├── ListIntSet.java │ │ │ ├── MutabilityControl.java │ │ │ ├── MutabilityException.java │ │ │ ├── Output.java │ │ │ ├── ToHuman.java │ │ │ ├── TwoColumnOutput.java │ │ │ ├── Warning.java │ │ │ ├── Writers.java │ │ │ └── package.html │ │ └── multidex │ │ ├── ArchivePathElement.java │ │ ├── ClassPathElement.java │ │ ├── ClassReferenceListBuilder.java │ │ ├── FolderPathElement.java │ │ ├── MainDexListBuilder.java │ │ └── Path.java ├── hook_details.txt ├── maindexlist.txt └── splitdex │ ├── apk_splitter.py │ ├── base_config.py │ ├── config.ini │ └── parse_util.py ├── far ├── .gitignore ├── build.gradle ├── libs │ └── greendao-3.2.0.jar ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── example │ │ └── moduleone │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── far │ │ │ ├── FarActivity.java │ │ │ └── FarClass1.java │ └── res │ │ ├── layout │ │ └── activity_far.xml │ │ ├── mipmap-xhdpi │ │ ├── far_module_01.png │ │ ├── far_module_02.png │ │ └── far_module_03.png │ │ └── values │ │ └── strings.xml │ └── test │ └── java │ └── com │ └── example │ └── moduleone │ └── ExampleUnitTest.java ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── res ├── .gitkeep ├── apk_origin.png ├── apk_origin_parse.png ├── dex_hack.png ├── dex_hack_english.png ├── dex_splitter_with_name.png ├── parse_result.png └── spilt_dex_apk.png └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea 5 | .DS_Store 6 | /build 7 | ../.DS_Store 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DexSplitter Solution 2 | As we all know, Google has provided aapt plugin for parsing apk, we can get a list of apk files by using 'aapt l -v '. 3 | We can divide each res file(assets file) into the module project which it belongs to. 4 | But source code of the project can not be divided directly because it will be shrinked optimized and obfuscated. 5 | DexSplitter can help you to divide source code. 6 | 7 | [中文文档](/README_CHINESE.md) 8 | 9 | 10 | # Scenarios 11 | + Analyze contribution rate of each module to the apk size 12 | + Diff the size of each module in the apk for every sprint 13 | 14 | 15 | # Apk Split Result 16 | 17 | 18 | > #### Android Origin Build Release.apk 19 | > ![SplitDexApk](res/apk_origin_parse.png) 20 | > #### DexSplitter Build Release.apk 21 | > ![SplitDexApk](res/dex_splitter_with_name.png) 22 | > #### splitter_result.txt 23 | > ![SplitDexApk](res/parse_result.png ) 24 | 25 | > ps:more details:extra/hack_description.txt extra/hook_details.txt 26 | 27 | # Demo Introduction 28 | + The most important purpose of dexSplitter is to build apk which has special dex files 29 | + You can use extra/dx.jar directly 30 | + Host app(lib:gson), library module moduleone(lib:GreenDAO), library module moduletwo(lib:universalimageloader) 31 | + subdexeslist.txt is used for splitting dex, TestClassForMainDex.class is just a test file 32 | + Third libs will not be obfuscated 33 | + Android Support library is marked as android_sys 34 | + subdexeslist.txt should not contain duplicated class files 35 | 36 | 37 | # Schematic Diagram 38 | ![SplitDexApk](res/dex_hack_english.png) 39 | 40 | 41 | # Implementation 42 | 43 | + Divide the dex files with class files 44 | + Build apk which has special dex files 45 | + Python files for collecting class files 46 | + Obfuscated class list for release version 47 | 48 | 49 | # Future 50 | 51 | + Signed apk 52 | + Generate tables about the proportion of module projects 53 | + Parse changes of dex files by comparing different apk versions 54 | + Divide the dex files by author, module etc. 55 | 56 | 57 | # License 58 | + Copyright (c) 2018-present, iQIYI, Inc. All rights reserved. 59 | Most source code in dexSplitter are MIT licensed. Some other source code have Apache licenses. 60 | Please refer to the LICENSE file for detailed information. 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /README_CHINESE.md: -------------------------------------------------------------------------------- 1 | # 项目简介 2 | 为严控apk体积增长,需要精确量化apk中各模块占比大小。针对res文件、so文件(assets)等,Google提供了AAPT套件,通过脚本,可解压分析出各部分大小。 3 | 针对源码部分,混淆过的class文件,因经过合并,压缩等操作生成最终dex文件,无法直接分析各模块占比。 4 | dexSplitter 主要针对源码部分,提供了一套彻底的分析APK dex组成的解决方案。 5 | 6 | # 应用场景 7 | 8 | + 分析apk包体积各模块贡献率 9 | + 跟踪版本迭代时,包体积各部分变动量,及变化趋势 10 | + 详细监控各模块内各子模块占比情况 11 | 12 | 13 | # Android原生Apk组成 14 | 15 | + apk中dex部分,无法衡量各业务占比情况 16 | 17 | > #### 正常生成的apk组成 18 | >![SplitDexApk](res/apk_origin_parse.png) 19 | 20 | # dexSplitter方案生成Apk 21 | + apk中dex部分,可以精确测算各业务占比,辅以python脚本可得出各业务总体占比情况 22 | 23 | > #### 最终Apk 24 | > ![SplitDexApk](res/dex_splitter_with_name.png) 25 | > #### 分析结果 26 | > ![SplitDexApk](res/parse_result.png ) 27 | 28 | > ps:more details:extra/hack_description.txt 29 | 30 | # Demo 示例说明: 31 | + dexSpliter工程,打包生成带有dex分组属性的apk,可认为dex分拆方案已完成。附带的python apk分析脚本,简单划分了module资源文件,仅供参考。 32 | + extra/dx.jar 为编译好的dx文件,可用来替换系统dx.jar 33 | + 主工程app(示例lib 为gson),library module moduleone(示例lib为GreenDAO),library module moduletwo( 示例lib为universalimageloader) 34 | + 实际分组文件为subdexeslist.txt, maindexlist.txt为系统必须文件,无实质内容,增加的测试文件TestClassForMainDex.class(用来绕过系统检查) 35 | + 为便于对比验证,第三方库未参与混淆 36 | + dex占比划分中,Android Support库作为独立库(android_sys)示例,单独划分 37 | + 未明确划分的代码,会被打进unkown.dex 38 | + subdexeslist.txt为真实apk包含的最终class,不应出现重复类,否则会导致打包错误 39 | 40 | 41 | # hack的基本原理示意图 42 | ![SplitDexApk](res/dex_hack.png) 43 | 44 | 45 | + dx.jar编译源码地址: https://android.googlesource.com/platform/dalvik demo基于26.0.2 46 | + android gradle源码地址:https://android.googlesource.com/platform/tools/base 47 | + 干预dex生成过程,按需生成dex文件,并对其按模块命名。com.android.dx.command.dexer.Main.java 48 | + 干预gradle插件packaging阶段重命名过程,使其保持模块命名。com.android.builder.internal.packaging.DexIncrementalRenameManager.java 49 | 50 | # SplitDexAPK已支持的功能: 51 | 52 | + 支持class粒度级别拆分各业务模块源码; 53 | + 支持按需输出apk文件,源码部分占比可直接展示 54 | + 可定制化脚本,自动收集生成各模块源码文件 55 | + 支持Release版本,混淆文件分拆分拣 56 | + 可按工程模块,业务模块等各种维度进行占比分析 57 | 58 | 59 | # 实际应用: 60 | 61 | + 持续监控IQIYI客户端多个版本apk体积变化,详细分解了如泡泡,基线,播放器,支付模块等业务模块,按照代码与资源相对apk整体贡献比每月出具量化报告。
62 | 为科学量化与严格监控客户端包体积变化提供了有效数据支撑。 63 | 64 | 65 | # 后续扩展 66 | 67 | + demo仅做演示,未增加签名处理,可通过签名文件处理,得到最终版本apk文件 68 | + 结合aapt分析res,assets目录文件等,可得出综合模块apk贡献率统计表 69 | + 脚本部署后,可定期跟踪包体积各部分变动量,及变化趋势 70 | + 可结合git提交记录等,按业务模块,提交作者,工程模块等各种维度进行占比分析 71 | 72 | 73 | # License 74 | + Copyright (c) 2018-present, 爱奇艺, Inc. All rights reserved. 75 | dexSplitter中大多数的源码使用 MIT 许可证,另外的一些源码使用 Apache 样式的许可证。 76 | 详细信息请查看 LICENSE 文件。 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | *.iml -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 26 5 | defaultConfig { 6 | applicationId "com.iqiyi.splitdexapk" 7 | multiDexEnabled true 8 | minSdkVersion 15 9 | targetSdkVersion 26 10 | versionCode 1 11 | versionName "1.0" 12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled true 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | 21 | dexOptions { 22 | if (project.findProperty('hack_builder') == 'true') { 23 | dexInProcess = true 24 | additionalParameters = ['--main-dex-list=' + projectDir+'/maindexlist.txt', 25 | '--minimal-main-dex', '--sub-dexes-list=' + projectDir + '/subdexeslist.txt'] 26 | } else if (project.findProperty('hack_dx') == 'true') { 27 | dexInProcess = false 28 | additionalParameters = ['--main-dex-list=' + projectDir + '/maindexlist.txt', 29 | '--minimal-main-dex', '--sub-dexes-list=' + projectDir+'/subdexeslist.txt'] 30 | } 31 | } 32 | } 33 | 34 | dependencies { 35 | implementation 'com.android.support:appcompat-v7:26.1.0' 36 | implementation 'com.android.support.constraint:constraint-layout:1.1.0' 37 | implementation project(':far') 38 | implementation project(':boo') 39 | implementation files('libs/gson-2.8.4.jar') 40 | } 41 | -------------------------------------------------------------------------------- /app/libs/gson-2.8.4.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iqiyi/dexSplitter/902f19419a9615081107d2ec8c2eabea20363fd6/app/libs/gson-2.8.4.jar -------------------------------------------------------------------------------- /app/maindexlist.txt: -------------------------------------------------------------------------------- 1 | com/iqiyi/dexsplitter/TestClassForMainDex.class -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -keep class com.iqiyi.splitdexapk.TestClassForMainDex{*;} 23 | 24 | -keep class android.** { *; } 25 | -keep public class * extends android.support.v4.** 26 | -keep public class * extends android.support.v7.** 27 | 28 | -keep @android.support.annotation.Keep class * {*;} 29 | -keepclasseswithmembers class * { 30 | @android.support.annotation.Keep ; 31 | } 32 | -keepclasseswithmembers class * { 33 | @android.support.annotation.Keep ; 34 | } 35 | -keepclasseswithmembers class * { 36 | @android.support.annotation.Keep (...); 37 | } 38 | 39 | -keep class okhttp3.**{*;} 40 | -dontwarn okhttp3.** 41 | -keep class com.google.gson.** {*;} 42 | -keep class org.greenrobot.greendao.**{*;} 43 | -dontwarn org.greenrobot.greendao.** -------------------------------------------------------------------------------- /app/src/androidTest/java/com/iqiyi/splitdexapk/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.iqiyi.splitdexapk; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumented test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.iqiyi.splitdexapk", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /app/src/main/java/com/iqiyi/dexsplitter/HostProjectClass1.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018-present, iQIYI, Inc. All rights reserved. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 5 | * associated documentation files (the "Software"), to deal in the Software without restriction, 6 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, 8 | * subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or substantial 11 | * portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 14 | * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 15 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 16 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 17 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | * 19 | */ 20 | 21 | package com.iqiyi.dexsplitter; 22 | 23 | public class HostProjectClass1 { 24 | 25 | public static String Test1(){ 26 | return "this is a test"; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /app/src/main/java/com/iqiyi/dexsplitter/TestClassForMainDex.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018-present, iQIYI, Inc. All rights reserved. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 5 | * associated documentation files (the "Software"), to deal in the Software without restriction, 6 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, 8 | * subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or substantial 11 | * portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 14 | * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 15 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 16 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 17 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | * 19 | */ 20 | 21 | package com.iqiyi.dexsplitter; 22 | 23 | /** 24 | * just prepare for maindex 25 | */ 26 | 27 | public class TestClassForMainDex { 28 | } 29 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 |