xml attribute exception
异常信息
由于属性值包含 0x0, 如: <LinearLayout android:layout_gravity="0x0" android:orientation="horizontal" 导致编译时异常, 异常信息如下
java
W: C:\Users\ADMINI~1\AppData\Local\Temp\APKTOOL4940937019646549448-12345\res\layout\cas_ip_activity.xml:11: error: '0x0' is incompatible with attribute layout_gravity (attr) flags [bottom=80, center=17, center_horizontal=1, center_vertical=16, clip_horizontal=8, clip_vertical=128, end=8388613, fill=119, fill_horizontal=7, fill_vertical=112, left=3, right=5, start=8388611, top=48].
W: error: failed linking file resources.如下图

解决思路
通过修改 apktool 源码, 判断属性值为 0x0 则替换为 "", 改动如下
java/brut/androlib/res/decoder/BinaryXmlResourceParser.java
java
@Override
public String getAttributeValue(int index) {
Attribute attr = getAttribute(index);
if (attr == null) {
return "";
}
// Use the raw value if preserved (rare for modern apps).
if (mHasRawValues && !mIgnoreRawValues) {
String rawValue = mStringPool != null ? mStringPool.getString(attr.rawValue) : null;
if (rawValue != null) {
return rawValue;
}
}
// Try to decode the typed value from the resource table.
ResItem value = null;
String name = null;
String decoded = null;
try {
ResPackage pkg = mTable.getMainPackage();
if (pkg == null) {
// If no main package, we load "android" package instead.
pkg = mTable.resolvePackageGroup(ResTable.SYS_PACKAGE_ID).getBasePackage();
}
if (attr.valueType == ResValue.TYPE_STRING) {
CharSequence strValue = mStringPool != null ? mStringPool.getText(attr.valueData) : null;
value = strValue != null ? new ResString(strValue) : null;
} else {
value = ResItem.parse(pkg, attr.valueType, attr.valueData);
}
if (value != null) {
ResId nameId = getAttributeNameResourceId(index);
if (nameId != ResId.NULL) {
// We need the attribute entry's value to format this value.
try {
ResEntry nameEntry = mTable.resolveEntry(nameId);
name = nameEntry.getName();
if (nameEntry.getValue() instanceof ResAttribute) {
ResAttribute nameValue = (ResAttribute) nameEntry.getValue();
// Add the value type to the attribute if needed.
boolean isExplicitType;
switch (attr.valueType) {
case ResValue.TYPE_NULL:
case ResValue.TYPE_REFERENCE:
case ResValue.TYPE_DYNAMIC_REFERENCE:
case ResValue.TYPE_ATTRIBUTE:
case ResValue.TYPE_DYNAMIC_ATTRIBUTE:
isExplicitType = false;
break;
default:
isExplicitType = true;
break;
}
if (isExplicitType && !nameValue.hasSymbolsForValue(value)) {
nameValue.addValueType(attr.valueType);
}
decoded = nameValue.formatAsAttributeValue(value);
if (decoded.equals("0x0")) {
System.out.println("W: 发现零值: " + name + "=" + decoded);
decoded = "";
System.out.println("W: 替换零值: " + name + "=" + decoded);
}
} else {
Log.w(TAG, "Unexpected attribute name: " + nameEntry);
}
} catch (UndefinedResObjectException ignored) {
}
} else {
// Format the value with the default attribute.
decoded = ResAttribute.DEFAULT.formatAsAttributeValue(value);
}
}
} catch (AndrolibException ex) {
if (mFirstError == null) {
mFirstError = ex;
}
}
if (decoded == null) {
if (name == null) {
name = mStringPool != null ? mStringPool.getString(attr.name) : null;
}
Log.w(TAG, "Could not decode attribute value: ns=%s, name=%s, type=0x%02x, value=0x%08x",
getAttributePrefix(index), name, attr.valueType, attr.valueData);
if (value != null) {
// Format the value with the default attribute.
try {
decoded = ResAttribute.DEFAULT.formatAsAttributeValue(value);
} catch (AndrolibException ignored) {
}
}
if (decoded == null) {
decoded = "";
}
}
return decoded;
}