Äú¿ÉÒÔ¾èÖú£¬Ö§³ÖÎÒÃǵĹ«ÒæÊÂÒµ¡£

1Ôª 10Ôª 50Ôª





ÈÏÖ¤Â룺  ÑéÖ¤Âë,¿´²»Çå³þ?Çëµã»÷Ë¢ÐÂÑéÖ¤Âë ±ØÌî



  ÇóÖª ÎÄÕ ÎÄ¿â Lib ÊÓÆµ iPerson ¿Î³Ì ÈÏÖ¤ ×Éѯ ¹¤¾ß ½²×ù Model Center   Code  
»áÔ±   
   
 
     
   
 ¶©ÔÄ
  ¾èÖú
Android App°üÊÝÉíÓÅ»¯Êµ¼ù
 
×÷Õߣº½¨Ë§ À´Ô´£ºÃÀÍż¼ÊõµãÆÀÖÐÐÄ ·¢²¼ÓÚ£º 2017-5-26
  3018  次浏览      30
 

Ëæ×ÅÒµÎñµÄ¿ìËÙµü´úÔö³¤£¬ÃÀÍÅAppÀï²»¶ÏÒýÈëеÄÒµÎñÂß¼­´úÂ롢ͼƬ×ÊÔ´ºÍµÚÈý·½SDK£¬Ö±½Óµ¼ÖÂAPKÌå»ý²»¶ÏÔö³¤¡£°üÌå»ýÔö³¤´øÀ´µÄÎÊÌâÔ½À´Ô½¶à£¬ÈçCDNÁ÷Á¿·ÑÓÃÔö¼Ó¡¢Óû§°²×°³É¹¦ÂʽµµÍ£¬ÉõÖÁ¿ÉÄÜ»áÓ°ÏìÓû§µÄÁô´æÂÊ¡£APKµÄÊÝÉíÒѾ­ÊDz»µÃ²»¿¼ÂǵÄÊÂÇé¡£ÔÚ³¢ÊÔÊÝÉíµÄ¹ý³ÌÖУ¬ÎÒÃÇ½è¼øÁ˺ܶàÒµ½çÆäËû¹«Ë¾ÌṩµÄ·½°¸£¬Í¬Ê±Ò²Õë¶Ô×ÔÉíÌØµã£¬·¢ÏÖÁËһЩеļ¼ÇÉ¡£±¾ÎĽ«¶ÔÆäÖеÄһЩ×öÏêϸ½éÉÜ¡£

ÔÚ¿ªÊ¼½²ÊÝÉí¼¼ÇÉ֮ǰ£¬ÏÈÀ´½²Ò»ÏÂAPKµÄ¹¹³É¡£

APKµÄ¹¹³É

¿ÉÒÔÓÃZip¹¤¾ß´ò¿ªAPK²é¿´¡£±ÈÈ磬ÃÀÍÅApp 7.8.6µÄÏßÉϰ汾µÄ¸ñʽÊÇÕâÑùµÄ£º

¿ÉÒÔ¿´µ½APKÓÉÒÔÏÂÖ÷Òª²¿·Ö×é³É£º

µ±È»»¹»áÓÐһЩÆäËüµÄÎļþ£¬ÀýÈçÉÏͼÖеÄorg/¡¢src/¡¢push_versionµÈÎļþ»òÎļþ¼Ð¡£ÕâЩ×ÊÔ´ÊÇJava Resources£¬¸ÐÐËȤµÄ¿ÉÒÔ½áºÏ±àÒ빤×÷Á÷ÖеÄÁ÷³ÌͼÒÔ¼° MergeJavaResourcesTransform µÄÔ´Âë¿´¿´±»´òÈëAPK°üÖеÄ×ÊÔ´¶¼ÓÐÄÄЩ£¬ÕâÀï²»×ö¹ý¶à½éÉÜ¡£

ÔÚ³ä·ÖÁ˽âÁËAPK¸÷¸ö×é³É²¿·ÖÒÔ¼°ËüÃǵÄ×÷Óúó£¬ÎÒÃÇÕë¶Ô×ÔÉíÌØµã½øÐÐÁË·ÖÎöºÍÓÅ»¯¡£ÏÂÃæ½«´ÓZipÎļþ¸ñʽ¡¢classes.dex¡¢×ÊÔ´Îļþ¡¢resources.arscµÈ·½ÃæÀ´½éÉÜÏÂÎÒÃÇ·¢ÏֵIJ¿·ÖÓÅ»¯¼¼ÇÉ¡£

Zip¸ñʽÓÅ»¯

Ç°Ãæ½éÉÜÁËAPKµÄÎļþ¸ñʽÒÔ¼°Ö÷Òª×é³É²¿·Ö£¬Í¨¹ýaapt l -v xxx.apk»òunzip -l xxx.apkÀ´²é¿´APKÎļþʱ»áµÃµ½ÒÔÏÂÐÅÏ¢£¬¼ûÏÂÃæ½ØÍ¼£º

ͨ¹ýÉÏͼ¿ÉÒÔ¿´µ½APKÖкܶà×ÊÔ´ÊÇÒÔStoredÀ´´æ´¢µÄ£¬¸ù¾ÝZipµÄÎļþ¸ñʽÖжÔѹËõ·½Ê½µÄÃèÊö Compression_methods ¿ÉÒÔ¿´³öÕâЩÎļþÊÇûÓÐѹËõµÄ£¬ÄÇΪʲôËüÃÇûÓб»Ñ¹ËõÄØ£¿´ÓAAPTµÄÔ´ÂëÖÐÕÒµ½ÒÔÏÂÃèÊö£º

/* these formats are already compressed, or don't compress well */
static const char* kNoCompressExt[] = {
".jpg", ".jpeg", ".png", ".gif",
".wav", ".mp2", ".mp3", ".ogg", ".aac",
".mpg", ".mpeg", ".mid", ".midi", ".smf", ".jet",
".rtttl", ".imy", ".xmf", ".mp4", ".m4a",
".m4v", ".3gp", ".3gpp", ".3g2", ".3gpp2",
".amr", ".awb", ".wma", ".wmv", ".webm", ".mkv"
};

¿ÉÒÔ¿´³öAAPTÔÚ×ÊÔ´´¦Àíʱ¶ÔÕâЩÎļþºó׺ÀàÐ͵Ä×ÊÔ´ÊDz»×öѹËõµÄ£¬ÄÇÊDz»ÊÇ¿ÉÒÔÐÞ¸ÄËüÃǵÄѹËõ·½Ê½´Ó¶ø´ïµ½ÊÝÉíµÄЧ¹ûÄØ£¿

ÔÚ½éÉÜÔõô×ö֮ǰ£¬ÏÈÀ´´ó¸Å½éÉÜÒ»ÏÂAppµÄ×ÊÔ´ÊÇÔõô±»´ò½øAPK°üÀïµÄ¡£Android¹¹½¨¹¤¾ßÁ´Ê¹ÓÃAAPT¹¤¾ßÀ´¶Ô×ÊÔ´½øÐд¦Àí£¬À´¿´ÏÂͼ£¨Í¼Æ¬À´Ô´ÓÚBuild Workflow£©£º

ͨ¹ýÉÏͼ¿ÉÒÔ¿´µ½Manifest¡¢ Resources¡¢AssetsµÄ×ÊÔ´¾­¹ýAAPT´¦ÀíºóÉú³ÉR.java¡¢ Proguard Configuration ¡¢Compiled Resources¡£ÆäÖÐR.java´ó¼Ò¶¼±È½ÏÊìϤ£¬ÕâÀï¾Í²»¹ý¶à½éÉÜÁË¡£ÎÒÃÇÀ´Öص㿴¿´Proguard Configuration ¡¢Compiled Resources¶¼ÊÇ×öʲôµÄÄØ£¿

Proguard Configuration ÊÇAAPT¹¤¾ßΪManifestÖÐÉùÃ÷µÄËÄ´ó×é¼þÒÔ¼°²¼¾ÖÎļþÖУ¨XML layouts£©Ê¹Óõĸ÷ÖÖViewsËùÉú³ÉµÄProGuardÅäÖ㬸ÃÎļþͨ³£´æ·ÅÔÚ${project.buildDir}/ $ {AndroidProject.FD _INTERMEDIATES} /proguard-rules/ ${flavorName}/ ${buildType}/aapt_rules.txt£¬ÏÂÃæÊÇÏîÄ¿ÖиÃÎļþµÄ½ØÍ¼£¬ºì¿ò±ê¼Ç³öÀ´µÄ¾ÍÊǶÔAndroidManifest.xml ¡¢XML LayoutsÖÐÏà¹Ø ClassµÄProGuardÅäÖá£

Compiled ResourcesÊÇÒ»¸öZip¸ñʽµÄÎļþ£¬Õâ¸öÎļþµÄ·¾¶Í¨³£Îª ${project.buildDir} /$ {AndroidProject.FD _INTERMEDIATES} /res/resources-$ {flavorName } -${buildType} -stripped.ap_¡£ ͨ¹ýÏÂÃæ¾­¹ýZip½âѹºóµÄ½ØÍ¼£¬¿ÉÒÔ¿´³öÕâ¸öÎļþ°üº¬ÁËres¡¢ AndroidManifest.xml ºÍresources.arscµÄÎļþ»òÎļþ¼Ð¡£½áºÏBuild WorkflowÖеÄÃèÊö£¬¿ÉÒÔ¿´³öÕâ¸öÎļþ£¨resources-$ {flavorName} -$ {buildType} -stripped.ap_£©»á±»apkbuilder´ò°üµ½APK°üÖУ¬ËüÆäʵ¾ÍÊÇAPKµÄ¡°×ÊÔ´°ü¡±£¨res¡¢ AndroidManifest.xml ºÍresources.arsc£©¡£

ÎÒÃǾÍÊÇͨ¹ýÕâ¸öÎļþÀ´Ð޸IJ»Í¬ºó׺Îļþ×ÊÔ´µÄѹËõ·½Ê½À´´ïµ½ÊÝÉíЧ¹ûµÄ£¬¶øÔÚºóÃæ¡°resources.arscµÄÓÅ»¯¡±Ò»½ÚÖÐÒ²ÊDzÙ×÷µÄÕâ¸öÎļþ¡£

±ÊÕßÔÚ×Ô¼ºµÄÏîÄ¿ÖÐÊÇͨ¹ýÔÚpackage${flavorName} Task£¨¸ÐÐËȤµÄͬѧ¿ÉÒԲ鿴ԴÂ룩֮ǰ½øÐÐÕâ¸ö²Ù×÷µÄ¡£

ÏÂÃæÊDz¿·Ö´úÂëÆ¬¶Î£º

appPlugin.variantManage r.variantDataList.each { variantData ->
variantData.outputs.each {
def sourceApFile = it.packageAndroidArtifactTask .getResourceFile();
def destApFile = new File ("${sourceApFile.name}.temp", sourceApFile.parentFile);
it.packageAndroidArtifactTask.doFirst {
byte[] buf = new byte[1024 * 8];

ZipInputStream zin = new ZipInputStream (new FileInputStream(sourceApFile));
ZipOutputStream out = new ZipOutputStream (new FileOutputStream(destApFile));

ZipEntry entry = zin.getNextEntry();
while (entry != null) {
String name = entry.getName();

// Add ZIP entry to output stream.
ZipEntry zipEntry = new ZipEntry(name);

if (ZipEntry.STORED == entry.getMethod() && !okayToCompress (entry.getName())) {
zipEntry.setMethod(ZipEntry.STORED)
zipEntry.setSize(entry.getSize())
zipEntry.setCompressedSize (entry.getCompressedSize())
zipEntry.setCrc(entry.getCrc())
} else {
zipEntry.setMethod(ZipEntry.DEFLATED)
...
}
...

out.putNextEntry(zipEntry);
out.closeEntry();
entry = zin.getNextEntry();
}
// Close the streams
zin.close();
out.close();

sourceApFile.delete();
destApFile.renameTo(sourceApFile);
}
}
}

µ±È»Ò²¿ÉÒÔÔÚÆäËü¹¹½¨²½ÖèÖвÉÓøü¸ßѹËõÂʵķ½Ê½À´´ïµ½ÊÝÉíЧ¹û£¬ÀýÈç²ÉÓÃ7ZipѹËõµÈµÈ¡£

±¾¼¼ÇɵÄʹÓÃÐèҪעÒâÒÔÏÂÎÊÌ⣺

Èç¹ûÒôÊÓÆµ×ÊÔ´±»Ñ¹Ëõ´æ·ÅÔÚAPKÖеϰ£¬ÔÚʹÓÃһЩÒôƵ¡¢ÊÓÆµAPIʱÓÈÆäҪעÒ⣬ÐèÒª×öºÃ³ä·ÖµÄ²âÊÔ¡£

resources.arscÎļþ×îºÃ²»ÒªÑ¹Ëõ´æ´¢£¬Èç¹ûѹËõ»áÓ°ÏìÒ»¶¨µÄÐÔÄÜ£¨ÓÈÆäÊÇÀäÆô¶¯Ê±¼ä£©¡£

Èç¹ûÏëÔÚAndroid 6.0ÉÏ¿ªÆô android:extractNativeLibs =¡±false ¡±µÄ»°£¬.so ÎļþÒ²²»Äܱ»Ñ¹Ëõ£¬ android:extractNativeLibsµÄʹÓÃ×ËÊÆ¿´ÕâÀApp Manifest --- application¡£

classes.dexµÄÓÅ»¯

ÈçºÎÓÅ»¯classes.dexµÄ´óÐ¡ÄØ£¿´óÌåÓÐÈçÏÂÌ×·£º

ʱ¿Ì±£³ÖÁ¼ºÃµÄ±à³Ìϰ¹ßºÍ¶Ô°üÌå»ýÃôÈñµÄÐá¾õ£¬È¥³ýÖØ¸´»òÕß²»ÓõĴúÂ룬É÷ÓõÚÈý·½¿â£¬Ñ¡ÓÃÌå»ýСµÄµÚÈý·½SDKµÈµÈ¡£

¿ªÆôProGuardÀ´½øÐдúÂëѹËõ£¬Í¨¹ýʹÓÃProGuardÀ´¶Ô´úÂë½øÐлìÏý¡¢ÓÅ»¯¡¢Ñ¹ËõµÈ¹¤×÷¡£

Õë¶ÔµÚÒ»ÖÖÌ×·£¬Òò¸÷¸ö¹«Ë¾µÄÏîÄ¿µÄ²îÒ죬¹²ÐԵĶ«Î÷½ÏÉÙ£¬ÐèÒªcase by caseµÄ·ÖÎö£¬ÕâÀï²»×ö¹ý¶àµÄ½éÉÜ¡£

ѹËõ´úÂë

¿ÉÒÔͨ¹ý¿ªÆôProGuardÀ´ÊµÏÖ´úÂëѹËõ£¬¿ÉÒÔÔÚbuild.gradleÎļþÏàÓ¦µÄ¹¹½¨ÀàÐÍÖÐÌí¼ÓminifyEnabled true¡£

Çë×¢Ò⣬´úÂëѹËõ»áÍÏÂý¹¹½¨ËÙ¶È£¬Òò´ËÓ¦¸Ã¾¡¿ÉÄܱÜÃâÔÚµ÷ÊÔ¹¹½¨ÖÐʹÓᣲ»¹ýÒ»¶¨ÒªÎªÓÃÓÚ²âÊÔµÄ×îÖÕAPKÆôÓôúÂëѹËõ£¬Èç¹û²»Äܳä·ÖµØ×Ô¶¨ÒåÒª±£ÁôµÄ´úÂ룬¿ÉÄÜ»áÒýÈë´íÎó¡£

ÀýÈ磬ÏÂÃæÕâ¶ÎÀ´×Ôbuild.gradleÎļþµÄ´úÂëÓÃÓÚΪ·¢²¼¹¹½¨ÆôÓôúÂëѹËõ£º

android {
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile(¡®proguard-android.txt'),
'proguard-rules.pro'
}
}
...
}

³ýÁËminifyEnabledÊôÐÔÍ⣬»¹ÓÐÓÃÓÚ¶¨ÒåProGuard¹æÔòµÄproguardFilesÊôÐÔ£º

getDefaultProguardFile (¡®proguard-android.txt') ÊÇ´Ó Android SDKtools/proguard/ Îļþ¼Ð»ñȡĬÈÏProGuardÉèÖá£

proguard-rules.proÎļþÓÃÓÚÌí¼Ó×Ô¶¨ÒåProGuard¹æÔò¡£Ä¬ÈÏÇé¿öÏ£¬¸ÃÎļþλÓÚÄ£¿é¸ùĿ¼£¨build.gradleÎļþÅÔ£©¡£

Ìáʾ£ºÒªÏë×ö½øÒ»²½µÄ´úÂëѹËõ£¬¿É³¢ÊÔʹÓÃλÓÚͬһλÖÃµÄ proguard-android-optimize.txt Îļþ¡£Ëü°üÀ¨ÏàͬµÄProGuard¹æÔò£¬µ«»¹°üÀ¨ÆäËûÔÚ×Ö½ÚÂëÒ»¼¶£¨·½·¨Äںͷ½·¨¼ä£©Ö´ÐзÖÎöµÄÓÅ»¯£¬ÒÔ½øÒ»²½¼õСAPK´óСºÍ°ïÖúÌá¸ßÆäÔËÐÐËÙ¶È¡£

ÔÚGradle Plugin 2.2.0¼°ÒÔÉϰ汾ProGuardµÄÅäÖÃÎļþ»á×Ô¶¯½âѹËõµ½ $ {rootProject.buildDir} /${AndroidProject .FD_INTERMEDIATES} /proguard-files/Ŀ¼Ï£¬proguardFiles»á´ÓÕâ¸öĿ¼À´»ñÈ¡ProGuardÅäÖá£

ÿ´ÎÖ´ÐÐÍêProGuardÖ®ºó£¬ProGuard¶¼»áÔÚ ${project.buildDir} / outputs/mapping/ $ {flavorDir}/Éú³ÉÒÔÏÂÎļþ£º

¿ÉÒÔͨ¹ýÔÚusage.txtÎļþÖп´µ½ÄÄЩ´úÂ뱻ɾ³ýÁË£¬ÈçÏÂͼÖÐËùʾandroid .support.multidex .MultiDexÒѾ­±»É¾³ýÁË£º

R FieldµÄÓÅ»¯

³ýÁ˶ÔÏîÄ¿´úÂëÓÅ»¯ºÍ¿ªÆô´úÂëѹËõÖ®Í⣬±ÊÕßÔÚ¡¶ÃÀÍÅAndroid DEX×Ô¶¯²ð°ü¼°¶¯Ì¬¼ÓÔØ¼ò½é¡·ÕâÆªÎÄÕÂÖÐÌáµ½ÁËͨ¹ýÄÚÁªR FieldÀ´½â¾öR Field¹ý¶àµ¼ÖÂMultiDex 65536µÄÎÊÌ⣬¶øÕâÒ»²½Öè¶Ô´úÂëÊÝÉíÄܹ»Æðµ½Ã÷ÏÔµÄЧ¹û¡£ÏÂÃæÊDZÊÕßͨ¹ý×Ö½ÚÂ빤¾ßÔÚ¹¹½¨Á÷³ÌÖÐÄÚÁªR FieldµÄ´úÂëÆ¬¶Î£¨×Ö½ÚÂëµÄÐ޸ĿÉÒÔʹÓÃJavassist»òÕßASM£¬¸Ã²½Öè±ÊÕß²ÉÓõÄÊÇJavassist£©¡£

ctBehaviors.each { CtBehavior ctBehavior ->
if (!ctBehavior.isEmpty()) {
try {
ctBehavior.instrument(new ExprEditor() {
@Override
public void edit(FieldAccess f) {
try {
def fieldClassName = JavassistUtils .getClassNameFromCtClass (f.getCtClass())
if (shouldInlineRField (className, fieldClassName) && f.isReader()) {
def temp = fieldClassName.substring (fieldClassName.indexOf (ANDROID_RESOURCE_R_FLAG) + ANDROID_RESOURCE_R_FLAG .length())
def fieldName = f.fieldName
def key = & quot;${temp} .${fieldName}"

if (resourceSymbols .containsKey (key)) {
Object obj = resourceSymbols.get(key)
try {
if (obj instanceof Integer) {
int value = ((Integer) obj).intValue()
f.replace("\$_=${value};")
} else if (obj instanceof Integer[]) {
def obj2 = ((Integer[]) obj)
StringBuilder stringBuilder = new StringBuilder()
for (int index = 0; index < obj2.length; ++index) {
stringBuilder.append (obj2[index].intValue())
if (index != obj2.length - 1) {
stringBuilder.append(",")
}
}
f.replace("\$_ = new int[] {${stringBuilder.toString()}};")
} else {
throw new GradleException (" Unknown ResourceSymbols Type!")
}
} catch (NotFoundException e) {
throw new GradleException(e.message)
} catch (CannotCompileException e) {
throw new GradleException(e.message)
}
} else {
throw new GradleException ("******** InlineRFieldTask unprocessed ${className}, ${fieldClassName}, ${f.fieldName}, ${key}")
}
}
} catch (NotFoundException e) {
}
}
})
} catch (CannotCompileException e) {
}
}
}

ÆäËüÓÅ»¯ÊÖ¶Î

Õë¶Ô´úÂëµÄÊÝÉí»¹ÓкܶàÓÅ»¯µÄ¼¼ÇÉ£¬ÀýÈ磺

¼õÉÙENUMµÄʹÓã¨ÏêÇé¿ÉÒԲο¼£ºRemove Enumerations£©£¬Ã¿¼õÉÙÒ»¸öENUM¿ÉÒÔ¼õÉÙ´óÔ¼1.0µ½1.4 KBµÄ´óС£»

ͨ¹ýpmd cpdÀ´¼ì²éÖØ¸´µÄ´úÂë´Ó¶ø½øÐдúÂëÓÅ»¯£»

ÒÆ³ýµôËùÓÐÎÞÓûòÕß¹¦ÄÜÖØ¸´µÄÒÀÀµ¿â¡£

ÕâЩÓÅ»¯¼¼ÇɾͲ»Õ¹¿ª½éÉÜÁË¡£

×ÊÔ´µÄÓÅ»¯

ͼƬÓÅ»¯

ΪÁËÖ§³ÖAndroidÉ豸DPIµÄ¶àÑù»¯ £¨[l|m|tv|h|x|xx|xxx]dpi£©ÒÔ¼°Óû§¶Ô¸ßÖÊÁ¿UIµÄÆÚ´ý£¬ÃÀÍÅAppÖÐʹÓÃÁË´óÁ¿µÄͼƬ£¬ÔÚAndroidÏÂÖ§³ÖºÜ¶à¸ñʽµÄͼƬ£¬ÀýÈ磺PNG¡¢JPG ¡¢WebP£¬ÄÇÎÒÃǸÃÔõôѡÔñ²»Í¬ÀàÐ͵ÄͼƬ¸ñÊ½ÄØ£¿ ÔÚGoogle I/O 2016ÖÐÌáµ½ÁËÕë¶ÔͼƬ¸ñʽµÄÑ¡Ôñ£¬À´¿´ÏÂͼ£¨Í¼Æ¬À´Ô´ÓÚImage compression for Android developers£©£º

ͨ¹ýÉÏͼ¿ÉÒÔ¿´³öÒ»¸ö´ó¸ÅͼƬ¸ñʽѡÔñµÄ·½·¨¡£Èç¹ûÄÜÓÃVectorDrawableÀ´±íʾµÄ»°ÓÅÏÈʹÓÃVectorDrawable£¬Èç¹ûÖ§³ÖWebPÔòÓÅÏÈÓÃWebP£¬¶øPNGÖ÷ÒªÓÃÔÚչʾ͸Ã÷»òÕß¼òµ¥µÄͼƬ£¬¶øÆäËü³¡¾°¿ÉÒÔʹÓÃJPG¸ñʽ¡£Õë¶ÔÿÖÖͼƬ¸ñʽҲÓи÷ÀàµÄÓÅ»¯ÊֶκÍÓÅ»¯¹¤¾ß¡£

ʹÓÃʸÁ¿Í¼Æ¬

¿ÉÒÔʹÓÃʸÁ¿Í¼ÐÎÀ´´´½¨¶ÀÁ¢ÓÚ·Ö±æÂʵÄͼ±êºÍÆäËû¿ÉÉìËõͼƬ¡£Ê¹ÓÃʸÁ¿Í¼Æ¬Äܹ»ÓÐЧµÄ¼õÉÙAppÖÐͼƬËùÕ¼ÓõĴóС£¬Ê¸Á¿Í¼ÐÎÔÚAndroidÖбíʾΪVectorDrawable¶ÔÏó¡£ Ê¹ÓÃVectorDrawable¶ÔÏó£¬100×Ö½ÚµÄÎļþ¿ÉÒÔÉú³ÉÆÁÄ»´óСµÄÇåÎúͼÏñ£¬µ«ÏµÍ³äÖȾÿ¸öVectorDrawable¶ÔÏóÐèÒª´óÁ¿µÄʱ¼ä£¬½Ï´óµÄͼÏñÐèÒª¸ü³¤µÄʱ¼ä²ÅÄܳöÏÖÔÚÆÁÄ»ÉÏ¡£ Òò´ËÖ»ÓÐÔÚÏÔʾСͼÏñʱ²Å¿¼ÂÇʹÓÃʸÁ¿Í¼ÐΡ£ÓйØÊ¹ÓÃVectorDrawableµÄ¸ü¶àÐÅÏ¢£¬Çë²ÎÔÄ Working with Drawables¡£

ʹÓÃWebP

Èç¹ûAppµÄminSdkVersion¸ßÓÚ14£¨Android 4.0+£©µÄ»°£¬¿ÉÒÔÑ¡ÓÃWebP¸ñʽ£¬ÒòΪWebPÔÚͬ»­ÖÊÏÂÌå»ý¸üС£¨WebPÖ§³Ö͸Ã÷¶È£¬Ñ¹Ëõ±È±ÈJPEG¸ü¸ßµ«ÏÔʾЧ¹ûÈ´²»ÊäÓÚJPEG£¬¹Ù·½ÆÀ²âquality²ÎÊýµÈÓÚ75¾ùºâ×î¼Ñ£©£¬ ¿ÉÒÔͨ¹ýPNGµ½WebPת»»¹¤¾ßÀ´½øÐÐת»»¡£µ±È»Android´Ó4.0²Å¿ªÊ¼WebPµÄÔ­ÉúÖ§³Ö£¬µ«ÊDz»Ö§³Ö°üº¬Í¸Ã÷¶È£¬Ö±µ½Android 4.2.1+²ÅÖ§³ÖÏÔʾº¬Í¸Ã÷¶ÈµÄWebP£¬ÔÚ±ÊÕßʹÓÃÖÐÊÇÅжϵ±Ç°AppµÄminSdkVersionÒÔ¼°Í¼Æ¬ÎļþµÄÀàÐÍ£¨ÊÇ·ñΪ͸Ã÷£©À´Ñ¡ÓÃÊÇ·ñÊÊÓÃWebP¡£¼ûÏÂÃæµÄ´úÂëÆ¬¶Î£º

boolean isPNGWebpConvertSupported() {
if (!isWebpConvertEnable()) {
return false
}

// Android 4.0+
return GradleUtils .getAndroidExtension(project) .defaultConfig.minSdkVersion .apiLevel >= 14
// 4.0
}

boolean is TransparencyPNGWebpConvertSupported () {
if (!isWebpConvertEnable()) {
return false
}

// Lossless, Transparency, Android 4.2.1+
return GradleUtils .getAndroidExtension (project) .defaultConfig .minSdkVersion .apiLevel >= 18
// 4.3
}

def convert() {
String resPath = "${project.buildDir} /$ {AndroidProject .FD_INTERMEDIATES} /res/merged/$ {variant.dirName}"
def resDir = new File("${resPath}")
resDir .eachDirMatch(~/drawable[a-z0-9-]*/) { dir ->
FileTree tree = project.fileTree(dir: dir)
tree.filter { File file ->
return (isJPGWebpConvertSupported () && (file.name .endsWith (SdkConstants.DOT_JPG) || file.name.endsWith (SdkConstants.DOT_JPEG))) || (isPNGWebpConvertSupported () && file.name.endsWith (SdkConstants.DOT_PNG) && !file .name.endsWith (SdkConstants.DOT_9PNG))
}.each { File file ->
def shouldConvert = true
if (file.name.endsWith (SdkConstants.DOT_PNG)) {
if (!isTransparencyPNGWebp ConvertSupported ()) {
shouldConvert = !Imaging.getImageInfo(file) .isTransparent()
}
}
if (shouldConvert) {
WebpUtils.encode (project, webpFactorQuality, file.absolutePath, webp)
}
}
}
}

Ñ¡Ôñ¸üÓŵÄѹËõ¹¤¾ß

¿ÉÒÔʹÓÃpngcrush¡¢pngquant»òzopflipngµÈѹËõ¹¤¾ßÀ´¼õÉÙPNGÎļþ´óС£¬¶ø²»»á¶ªÊ§Í¼ÏñÖÊÁ¿¡£ËùÓÐÕâЩ¹¤¾ß¶¼¿ÉÒÔ¼õÉÙPNGÎļþ´óС£¬Í¬Ê±±£³ÖͼÏñÖÊÁ¿¡£

pngcrush¹¤¾ßÌØ±ðÓÐЧ£º´Ë¹¤¾ßÔÚPNG¹ýÂËÆ÷ºÍzlib£¨Deflate£©²ÎÊýÉϵü´ú£¬Ê¹ÓùýÂËÆ÷ºÍ²ÎÊýµÄÿ¸ö×éºÏÀ´Ñ¹ËõͼÏñ¡£È»ºóÑ¡Ôñ²úÉú×îСѹËõÊä³öµÄÅäÖá£

¶ÔÓÚJPEGÎļþ£¬Äã¿ÉÒÔʹÓÃpackJPG»òguetzliµÈ¹¤¾ß½«JPEGÎļþѹËõµÄ¸üС£¬ÕâЩ¹¤¾ßÄܹ»ÔÚ±£³ÖͼƬÖÊÁ¿²»±äµÄÇé¿öÏ£¬°ÑͼƬÎļþѹËõµÄ¸üС¡£guetzli¹¤¾ß¸üÊÇÄܹ»ÔÚͼƬÖÊÁ¿²»±äµÄÇé¿öÏ£¬½«Îļþ´óС½µµÍ35%¡£

ÔÚAndroid¹¹½¨Á÷³ÌÖÐAAPT»áʹÓÃÄÚÖõÄѹËõËã·¨À´ÓÅ»¯res/drawable/Ŀ¼ÏµÄPNGͼƬ£¬µ«Ò²¿ÉÄܻᵼÖ±¾À´ÒѾ­ÓÅ»¯¹ýµÄͼƬÌå»ý±ä´ó£¬¿ÉÒÔͨ¹ýÔÚbuild.gradleÖÐÉèÖÃcruncherEnabledÀ´½ûÖ¹AAPTÀ´ÓÅ»¯PNGͼƬ¡£

aaptOptions {
cruncherEnabled = false
}

¿ªÆô×ÊԴѹËõ

AndroidµÄ±àÒ빤¾ßÁ´ÖÐÌṩÁËÒ»¿î×ÊԴѹËõµÄ¹¤¾ß£¬¿ÉÒÔͨ¹ý¸Ã¹¤¾ßÀ´Ñ¹Ëõ×ÊÔ´£¬Èç¹ûÒªÆôÓÃ×ÊԴѹËõ£¬¿ÉÒÔÔÚbuild.gradleÎļþÖн«shrinkResources true¡£ÀýÈ磺

android {
...
buildTypes {
release {
shrinkResources true
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'),
'proguard-rules.pro'
}
}
}

ÐèҪעÒâµÄÊÇĿǰ×ÊԴѹËõÆ÷Ŀǰ²»»áÒÆ³ývalues/Îļþ¼ÐÖж¨ÒåµÄ×ÊÔ´£¨ÀýÈç×Ö·û´®¡¢³ß´ç¡¢ÑùʽºÍÑÕÉ«£©£¬ÓйØÏêÇ飬Çë²ÎÔÄÎÊÌâ 70869¡£

Android¹¹½¨¹¤¾ßÊÇͨ¹ýResourceUsageAnalyzerÀ´¼ì²éÄÄЩ×ÊÔ´ÊÇÎÞÓõ쬵±¼ì²éµ½ÎÞÓõÄ×ÊԴʱ»á°Ñ¸Ã×ÊÔ´Ìæ»»³ÉÔ¤¶¨ÒåµÄ°æ±¾¡£Ïê¿´ÏÂÃæ´úÂëÆ¬¶Î£¨Õª×Ôcom.android .build .gradle.tasks .ResourceUsageAnalyzer£©£º

public class ResourceUsageAnalyzer {
...

/**
* Whether we should create small/empty dummy files instead of actually
* removing file resources. This is to work around crashes on some devices
* where the device is traversing resources. See http://b.android.com/79325 for more.
*/
public static final boolean REPLACE_DELETED_WITH_EMPTY = true;

// A 1x1 pixel PNG of type BufferedImage.TYPE_BYTE_GRAY
public static final byte[] TINY_PNG = new byte[] {
(byte)-119, (byte) 80, (byte) 78, (byte) 71, (byte) 13, (byte) 10,
(byte) 26, (byte) 10, (byte) 0, (byte) 0, (byte) 0, (byte) 13,
(byte) 73, (byte) 72, (byte) 68, (byte) 82, (byte) 0, (byte) 0,
(byte) 0, (byte) 1, (byte) 0, (byte) 0, (byte) 0, (byte) 1,
(byte) 8, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 58,
(byte) 126, (byte)-101, (byte) 85, (byte) 0, (byte) 0, (byte) 0,
(byte) 10, (byte) 73, (byte) 68, (byte) 65, (byte) 84, (byte) 120,
(byte) -38, (byte) 99, (byte) 96, (byte) 0, (byte) 0, (byte) 0,
(byte) 2, (byte) 0, (byte) 1, (byte) -27, (byte) 39, (byte) -34,
(byte) -4, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 73,
(byte) 69, (byte) 78, (byte) 68, (byte) -82, (byte) 66, (byte) 96,
(byte)-126
};

public static final long TINY_PNG_CRC = 0x88b2a3b0L;

// A 3x3 pixel PNG of type BufferedImage.TYPE_INT_ARGB with 9-patch markers
public static final byte[] TINY_9PNG = new byte[] {
(byte)-119, (byte) 80, (byte) 78, (byte) 71, (byte) 13, (byte) 10,
(byte) 26, (byte) 10, (byte) 0, (byte) 0, (byte) 0, (byte) 13,
(byte) 73, (byte) 72, (byte) 68, (byte) 82, (byte) 0, (byte) 0,
(byte) 0, (byte) 3, (byte) 0, (byte) 0, (byte) 0, (byte) 3,
(byte) 8, (byte) 6, (byte) 0, (byte) 0, (byte) 0, (byte) 86,
(byte) 40, (byte) -75, (byte) -65, (byte) 0, (byte) 0, (byte) 0,
(byte) 20, (byte) 73, (byte) 68, (byte) 65, (byte) 84, (byte) 120,
(byte) -38, (byte) 99, (byte) 96, (byte)-128, (byte)-128, (byte) -1,
(byte) 12, (byte) 48, (byte) 6, (byte) 8, (byte) -96, (byte) 8,
(byte)-128, (byte) 8, (byte) 0, (byte)-107, (byte)-111, (byte) 7,
(byte) -7, (byte) -64, (byte) -82, (byte) 8, (byte) 0, (byte) 0,
(byte) 0, (byte) 0, (byte) 0, (byte) 73, (byte) 69, (byte) 78,
(byte) 68, (byte) -82, (byte) 66, (byte) 96, (byte)-126
};

public static final long TINY_9PNG_CRC = 0x1148f987L;

// The XML document <x/> as binary-packed with AAPT
public static final byte[] TINY_XML = new byte[] {
(byte) 3, (byte) 0, (byte) 8, (byte) 0, (byte) 104, (byte) 0,
(byte) 0, (byte) 0, (byte) 1, (byte) 0, (byte) 28, (byte) 0,
(byte) 36, (byte) 0, (byte) 0, (byte) 0, (byte) 1, (byte) 0,
(byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0,
(byte) 0, (byte) 1, (byte) 0, (byte) 0, (byte) 32, (byte) 0,
(byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0,
(byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 1, (byte) 1,
(byte) 120, (byte) 0, (byte) 2, (byte) 1, (byte) 16, (byte) 0,
(byte) 36, (byte) 0, (byte) 0, (byte) 0, (byte) 1, (byte) 0,
(byte) 0, (byte) 0, (byte) -1, (byte) -1, (byte) -1, (byte) -1,
(byte) -1, (byte) -1, (byte) -1, (byte) -1, (byte) 0, (byte) 0,
(byte) 0, (byte) 0, (byte) 20, (byte) 0, (byte) 20, (byte) 0,
(byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0,
(byte) 0, (byte) 0, (byte) 3, (byte) 1, (byte) 16, (byte) 0,
(byte) 24, (byte) 0, (byte) 0, (byte) 0, (byte) 1, (byte) 0,
(byte) 0, (byte) 0, (byte) -1, (byte) -1, (byte) -1, (byte) -1,
(byte) -1, (byte) -1, (byte) -1, (byte) -1, (byte) 0, (byte) 0,
(byte) 0, (byte) 0
};

public static final long TINY_XML_CRC = 0xd7e65643L;

...
}

ÉÏÃæ½ØÍ¼ÖÐ3¸öbyteÊý×éµÄ¶¨Òå¾ÍÊÇ×ÊԴѹËõ¹¤¾ßΪÎÞÓÃ×ÊÔ´ÌṩµÄÔ¤¶¨Òå°æ±¾£¬¿ÉÒÔ¿´³ö¶Ô.pngÌṩÁËTINY_PNG£¬ ¶Ô.9.pngÌṩÁËTINY_9PNGÒÔ¼°¶Ô.xmlÌṩÁËTINY_XMLµÄÔ¤¶¨Òå°æ±¾¡£

×ÊԴѹËõ¹¤¾ßµÄÏêϸʹÓÿÉÒԲο¼Shrink Your Code and Resources¡£×ÊԴѹËõ¹¤¾ßĬÈÏÊDzÉÓð²È«Ñ¹ËõģʽÀ´ÔËÐУ¬¿ÉÒÔͨ¹ý¿ªÆôÑϸñѹËõģʽÀ´´ïµ½¸üºÃµÄÊÝÉíЧ¹û¡£

Èç¹ûÏëÖªµÀÄÄЩ×ÊÔ´ÊÇÎÞÓõģ¬¿ÉÒÔͨ¹ý×ÊԴѹËõ¹¤¾ßµÄÊä³öÈÕÖ¾Îļþ ${project.buildDir} /outputs /mappin g /release/resources.txtÀ´²é¿´¡£ÈçÏÂͼËùʾres/layout /abc_activity _chooser_viewer .xml¾ÍÊÇÎÞÓõģ¬È»ºó±»Ô¤¶¨ÒåµÄ°æ±¾TINY_XMLËùÌæ»»£º

×ÊԴѹËõ¹¤¾ßÖ»ÊǰÑÎÞÓÃ×ÊÔ´Ìæ»»³ÉÔ¤¶¨Òå½ÏСµÄ°æ±¾£¬ÄÇÎÒÃÇÈçºÎɾ³ýÕâЩÎÞÓÃ×ÊÔ´ÄØ£¿Í¨³£µÄ×ö·¨ÊǽáºÏ×ÊԴѹËõ¹¤¾ßµÄÊä³öÈÕÖ¾£¬ÕÒµ½ÕâЩ×ÊÔ´²¢°ÑËüÃǽøÐÐɾ³ý¡£µ«ÔÚ±ÊÕßµÄÏîÄ¿ÖкܶàÎÞÓÃ×ÊÔ´ÊDZ»ÆäËü×é¼þ»òµÚÈý·½SDKËùÒýÈëµÄ£¬Èç¹û²ÉÓÃÕâÖÖÓÅ»¯·½Ê½»á´øÀ´ÕâЩSDKºóÆÚά»¤³É±¾µÄÔö¼Ó£¬Õë¶ÔÕâÖÖÇé¿ö±ÊÕßÊÇͨ¹ý²ÉÓÃÔÚresources.arscÖÐ×öÓÅ»¯À´½â¾öµÄ£¬ÏêÇé¿´ÏÂÃæ¡°resources.arscµÄÓÅ»¯¡±Ò»½ÚµÄ½éÉÜ¡£

ÓïÑÔ×ÊÔ´ÓÅ»¯

¸ù¾ÝApp×ÔÉíÖ§³ÖµÄÓïÑ԰汾ѡÓúÏÊʵÄÓïÑÔ×ÊÔ´£¬ÀýÈçʹÓÃÁËAppCompat£¬Èç¹û²»×öÈκÎÅäÖõϰ£¬×îÖÕAPK°üÖлá°üº¬AppCompatÖÐÏûÏ¢µÄËùÓÐÒÑ·­ÒëÓïÑÔ×Ö·û´®£¬ÎÞÂÛÓ¦ÓÃµÄÆäÓಿ·ÖÊÇ·ñ·­ÒëΪͬһÓïÑÔ£¬¿ÉÒÔͨ¹ýresConfigÀ´ÅäÖÃʹÓÃÄÄЩÓïÑÔ£¬´Ó¶øÈù¹½¨¹¤¾ßÒÆ³ýÖ¸¶¨ÓïÑÔÖ®ÍâµÄËùÓÐ×ÊÔ´¡£ÏÂͼÊǾßÌåµÄÅäÖÃʾÀý£º

android {
...
defaultConfig {
...
resConfigs "zh", "zh-rCN"
}
...
}

Õë¶ÔΪ²»Í¬DPIËùÌṩµÄͼƬҲ¿ÉÒÔ²ÉÓÃÏàͬµÄ²ßÂÔ£¬ÐèÒªÕë¶Ô×ÔÉíµÄÄ¿±êÓû§ºÍÄ¿±êÉ豸×öÒ»¶¨µÄÑ¡Ôñ£¬¿ÉÒԲο¼ Support Only Specific DensitiesÀ´²Ù×÷¡£ÓÐ¹ØÆÁÄ»ÃܶȵÄÏêϸÐÅÏ¢£¬Çë²ÎÔÄScreen Sizes and Densities¡£

¶Ô.soÎļþÒ²¿ÉÒÔ²ÉÓÃÀàËÆµÄ²ßÂÔ£¬±ÈÈç±ÊÕßµÄÏîÄ¿ÖÐÖ»±£ÁôÁËarmeabi°æ±¾µÄ.soÎļþ¡£

resources.arscµÄÓÅ»¯

Õë¶Ôresources.arsc£¬±ÊÕß³¢ÊÔ¹ýµÄÓÅ»¯ÊÖ¶ÎÈçÏ£º

¿ªÆô×ÊÔ´»ìÏý£»

¶ÔÖØ¸´µÄ×ÊÔ´½øÐÐÓÅ»¯£»

¶Ô±»shrinkResourcesÓÅ»¯µôµÄ×ÊÔ´½øÐд¦Àí¡£

ÏÂÃæ½«·Ö±ð¶ÔÕâЩÓÅ»¯ÊֶνøÐÐÕ¹¿ª½éÉÜ¡£

×ÊÔ´»ìÏý

ÔÚ±ÊÕßÁíһƪ¡¶ÃÀÍÅAndroid×ÊÔ´»ìÏý±£»¤Êµ¼ù¡·ÎÄÕÂÖнéÉÜÁ˲ÉÓöÔ×ÊÔ´»ìÏýµÄ·½Ê½À´±£»¤×ÊÔ´µÄ°²È«£¬Í¬Ê±Ò²Ìáµ½ÁËÕâÖÖ·½Ê½ÓÐÏÔÖøµÄÊÝÉíЧ¹û¡£±ÊÕßµ±Ê±ÊDzÉÓÃÐÞ¸ÄAAPTµÄÏà¹ØÔ´ÂëµÄ·½Ê½£¬ÕâÖÖ·½Ê½µÄÍ´µãÊÇÿ´ÎÉý¼¶Build Tools¶¼ÒªÐÞ¸ÄÒ»´ÎAAPTÔ´Â룬ά»¤ÐԽϲĿǰ±ÊÕß²ÉÓÃÁË΢ÐÅ¿ªÔ´µÄ×ÊÔ´»ìÏý¿âAndResGuard£¬¾ßÌåµÄÔ­ÀíºÍʹÓðïÖú¿ÉÒԲο¼°²×°°üÁ¢¼õ1M--΢ÐÅAndroid×ÊÔ´»ìÏý´ò°ü¹¤¾ß¡£

ÎÞÓÃ×ÊÔ´ÓÅ»¯

ÔÚÉÏÒ»½ÚÖнéÉÜÁË¿ÉÒÔͨ¹ýshrinkResources trueÀ´¿ªÆô×ÊԴѹËõ£¬×ÊԴѹËõ¹¤¾ß»á°ÑÎÞÓõÄ×ÊÔ´Ìæ»»³ÉÔ¤¶¨ÒåµÄ°æ±¾¶ø²»ÊÇÒÆ³ý£¬Èç¹û²ÉÓÃÈ˹¤ÒƳýµÄ·½Ê½»á´øÀ´ºóÆÚµÄά»¤³É±¾£¬ÕâÀï±ÊÕß²ÉÓÃÁËÒ»ÖֱȽÏÈ¡Çɵķ½Ê½£¬ÔÚAndroid¹¹½¨¹¤¾ßÖ´ÐÐpackage${flavorName}Task֮ǰͨ¹ýÐÞ¸ÄCompiled ResourcesÀ´ÊµÏÖ×Ô¶¯È¥³ýÎÞÓÃ×ÊÔ´¡£

¾ßÌåÁ÷³ÌÈçÏ£º

ÊÕ¼¯×ÊÔ´°ü£¨Compiled ResourcesµÄ¼ò³Æ£©Öб»Ìæ»»µÄÔ¤¶¨Òå°æ±¾µÄ×ÊÔ´Ãû³Æ£¬Í¨¹ý²é¿´×ÊÔ´°ü£¨Zip¸ñʽ£©ÖÐÿ¸öZipEntryµÄCRC-32 checksumÀ´Ñ°ÕÒ±»Ìæ»»µÄÔ¤¶¨Òå×ÊÔ´£¬Ô¤¶¨Òå×ÊÔ´µÄCRC-32¶¨ÒåÔÚResourceUsageAnalyzer£¬ÏÂÃæÊÇËüÃǵ͍Òå¡£

// A 1x1 pixel PNG of type BufferedImage.TYPE_BYTE_GRAY
public static final long TINY_PNG_CRC = 0x88b2a3b0L;

// A 3x3 pixel PNG of type BufferedImage.TYPE_INT_ARGB with 9-patch markers
public static final long TINY_9PNG_CRC = 0x1148f987L;

// The XML document <x/> as binary-packed with AAPT
public static final long TINY_XML_CRC = 0xd7e65643L;

ͨ¹ýandroid-chunk-utils°Ñresources.arscÖжÔÓ¦µÄ¶¨ÒåÒÆ³ý£»

ɾ³ý×ÊÔ´°üÖжÔÓ¦µÄ×ÊÔ´Îļþ¡£

ÖØ¸´×ÊÔ´ÓÅ»¯

ĿǰÃÀÍÅAppÊÇÓɸ÷¸öÒµÎñÍŶӹ²Í¬¿ª·¢Íê³É£¬ÎªÁË·½±ã¸÷ÒµÎñÍŶӵĶÀÁ¢¿ª·¢£¬ÃÀÍÅApp½øÐÐÁËÆ½Ì¨»¯¸ÄÔì¡£¸ÄÔìʱ´æÔںܶà×ÊÔ´Îļþ£¨È磺drawable¡¢layoutµÈ£©±»²»Í¬µÄÒµÎñÍŶӶ¼¿½±´µ½×Ô¼ºµÄLibraryÏ£¬Í¬Ê±ÎªÁ˱ÜÃâÒý·¢×ÊÔ´¸²¸ÇµÄÎÊÌ⣬ÿ¸öÒµÎñÍŶӶ¼»áΪ×Ô¼ºµÄ×ÊÔ´ÎļþÃûÌí¼Óǰ׺¡£ÕâÑù¾Íµ¼ÖÂÁËÕâЩ×ÊÔ´ÎļþËäÈ»ÄÚÈÝÏàͬ£¬µ«ÒòΪÃû³ÆµÄ²»Í¬¶ø²»Äܱ»¸²¸Ç£¬×îÖÕ¶¼»á±»¼¯³Éµ½APK°üÖУ¬Õë¶ÔÕâÖÖÎÊÌâ±ÊÕß²ÉÓÃÁ˺ÍÇ°Ãæ¡°ÎÞÓÃ×ÊÔ´ÓÅ»¯¡±Ò»½ÚÖÐÃèÊöÀàËÆµÄ²ßÂÔ¡£

¾ßÌå²½ÖèÈçÏ£º

ͨ¹ý×ÊÔ´°üÖеÄÿ¸öZipEntryµÄ CRC-32 checksumÀ´É¸Ñ¡³öÖØ¸´µÄ×ÊÔ´£»

ͨ¹ýandroid-chunk-utilsÐÞ¸Ä resources.arsc£¬°ÑÕâÐ©ÖØ¸´µÄ×ÊÔ´¶¼Öض¨Ïòµ½Í¬Ò»¸öÎļþÉÏ£»

°ÑÆäËüÖØ¸´µÄ×ÊÔ´Îļþ´Ó×ÊÔ´°üÖÐɾ³ý¡£

´úÂëÆ¬¶Î£º

variantData.outputs.each {
def apFile = it.packageAndroidArtifactTask .getResourceFile();

it.packageAndroidArtifactTask.doFirst {
def arscFile = new File (apFile.parentFile, " resources.arsc");
JarUtil.extractZipEntry (apFile, "resources.arsc", arscFile);

def HashMap<String, ArrayList<DuplicatedEntry>> duplicatedResources = findDuplicatedResources(apFile);

removeZipEntry (apFile, "resources.arsc");

if (arscFile.exists()) {
FileInputStream arscStream = null;
ResourceFile resourceFile = null;
try {
arscStream = new FileInputStream(arscFile);

resourceFile = ResourceFile.fromInputStream (arscStream);
List<Chunk> chunks = resourceFile.getChunks();

HashMap<String, String> toBeReplacedResourceMap = new HashMap<String, String>(1024);

// ´¦Àíarsc²¢É¾³ýÖØ¸´×ÊÔ´
Iterator<Map.Entry< String, ArrayList< DuplicatedEntry>>> iterator = duplicatedResources .entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<String, ArrayList< DuplicatedEntry>> duplicatedEntry = iterator.next();

// ±£ÁôµÚÒ»¸ö×ÊÔ´£¬ ÆäËû×ÊԴɾ³ýµô
for (def index = 1; index < duplicatedEntry.value.size(); ++index) {
removeZipEntry (apFile, duplicatedEntry .value.get (index).name);

toBeReplacedResourceMap. put (duplicatedEntry.value.get (index).name, duplicatedEntry.value.get(0).name);
}
}

for (def index = 0; index < chunks.size(); ++index) {
Chunk chunk = chunks.get(index);
if (chunk instanceof ResourceTableChunk) {
ResourceTableChunk resourceTableChun k = (ResourceTableChunk) chunk;
StringPoolChunk stringPoolChunk = resourceTableChunk.getStringPool();
for (def i = 0; i < stringPoolChunk.stringCount; ++i) {
def key = stringPoolChunk.getString(i);
if (toBeReplacedResourceMap .containsKey(key)) {
stringPoolChunk.setString (i, toBeReplacedResourceMap .get(key));
}
}
}
}

} catch (IOException ignore) {
} catch (FileNotFoundException ignore) {
} finally {
if (arscStream != null) {
IOUtils.closeQuietly(arscStream);
}

arscFile.delete();
arscFile << resourceFile.toByteArray();

addZipEntry(apFile, arscFile);
}
}
}
}

ͨ¹ýÕâÖÖ·½Ê½¿ÉÒÔÓÐЧ¼õÉÙÖØ¸´×ÊÔ´¶Ô°üÌå´óСµÄÓ°Ï죬ͬʱÕâÖÖ²Ù×÷·½Ê½¶Ô¸÷ÒµÎñÍŶÓ͸Ã÷£¬Ò²²»»áÔö¼ÓЭµ÷Ïàͬ×ÊÔ´ÈçºÎ±»²»Í¬ÒµÎñÍŶӸ´Óõijɱ¾¡£

×ܽá

ÉÏÊö¾ÍÊÇÎÒÃÇĿǰÔÚAPKÊÝÉí·½ÃæµÄ×öµÄһЩ³¢ÊԺͻýÀÛ£¬¿ÉÒÔ¸ù¾Ý×ÔÉíÇé¿öÈ¡ÉáʹÓᣵ±È»ÎÒÃÇ»¹¿ÉÒÔ²ÉȡһЩ°´Ðè¼ÓÔØµÄ²ßÂÔÀ´¼õÉÙ°²×°°üµÄÌå»ý¡£×îºóÌáÒ»µã£¬¿³µô²»±ØÒªµÄ¹¦ÄܲÅÊǰ²×°°üÊÝÉíµÄ³¬¼¶´óÕС£Ò»¸öºÃµÄAppµÄ±ê×¼ÓÐºÜ¶à·½Ãæ£¬µ«Ìṩ¾¡¿ÉÄÜСµÄ°²×°°üÊÇÆäÖÐÒ»¸öÖØÒªµÄ·½Ã棬ÕâÒ²ÊǶÔÎÒÃÇAndroid¿ª·¢ÕßÈËÔ±×ÔÉíµÄÌá³öµÄ»ù±¾ÒªÇó£¬ÒªÊ±¿Ì±£³ÖÁ¼ºÃµÄ±à³Ìϰ¹ßºÍ¶Ô°üÌå»ýÃôÈñµÄÐá¾õ¡£

   
3018 ´Îä¯ÀÀ       30
Ïà¹ØÎÄÕÂ

Éî¶È½âÎö£ºÇåÀíÀôúÂë
ÈçºÎ±àд³öÓµ±§±ä»¯µÄ´úÂë
ÖØ¹¹-ʹ´úÂë¸ü¼ò½àÓÅÃÀ
ÍŶÓÏîÄ¿¿ª·¢"±àÂë¹æ·¶"ϵÁÐÎÄÕÂ
Ïà¹ØÎĵµ

ÖØ¹¹-¸ÄÉÆ¼ÈÓдúÂëµÄÉè¼Æ
Èí¼þÖØ¹¹v2
´úÂëÕû½àÖ®µÀ
¸ßÖÊÁ¿±à³Ì¹æ·¶
Ïà¹Ø¿Î³Ì

»ùÓÚHTML5¿Í»§¶Ë¡¢Web¶ËµÄÓ¦Óÿª·¢
HTML 5+CSS ¿ª·¢
ǶÈëʽC¸ßÖÊÁ¿±à³Ì
C++¸ß¼¶±à³Ì