大致内容看这篇文章Android中如何修改编译的资源ID值(默认值是0x7F…可以随意改成0x02~0x7E),但是该文章中修改并不完全,是有问题的,见后文细说。该文章也参考了携程的aapt源码。

从该文章中看到修改的地方主要有这么几个地方。

  • 加入- -apk-module 参数读取外部packageId值。
  • 根据Bundle把packageId传入,并进行传递。
  • 设置packageId的时候判断Bundle中是否有packageId,有的话覆盖packageId。

下面的代码基于Android源码主分支,应该是6.0的源码。

第一点修改的地方就在Main.cpp中。增加参数,具体位置自己找。

else if(strcmp(cp, "-apk-module") == 0){    argc--;    argv++;    if (!argc) {        fprintf(stderr, "ERROR: No argument supplied for '--apk-module' option\n");        wantUsage = true;        goto bail;    }    bundle.setApkModule(argv[0]);}

其次要在Bundle.h中增加setApkModule和getApkModule方法,当然还有一个成员变量,加在什么位置自行找。

android::String8 mApkModule;const android::String8& getApkModule() const {return mApkModule;}void setApkModule(const char* str) { mApkModule=str;}

在ResourceTable.cpp中读取bundle中的mApkModule,如果不为空则覆盖packageId。

//read the apk moduleif(!bundle->getApkModule().isEmpty()){  android::String8 apkmoduleVal=bundle->getApkModule();  packageId=apkStringToInt(apkmoduleVal);}   

涉及到两个转换方法,其实现为。

ssize_t ResourceTable::apkStringToInt(const String8& s){    size_t i = 0;    ssize_t val = 0;    size_t len=s.length();    if (s[i] < '0' || s[i] > '9') {        return -1;    }    // Decimal or hex?    if (s[i] == '0' && s[i+1] == 'x') {        i += 2;        bool error = false;        while (i < len && !error) {            val = (val*16) + apkgetHex(s[i], &error);            i++;        }        if (error) {            return -1;        }    } else {        while (i < len) {            if (s[i] < '0' || s[i] > '9') {                return false;            }            val = (val*10) + s[i]-'0';            i++;        }    }    if (i == len) {        return val;    }    return -1;}uint32_t ResourceTable::apkgetHex(char c, bool* outError){    if (c >= '0' && c <= '9') {        return c - '0';    } else if (c >= 'a' && c <= 'f') {        return c - 'a' + 0xa;    } else if (c >= 'A' && c <= 'F') {        return c - 'A' + 0xa;    }    *outError = true;    return 0;}

此外还要在ResourceTable.h中声明这两个方法。

private:    ssize_t apkStringToInt(const String8& s);    uint32_t apkgetHex(char c, bool* outError);

执行编译,进入到android源码根目录。

make aapt

没有发生错误,则产生了aapt文件,文件在/out/host/linux-x86/bin。对应的windows版为/out/host/windows-x86/bin。mac版没有配置,所以不会产生,最好在mac上编译,以此类推,对应的文件应该在/out/host/darwin-x86/bin下。

这时候你使用aapt指定apk-module参数,肯定会报错。错误为。

error: Error: No resource found that matches the given name

所以最终的结论是携程开源的aapt源码并不完整。该错误在哪里报的呢。源码路径在/frameworks/base/libs/androidfw/ResourceTypes.cpp。该文件中有一个函数。

bool ResTable::stringToValue(Res_value* outValue, String16* outString,                             const char16_t* s, size_t len,                             bool preserveSpaces, bool coerceType,                             uint32_t attrID,                             const String16* defType,                             const String16* defPackage,                             Accessor* accessor,                             void* accessorCookie,                             uint32_t attrType,                             bool enforcePrivate) const{            //剩余代码            if (accessor) {                uint32_t rid = accessor->getCustomResourceWithCreation(package, type, name,                                                                       createIfNotFound);                if (rid != 0) {                    if (kDebugTableNoisy) {                        ALOGI("Pckg %s:%s/%s: 0x%08x\n",                                String8(package).string(), String8(type).string(),                                String8(name).string(), rid);                    }                    uint32_t packageId = Res_GETPACKAGE(rid) + 1;                    if (packageId == 0x00) {                        outValue->data = rid;                        outValue->dataType = Res_value::TYPE_DYNAMIC_REFERENCE;                        return true;                    } else if (packageId == APP_PACKAGE_ID || packageId == SYS_PACKAGE_ID) {                        // We accept packageId's generated as 0x01 in order to support                        // building the android system resources                        outValue->data = rid;                        return true;                    }                }            }        }        if (accessor != NULL) {            accessor->reportError(accessorCookie, "No resource found that matches the given name");        }        return false;        //剩余代码}

可以看到

if (accessor != NULL) {            accessor->reportError(accessorCookie, "No resource found that matches the given name");        }

那么这个什么时候回执行到呢。就是当上面没有返回的情况下,前面返回的情况是当package为0x00,0x01,0x7f中的其中一个就会返回true,我们需要在else if分支加上我们的packageId的判断,让他返回true,但是这里没有Bundle,没办法传递packageId,因此我们需要一个辅助类Helper。

在/frameworks/base/include/androidfw/下新建Helper.h。这是一个单例。

#ifndef __Helper_h#define __Helper_h#include #include #include #include #include #include #include using namespace std;class Helper{        size_t packageId;public:        static Helper* getInstance()        {                static Helper instance;                return &instance;        }        size_t getPackageId();        void setPackageId(size_t _packageId);protected:        struct Object_Creator        {                Object_Creator()                {                        Helper::getInstance();                }        };        static Object_Creator _object_creator;        Helper() {                packageId=0x7f;        }        ~Helper() {        }};#endif

在/frameworks/base/libs/androidfw/下新建Helper.cpp。对方法进行实现。

#include #include #include using namespace std;Helper::Object_Creator Helper::_object_creator;size_t Helper::getPackageId(){        return packageId;}void Helper::setPackageId(size_t  _packageId){        packageId=_packageId;}

同时修改该目录中的Android.mk文件。加入该cpp。

commonSources := \    原来的内容  \    Helper.cpp

回到ResourceTable.cpp中,在获取packageId后,将值传入到Helper单例中去。

//引入头文件。#include <androidfw/Helper.h> //read the apk moduleif(!bundle->getApkModule().isEmpty()){          android::String8 apkmoduleVal=bundle->getApkModule();          packageId=apkStringToInt(apkmoduleVal); } //set package idHelper::getInstance()->setPackageId(packageId);

再回到刚才扔出异常的那个地方,在else if中加入packageId的判断。

//引入头文件。#include <androidfw/Helper.h>else if (packageId== Helper::getInstance()->getPackageId() ||packageId == APP_PACKAGE_ID || packageId == SYS_PACKAGE_ID) {    // We accept packageId's generated as 0x01 in order to support    // building the android system resources    outValue->data = rid;    return true;}

只是加了一个条件

packageId== Helper::getInstance()->getPackageId()

再执行编译

make aapt

这时候就能随意指定packageId了,范围在0x00~0x7f之间,其中0x00、0x01、0x7f已经被使用。

之前报错的原因也有可能6.0的源码发生了变化,也有可能携程开源的代码不全。这个结论也不好下。当然我也不敢保证我这么修改后一定没有问题。

更多相关文章

  1. 基于MAC Android 8.1源码下载编译阅读
  2. android 调用系统文件管理器
  3. Android运行时权限,6.0—9.0多版本,多终端(手机,TV盒子)130行代码一劳
  4. Android屏幕锁定实例源码详解教程一
  5. 从零开始--系统深入学习android(实践-让我们开始写代码-Android框
  6. android 使用handler更新ui,使用与原理分析详解(附上代码以及截图)
  7. 如何编译Android内核源码
  8. Android 为【apk】文件签名,增加修改系统时间等权限

随机推荐

  1. Android学习08-----Android中的基本控件(
  2. 记录博客“参考网站”专栏源码
  3. Android(安卓)装载器---启动装载器
  4. Android(安卓)sendevent/getevent 用法
  5. Android(安卓)ART 的初始化和启动
  6. IDS打包系统包修改
  7. Android的配置
  8. android animation中interpolator参数详
  9. AndroidX设计架构MVVM之DataBinding+View
  10. JSONObject与JSONArray的使用 jsonobject