首页 > 其他分享 >在APK打包过程中,Assets资源漏编译漏打包的本质

在APK打包过程中,Assets资源漏编译漏打包的本质

时间:2023-06-19 11:36:09浏览次数:38  
标签:文件 Assets char APK token path 目录 打包


背景

作为 Androider,我们平时在 Assets 资源目录下都放点啥呢,字体、预置数据、图片、配置文件…等等,那大家有没有想过,万一哪天我在 Assets 目录下新增了一个子目录放了点自己的资源文件,打包之后再解包发现 Apk 包里没有找到这部分文件,怎么办呢?

原理分析

我们都知道典型的 Android 应用构建流程第一步就是 Android 编译器将应用的源代码转换成 DEX 文件(即 Dalvik 可执行文件),并且把其他所有内容转换成为编译后的资源,然后打包器将 DEX 文件和编译后的资源文件组合成 APK。

这里的资源文件就包括 Assets 目录下的文件在内,还有 res 目录下的所有文件和 AndroidManifest.xml 文件,我们刚刚提到 APK 的资源编译是编译过程中的一项主要工作,AGP3.0.0 之后默认通过 AAPT2 来编译资源。

受到 Android 系统 AAPT 配置的影响,如果走系统默认配置打包,我们的 Assets 目录合并过程中会走一些判断逻辑,如果根据系统规则判定该文件夹是需要被忽略的,那么也就意味着打不进 Apk 里了。

规则是这样的:

# Assets 目录合并忽略模式
!.svn:!.git:!.ds_store:!*.scc:.*:<dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~

规则判断的源码是这样的:

// 忽略模式核心源码
static bool isHidden(const char *root, const char *path)
{
    if (strcmp(path, ".") == 0 || strcmp(path, "..") == 0) {
        return true;
    }

    const char *delim = ":";
    const char *p = gUserIgnoreAssets;
    if (!p || !p[0]) {
        p = getenv("ANDROID_AAPT_IGNORE");
    }
    if (!p || !p[0]) {
        p = gDefaultIgnoreAssets;
    }
    char *patterns = strdup(p);

    bool ignore = false;
    bool chatty = true;
    char *matchedPattern = NULL;

    String8 fullPath(root);
    fullPath.appendPath(path);
    FileType type = getFileType(fullPath);

    int plen = strlen(path);

    // Note: we don't have strtok_r under mingw.
    for(char *token = strtok(patterns, delim);
        !ignore && token != NULL;
        token = strtok(NULL, delim)) {
            chatty = token[0] != '!';
            if (!chatty) token++; // skip !
            if (strncasecmp(token, "<dir>" , 5) == 0) {
                if (type != kFileTypeDirectory) continue;
                token += 5;
            }
            if (strncasecmp(token, "<file>", 6) == 0) {
                if (type != kFileTypeRegular) continue;
                token += 6;
            }

            matchedPattern = token;
            int n = strlen(token);

            if (token[0] == '*') {
                // Match *suffix
                token++;
                n--;
                if (n <= plen) {
                    ignore = strncasecmp(token, path + plen - n, n) == 0;
                }
            } else if (n > 1 && token[n - 1] == '*') {
                // Match prefix*
                ignore = strncasecmp(token, path, n - 1) == 0;
            } else {
                ignore = strcasecmp(token, path) == 0;
            }
        }

    if (ignore && chatty) {
        fprintf(stderr, "    (skipping %s '%s' due to ANDROID_AAPT_IGNORE pattern '%s')\n",
            type == kFileTypeDirectory ? "dir" : "file",
            path,
            matchedPattern ? matchedPattern : "");
    }

    free(patterns);
    return ignore;
}

源码挺长,我们直接看忽略模式解读图:

在APK打包过程中,Assets资源漏编译漏打包的本质_Android

举个例子

原理分析比较长,我们看一个详细的例子,更好地理解这个判断规则

随便找一个子 Module,在对应 Assets 目录下增加一个新的子目录,命名为 “__testxxx”,在这个目录下随便放一个测试文件,“test.txt”。

我们尝试打 SNAPSHOP 包然后更新依赖并且打 APK 包,解包以后好像并没有找到这个目录,更没有这个测试文件。

为什么呢?

我们回过头看下规则,其中 “:” 是分隔符,


* 就是今天的重点了,啥意思呢,当判断到 “__testxxx” 是一个目录时,按照规则会接着判断后一位,恰好后一位是 "" 下划线,和我们的文件夹名称开头一致,也就被认为需要被忽略合并。


简单来说,就是下划线开头的文件夹目录在打包时将会被认做需要忽略合并的文件夹,不予合并。

解决方案

两种方式,第一种很简单,就是换名字,换个和规则不匹配的名称即可

当然,有些情形下是没办法换组件名字的,不急,还有第二种方案,自定义 AAPT 配置,像这样:

android {
    aaptOptions {
        noCompress ' test1', 'test2'
        ignoreAssetsPattern "!.svn:!.git:!.ds_store:!*.scc:.*:!CVS:!thumbs.db:!picasa.ini:!*~"
    }
}

接下来,就看你自己的诉求了,如果是需要打到子 Module 的 SNAPSHOP 中,就把 ignoreAssetsPattern 加到对应 Module 的 android 配置中,如果是需要打到安装包 APK 中,就需要到壳工程的 build.gradle 中去同步一份配置了。

影响面评估

这份配置修改的是打包过程中 Assets 资源合并的规则,那么相对地,就会有一些绕开默认规则且符合自定义规则的资源被合并进 APK 包中了。简单地说:

  • 对于加了配置的 Module,会有一些 _* 规则以外的文件会被合并进去
  • 对于没有加配置的 Module,也就没有影响

大家可以针对 app/build/intermediates/incremental/mergeDebugAssets/merger.xml XML 文件做加配置前后的 DIFF 对比,在合并之前检查是否有不该合并的文件被合并进去。

影响完全可控,并且也达到了我们的初心,让合理资源被正常打包,不合理的资源被忽略,彻底解决漏编译漏打。

作者:闫宇威


标签:文件,Assets,char,APK,token,path,目录,打包
From: https://blog.51cto.com/u_16163480/6512007

相关文章

  • 2023-06-19 uniapp云打包报错:app-plus.distribute.icons.android.hdpi 文件不存在
    详细报错:[HBuilder]11:02:51.408Manifest.json文件以下节点配置错误,请检查修复[HBuilder]11:02:51.408app-plus.distribute.icons.android.hdpi 文件不存在[HBuilder]11:02:51.408app-plus.distribute.icons.android.xxhdpi 文件不存在[HBuilder]11:02:51.408ap......
  • 使用nwjs打包VUE生成桌面应用
    摘抄自:https://blog.csdn.net/weixin_40521770/article/details/126907614目前已知把Vue项目打包成桌面应用有两种方式:(1)使用nwjs生成桌面应用;(2)使用Electron生成桌面应用。本文采用的是nwjs生成桌面应用,也是我认为最简单、最快捷的一种。一、打包Vue应用程序npmrunbuild二、添......
  • std::thread 五:打包任务(packaged_task)
     #include<iostream>#include<thread>#include<mutex>#include<list>#include<future>usingnamespacestd;intmyThread(intnum){cout<<"myThread()startthreadid="<<this_thread::get_i......
  • unity将安卓streamingAssetsPath文件复制到persistentDataPath
    privatevoidTestCopy(){stringfrom=Application.streamingAssetsPath+"/Test/test.txt";stringto=Application.persistentDataPath+"/Test/";CopyFile(from,to);}publicstaticvoidCopyFile(stringsourcePath,stringdesti......
  • xcode打包APP或真机调试 无法签名的问题(初学者问题)
    一般真机调试的准备工作:在项目的Signing&Capabilities属性设置中,profile首先要导入(从开发者中心下载的.mobileprovision文件,原先就已存在的,一般这一步就已经有坑了),证书从苹果开发者中心下载并安装(原先在开发者中心就已存在的,这里又是一个坑)。但证书状态那里一直显示:Nosigning......
  • Unity 编辑器直接运行正常,打包后的程序运行异常问题
     打包后的程序运行报错:base="System.MissingMethodException:Defaultconstructornotfoundfortypelog4net.Repository.Hierarchy.Hierarchy\r\natSystem.RuntimeType.CreateInstanceMono(System.BooleannonPublic,System.BooleanwrapExceptions)[0x00076]in&l......
  • 如何降低Vue.js项目中Webpack打包文件的大小?
    结论结论:vue中,直接引用文件,可以让打包文件最小。试验记录下面测试项目中引入一个Button组件的代价。基准工程大小:[raywill:shop]npmrunbuild>shop@build/Users/raywill/code/vue/shop>cross-envNODE_ENV=productionwebpack--progress--hide-modulesHash:d902d9dc5e......
  • @MapKey is required
    @MapKeyisrequired 这就是mybatis的annotation的一个提醒,可以直接忽略,不影响代码编译;为啥出现这种情况,因为我们很烂,sql中返回的对象不愿意定义一个 resultMap,select默认就是返回list,不指定resultMap或者resultType,默认就是组装为map对象返回;注意:一定要指定 resultType="......
  • Vue项目打包部署上线时devServer.proxy代理失效如何解决?使用nginx的proxy_pass 代理跨
    Vue项目打包部署上线时devServer.proxy代理失效如何解决?使用proxy_pass代理跨域转发前言本篇文章用于记录项目前端部署上线遇到的问题,包含对问题的思考、解决思路,以及从中获得的收获。正确的部署流程我也写了一篇文章,供大家参考使用宝塔将Vue2+Nodejs全栈项目打包部署到腾讯云服......
  • Unity 打包程序调试
          ......