性能优化-apk瘦身

目录

 安卓中的R文件

AndResGuard缩小包体积

Matrix-ApkChecker分析Apk包

动态加载的两种方案


matrix做

arm能兼容v7,v8但是不能兼容

so库的崩溃是因为指令集不同,

splits {
    abi {
        enable true
        reset()
        include 'arm64-v8a','armeabi-v7a'
    exclude 'armeabi'
        universalApk true  //是否打包一个包含所有so的apk
    }
}

按照上图配置,会打3个包,分笔试v8a,v7a,以及包含全部so库的名叫universalApk的一个apk。

linker框架 + soloader做远端so的自动化的下载,用来兼容低版本的手机 

so库的兼容性问题,不能向下兼容。

(1)只适配 armeabi APP 可以跑在 armeabi,armeabi-v7a,arm64-v8 上;
(2)只适配 armeabi-v7a 可以运行在 armeabi-v7a arm64-v8a;
(3)只适配 arm64-v8a 可以运行在 arm64-v8a 上。

 安卓中的R文件

 

红框表示资源ID(Identitify document),蓝框表示资源的值;绿框便是资源的类型。

public final class R { ...
    public static final class string { ...
        /**
         * Description of the choose target button in a ShareActionProvider (share UI). [CHAR LIMIT=NONE]
         */
        public static final int abc_shareactionprovider_share_with = 0x7f0a000c;
        /**
         * Description of a share target (both in the list of such or the default share button) in a ShareActionProvider (share UI). [CHAR LIMIT=NONE]
         */
        public static final int abc_shareactionprovider_share_with_application = 0x7f0a000b;
        public static final int action_settings = 0x7f0a000f;
        public static final int app_name = 0x7f0a000d;
        public static final int menu_home = 0x7f0a000e;
    } ...
}
可以看到每个资源文件在 R 中都是一个 class ,每个资源项名称都分配了一个 id id 值是一个四字节无符号 整数,格式是这样的:0xpptteeee ,(p代表的是 package t 代表的是 type e 代表的是 entry ),最高 字节代表Package ID ,次高字节代表 Type ID ,后面两个字节代表 Entry ID,用来区分具体的信息

(1)Package ID 相当于是一个命名空间,限定资源的来源。 Android 系统当前定义了两个资源命令空 间,其中一个系统资源命令空间,它的Package ID 等于 0x01 ,另外一个是应用程序资源命令空 间,它的Package ID 等于 0x7f 。所有位于 [0x01, 0x7f] 之间的 Package ID 都是合法的,而在这个范 围之外的都是非法的Package ID 。前面提到的系统资源包 package-export.apk Package ID 就等 于0x01 ,而我们在应用程序中定义的资源的 Package ID 的值都等于 0x7f ,这一点可以通过生成的 R.java文件来验证。
(2)Type ID 是指资源的类型 ID 。资源的类型有 animator anim color drawable layout
menu raw string xml 等等若干种,每一种都会被赋予一个 ID
(3)Entry ID 是指每一个资源在其所属的资源类型中所出现的次序。注意,不同类型的资源的 Entry ID 有可能是相同的,但是由于它们的类型不同,我们仍然可以通过其资源ID 来区别开来。

 混淆的核心:

 就是将Name压缩,将路径压缩。

 比如上图中混淆之后就变成了

这个修改的原理就是,读取每一个字节,改成abcd之类的就行了。混淆的信息,将映射的名字简化了。

AndResGuard缩小包体积

AndResGuard的配置,对于apk体积帮助不大, 面试可以说一说这种方式。

andResGuard {
    // 压缩文件
    // mappingFile = file("./resource_mapping.txt")
    mappingFile = null
    // 手否签名。
    use7zip = true
    useSign = true
    // 打开这个开关,会keep住所有资源的原始路径,只混淆资源的名字
    keepRoot = false
    // 设置这个值,会把arsc name列混淆成相同的名字,减少string常量池的大小
//    fixedResName = "arg"
    // 打开这个开关会合并所有哈希值相同的资源,但请不要过度依赖这个功能去除去冗余资源
    mergeDuplicatedRes = true
    // 白名单的资源都不能混淆。如果有反射调用的地方,需要进行添加到这里边。
    whiteList = [
            // for your icon
            "R.drawable.ic_launcher",
            "R.drawable.ic_launcher_round",
            // for fabric
            "R.string.com.crashlytics.*",
            // for google-services
            "R.string.google_app_id",
            "R.string.gcm_defaultSenderId",
            "R.string.default_web_client_id",
            "R.string.ga_trackingId",
            "R.string.firebase_database_url",
            "R.string.google_api_key",
            "R.string.google_crash_reporting_api_key"
    ]
    // 压缩什么文件
    compressFilePattern = [
            "*.png",
            "*.jpg",
            "*.jpeg",
            "*.gif",
    ]
    // 压缩使用的工具。
    sevenzip {
        artifact = 'com.tencent.mm:SevenZip:1.2.19'
        //path = "/usr/local/bin/7za"
    }

    /**
     * 可选: 如果不设置则会默认覆盖assemble输出的apk
     **/
    // finalApkBackupPath = "${project.rootDir}/final.apk"

    /**
     * 可选: 指定v1签名时生成jar文件的摘要算法
     * 默认值为“SHA-1”
     **/
    // digestalg = "SHA-256"
}

Android studio自带的Unused resource使用时需要小心,因为会移出反射调用的资源。

Matrix-ApkChecker分析Apk包

使用方式

调研-》看别人的代码-》优化-》自己输出。

matrix

动态加载的两种方案

(1)Linker + soloader(FB)

(2)Tinker,重要的一个类,TinkerLoaderLibrary#installNativeLibrary()//实现so动态加载,不用Tinker也能用。

下边是Tinker实现动态下载的简易结构图: 

图讲解:将一个文件下载到sdcard,然后拷贝到应用内部的一个目录,之后调用Tinker的loaderLibrary实现so的加载。

系统加载so的路程:

(1)PMS把对应的so 拷贝到data/data/包名/lib

(2)app启动,so文件的路径会传递到BaseDexClassLoader,这个类里边有一个变量叫做DexpathList,里边有可以加载so库的方法;

(3)之后调用System.loadLibrary就可以了。

热修复一定要注意这个构造方法:

dalvik.system.DexPathList#DexPathList(ClassLoader, String)

/**
 * Construct an instance.
 *
 * @param definingContext the context in which any as-yet unresolved
 * classes should be defined
 *
 * @param dexFiles the bytebuffers containing the dex files that we should load classes from.
 */
public DexPathList(ClassLoader definingContext, String librarySearchPath) {
    if (definingContext == null) {
        throw new NullPointerException("definingContext == null");
    }
    this.definingContext = definingContext;
    this.nativeLibraryDirectories = splitPaths(librarySearchPath, false);
    this.systemNativeLibraryDirectories =
            splitPaths(System.getProperty("java.library.path"), true);
    this.nativeLibraryPathElements = makePathElements(getAllNativeLibraryDirectories());
}

Tinker的加载流程:

将我们自定义的so文件加载到 dalvik.system.DexPathList#nativeLibraryDirectories这个List集合中,这样子应用启动后就能够加载这些so文件了。

Tinker的核心代码:

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值