您的位置:首页 > 其它

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读入的一个变量即可。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: