android 资源如何查找(AaptAssets)分析

AaptAsset.cpp 位于 src/frameworks/base/tools/aapt目录xiam

主要入手是从 函数 ssize_t AaptAssets::slurpFromArgs(Bundle* bundle)开始

首先先判断 是否存在 AndroidManifest.xml 这个文件,然后加入,

在加入文件的时候,使用到  status_t AaptGroup::addFile(const sp<AaptFile>& file) 此函数

status_t AaptGroup::addFile(const sp<AaptFile>& file)
{
    if (mFiles.indexOfKey(file->getGroupEntry()) < 0) {
        file->mPath = mPath;
        mFiles.add(file->getGroupEntry(), file);
        return NO_ERROR;
    }

    SourcePos(file->getSourceFile(), -1).error("Duplicate file.\n%s: Original is here.",
                                               getPrintableSource().string());
    return UNKNOWN_ERROR;
}

变量mFiles是存放文件用的,

然后是遍历 assets文件夹,用到函数

ssize_t AaptDir::slurpFullTree(Bundle* bundle, const String8& srcDir,
                            const AaptGroupEntry& kind, const String8& resType)
{
    Vector<String8> fileNames;

    {
        DIR* dir = NULL;

        dir = opendir(srcDir.string());
        if (dir == NULL) {
            fprintf(stderr, "ERROR: opendir(%s): %s\n", srcDir.string(), strerror(errno));
            return UNKNOWN_ERROR;
        }

        /*
         * Slurp the filenames out of the directory.
         */

   / /dirent含有指针,所以这while 相当于找到当前文件夹下面的第一级的 文件夹
        while (1) {
            struct dirent* entry;

            entry = readdir(dir);
            if (entry == NULL)
                break;

            if (isHidden(srcDir.string(), entry->d_name))
                continue;

            fileNames.add(String8(entry->d_name));
        }

        closedir(dir);
    }

    ssize_t count = 0;

    /*
     * Stash away the files and recursively descend into subdirectories.
     */

//通过找到的文件夹,然后调用  slurpFullTree 继续遍历
    const size_t N = fileNames.size();
    size_t i;
    for (i = 0; i < N; i++) {
        String8 pathName(srcDir);
        FileType type;

        pathName.appendPath(fileNames[i].string());
        type = getFileType(pathName.string());
        if (type == kFileTypeDirectory) {
            sp<AaptDir> subdir;
            bool notAdded = false;

//在保存文件夹的变量 mDirs里面判断是否已经存在这个文件夹


            if (mDirs.indexOfKey(fileNames[i]) >= 0) {
                subdir = mDirs.valueFor(fileNames[i]);
            } else {
                subdir = new AaptDir(fileNames[i], mPath.appendPathCopy(fileNames[i]));
                notAdded = true;
            }
            ssize_t res = subdir->slurpFullTree(bundle, pathName, kind,
                                                resType);
            if (res < NO_ERROR) {
                return res;
            }
            if (res > 0 && notAdded) {
                mDirs.add(fileNames[i], subdir);
            }
            count += res;
        }

//如果不是文件夹,那就按文件存储

else if (type == kFileTypeRegular) {
            sp<AaptFile> file = new AaptFile(pathName, kind, resType);
            status_t err = addLeafFile(fileNames[i], file);
            if (err != NO_ERROR) {
                return err;
            }

            count++;

        } else {
            if (bundle->getVerbose())
                printf("   (ignoring non-file/dir '%s')\n", pathName.string());
        }
    }

    return count;
}

然后是查找遍历res文件夹

    /*
     * If a directory of resource-specific assets was supplied, slurp 'em up.
     */
    for (size_t i=0; i<dirCount; i++) {

..

..

..

用到了  slurpResourceTree 这个函数

在 slurpResourceTree里面用到了

AaptGroupEntry::initFromDirName(const char* dir, String8* resType)这个函数

initFromDirName函数里面判断文件夹是否合法啊之类的 ,当然如果合法的话进行赋值之类的。

从这个函数里面调用的子函数里面可以看到,例如 因为分辨率或者屏幕是否touch、是否land等文件夹的命名规则

写这个笔记主要是因为在做系统的时候,考虑到不同客户需要使用到不同的参数

所以可以使用不同的文件夹

比如客户abc,那我们可以使用一个名字为  value-abc的文件

然后如果这个文件夹里面存在文件,比如 string.xml,那可以value-abc里面的string.xml去替换原来的value里面的string.xml,

    if(file->getGroupEntry().overlay){
//        printf("--fail-%s",file->getPrintableSource().string());
//        printf("  %s\n", getPath().string());
        String8 fileName = file->getSourceFile().getPathLeaf();
        String8 pathName = file->getSourceFile().getPathDir();

  
        const size_t N=mFiles.size();
        size_t i;
        for (i=0; i<N; i++) {
            sp<AaptFile> file0 = mFiles.valueAt(i);
            String8 name =file0->getSourceFile().getPathLeaf();
            String8 path =file0->getSourceFile().getPathDir();
            path.append("-");
            path.append(kCustomer);
            if( name == fileName && path == pathName ){
//                printf("---john-- \n replace  %s: %s  \n",
//                file0->getSourceFile().string(), file->getSourceFile().string());
//              mFiles.replaceValueAt(i,new AaptFile());
                sp<AaptFile>& aptFile= mFiles.editValueAt(i);
                aptFile->mSourceFile = file->getSourceFile();
            }
        }
      return NO_ERROR;
    }else{
            String8 name =file->getSourceFile().getPathLeaf();
            String8 path =file->getSourceFile().getPathDir();
            path.append("-");
            path.append(kCustomer);
            String8 cur_path = getPrintableSource();
            if(path == cur_path.getPathDir() &&  name == cur_path.getPathLeaf()){
                return   NO_ERROR;
            }
    }

其中   overlay是自己添加的一个变量,在initFromDirName 里面,添加了自己的代码,判断所谓的 value-abc是否存在,如果存在  overlay置为true

其实apk文件存放资源的路径、结构跟pc上的类似 可以通过解压apk包查看

原文地址:https://www.cnblogs.com/rollrock/p/2107703.html