aapt 如何修改资源ID
2016-01-10 20:55
337 查看
在android项目中,出现资源ID(packageId+typeId+ItemValue)发生冲突的问题。特别是插件化开发的需求背景时(网上有很多解决方案,不一一列举,如public 限定等)。那么对于我们自己提供的库包,如果能指定其包的命令空间(默认是从127开始),特别考虑mutiDex的情况,自定义修改package
ID显得意义重大。网上已经有很多修改package ID 的AAPT可执行文件(但是绝大部分不提供源码,觉得很神,就决定自己研究一下),通过命令行参数提供package ID赋值,现在从aapt资源打包源码流程角度,讲解该过程中何时会生成应用程序包的package ID, 然后如何进行修改。
aapt首先根据命令行参数路径,寻找到androidmanifest文件,提取出应用程序的名称,创建resourceTable.
具体调用路径main(main.cpp)-->handleCommand(command.cpp)->doPackage-->buildResources(Resource.cpp)
status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets)
{
// First, look for a
package file to parse. This is required to
// be able to generate the resource information.
sp<AaptGroup> androidManifestFile =
assets->getFiles().valueFor(String8("AndroidManifest.xml"));
if (androidManifestFile == NULL) {
fprintf(stderr, "ERROR: No AndroidManifest.xml file found.\n");
return UNKNOWN_ERROR;
}
status_t err = parsePackage(bundle, assets, androidManifestFile);
if (err != NO_ERROR) {
return err;
}
NOISY(printf("Creating resources for package %s\n",
assets->getPackage().string()));
ResourceTable table(bundle, String16(assets->getPackage()));
err = table.addIncludedResources(bundle, assets);
从第5行到第20行,我们需要关注的过程主要是读取androidManifest.xml内的应用名称(parsePackage比较麻烦,它会收集工程XML文件的元素<资源>信息,并对XML进行扁平压缩,最终写入到ResXMLTree的数据结构中),来创建一个资源表Resourcetable(资源打包最后阶段会根据该内容生成资源索引表resources.arsc),在上述代码第21行,我们能看到table.addIncludedResources(bundle, assets);该函数主要是用于添加被引用的资源包,当然一般是系统资源包android.jar.
status_t ResourceTable::addIncludedResources(Bundle* bundle, const sp<AaptAssets>& assets)
{
status_t err = assets->buildIncludedResources(bundle);
if (err != NO_ERROR) {
return err;
}
// For future reference to included
resources.
mAssets = assets;
const ResTable& incl = assets->getIncludedResources();
// Retrieve all the packages.
const size_t N = incl.getBasePackageCount();
for (size_t phase=0; phase<2; phase++) {
for (size_t i=0; i<N; i++) {
String16 name(incl.getBasePackageName(i));
uint32_t id = incl.getBasePackageId(i);
// First time through: only
add base packages (id
// is not 0); second time through
add the other
// packages.
if (phase != 0) {
if (id != 0) {
// Skip base packages -- already
one.
id = 0;
} else {
// Assign a dynamic id.
id = mNextPackageId;
}
} else if (id != 0) {
if (id == 127) {
if (mHaveAppPackage) {
fprintf(stderr, "Included resources have two application
packages!\n");
return UNKNOWN_ERROR;
}
mHaveAppPackage = true;
}
if (mNextPackageId > id) {
fprintf(stderr, "Included base package ID %d already in
use!\n", id);
return UNKNOWN_ERROR;
}
}
if (id != 0) {
NOISY(printf("Including package %s with ID=%d\n",
String8(name).string(), id));
sp<Package> p = new Package(name, id);
mPackages.add(name, p);
mOrderedPackages.add(p);
if (id >= mNextPackageId) {
mNextPackageId = id+1;
}
}
}
}
// Every resource table always has one first entry, the bag attributes.
const SourcePos unknown(String8("????"), 0);
sp<Type> attr = getType(mAssetsPackage, String16("attr"), unknown);
return NO_ERROR;
}
从上述代码14行到第55行,描述了添加引用依赖包的过程,核心在第46-48行,以Pair的格式存入依赖包(注意ID为包命名空间8位二进制,系统层为1)。
从第59行getType()开始就要进入到当前资源包ID的命名了,ResourceTable::getType()---》call
ResourceTable::getPackages()
sp<ResourceTable::Package> ResourceTable::getPackage(const String16& package)
{
sp<Package> p = mPackages.valueFor(package);
if (p == NULL) {
if (mBundle->getIsOverlayPackage()) {
p = new Package(package, 0x00);
} else if (mIsAppPackage) {
if (mHaveAppPackage) {
fprintf(stderr, "Adding multiple application package resources;
only one is allowed.\n"
"Use -x to create extended resources.\n");
return NULL;
}
mHaveAppPackage = true;
p = new Package(package, 127);
} else {
p = new Package(package, mNextPackageId);
}
//printf("***
NEW PACKAGE: \"%s\" id=%d\n",
// String8(package).string(), p->getAssignedId());
mPackages.add(package, p);
mOrderedPackages.add(p);
mNextPackageId++;
}
return p;
}
在这里我们应用程序的ID赋值在第14行,最终在第20行到21行完成对新包的加入,代码相对比较简单,不再进行赘述,至此,应用程序的包ID被赋值为0x7f(127).
那么到了这里大家大概知道如何修改源码了,是不是只要把127换成一个其它数字就可以了呢,可以说确实是的。我们只需要对bundle数据结构进行扩展,将ID-127换成从bundle读入的一个变量即可。
ID显得意义重大。网上已经有很多修改package ID 的AAPT可执行文件(但是绝大部分不提供源码,觉得很神,就决定自己研究一下),通过命令行参数提供package ID赋值,现在从aapt资源打包源码流程角度,讲解该过程中何时会生成应用程序包的package ID, 然后如何进行修改。
aapt首先根据命令行参数路径,寻找到androidmanifest文件,提取出应用程序的名称,创建resourceTable.
具体调用路径main(main.cpp)-->handleCommand(command.cpp)->doPackage-->buildResources(Resource.cpp)
status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets)
{
// First, look for a
package file to parse. This is required to
// be able to generate the resource information.
sp<AaptGroup> androidManifestFile =
assets->getFiles().valueFor(String8("AndroidManifest.xml"));
if (androidManifestFile == NULL) {
fprintf(stderr, "ERROR: No AndroidManifest.xml file found.\n");
return UNKNOWN_ERROR;
}
status_t err = parsePackage(bundle, assets, androidManifestFile);
if (err != NO_ERROR) {
return err;
}
NOISY(printf("Creating resources for package %s\n",
assets->getPackage().string()));
ResourceTable table(bundle, String16(assets->getPackage()));
err = table.addIncludedResources(bundle, assets);
从第5行到第20行,我们需要关注的过程主要是读取androidManifest.xml内的应用名称(parsePackage比较麻烦,它会收集工程XML文件的元素<资源>信息,并对XML进行扁平压缩,最终写入到ResXMLTree的数据结构中),来创建一个资源表Resourcetable(资源打包最后阶段会根据该内容生成资源索引表resources.arsc),在上述代码第21行,我们能看到table.addIncludedResources(bundle, assets);该函数主要是用于添加被引用的资源包,当然一般是系统资源包android.jar.
status_t ResourceTable::addIncludedResources(Bundle* bundle, const sp<AaptAssets>& assets)
{
status_t err = assets->buildIncludedResources(bundle);
if (err != NO_ERROR) {
return err;
}
// For future reference to included
resources.
mAssets = assets;
const ResTable& incl = assets->getIncludedResources();
// Retrieve all the packages.
const size_t N = incl.getBasePackageCount();
for (size_t phase=0; phase<2; phase++) {
for (size_t i=0; i<N; i++) {
String16 name(incl.getBasePackageName(i));
uint32_t id = incl.getBasePackageId(i);
// First time through: only
add base packages (id
// is not 0); second time through
add the other
// packages.
if (phase != 0) {
if (id != 0) {
// Skip base packages -- already
one.
id = 0;
} else {
// Assign a dynamic id.
id = mNextPackageId;
}
} else if (id != 0) {
if (id == 127) {
if (mHaveAppPackage) {
fprintf(stderr, "Included resources have two application
packages!\n");
return UNKNOWN_ERROR;
}
mHaveAppPackage = true;
}
if (mNextPackageId > id) {
fprintf(stderr, "Included base package ID %d already in
use!\n", id);
return UNKNOWN_ERROR;
}
}
if (id != 0) {
NOISY(printf("Including package %s with ID=%d\n",
String8(name).string(), id));
sp<Package> p = new Package(name, id);
mPackages.add(name, p);
mOrderedPackages.add(p);
if (id >= mNextPackageId) {
mNextPackageId = id+1;
}
}
}
}
// Every resource table always has one first entry, the bag attributes.
const SourcePos unknown(String8("????"), 0);
sp<Type> attr = getType(mAssetsPackage, String16("attr"), unknown);
return NO_ERROR;
}
从上述代码14行到第55行,描述了添加引用依赖包的过程,核心在第46-48行,以Pair的格式存入依赖包(注意ID为包命名空间8位二进制,系统层为1)。
从第59行getType()开始就要进入到当前资源包ID的命名了,ResourceTable::getType()---》call
ResourceTable::getPackages()
sp<ResourceTable::Package> ResourceTable::getPackage(const String16& package)
{
sp<Package> p = mPackages.valueFor(package);
if (p == NULL) {
if (mBundle->getIsOverlayPackage()) {
p = new Package(package, 0x00);
} else if (mIsAppPackage) {
if (mHaveAppPackage) {
fprintf(stderr, "Adding multiple application package resources;
only one is allowed.\n"
"Use -x to create extended resources.\n");
return NULL;
}
mHaveAppPackage = true;
p = new Package(package, 127);
} else {
p = new Package(package, mNextPackageId);
}
//printf("***
NEW PACKAGE: \"%s\" id=%d\n",
// String8(package).string(), p->getAssignedId());
mPackages.add(package, p);
mOrderedPackages.add(p);
mNextPackageId++;
}
return p;
}
在这里我们应用程序的ID赋值在第14行,最终在第20行到21行完成对新包的加入,代码相对比较简单,不再进行赘述,至此,应用程序的包ID被赋值为0x7f(127).
那么到了这里大家大概知道如何修改源码了,是不是只要把127换成一个其它数字就可以了呢,可以说确实是的。我们只需要对bundle数据结构进行扩展,将ID-127换成从bundle读入的一个变量即可。
相关文章推荐
- 【数组】Maximum Product Subarray
- 语言文法
- 冒泡排序的推导
- 停车管理系统
- Oracle两表关联(join)更新字段值一张表到另一张表
- Oracle两表关联(join)更新字段值一张表到另一张表
- Android Animation使用
- Eclipse调试Android工具-DDMS
- Linux gprof命令
- epoll用法整理
- 春风醉人,暖意微醺
- jQuery中的事件
- SAWV Eclipse Plugin
- 原始XML资源
- 飘逸的python - __new__、__init__、__call__傻傻分不清
- 清除图片周围的空白区域
- 浅谈 举家搬迁静态文件到CDN
- GIT - 一些基本概念
- C语言 typedef的使用
- 【Java】使用Json-lib序列化关联对象的异常解决