Flutter 资源优化

483 阅读3分钟

筛选废弃资源文件

中途参与一个flutter项目,接到任务是整合项目中的资源文件,筛选出系统中未被引用到的资源文件。由于项目过大,为了减少劳动力,想到用node编写脚本,筛选文件。

考虑到部分资源文件可能已动弹参数的形式引用,所以只是单纯将文件名列出,不做删除处理。

本地配置node环境, NPM是随同NodeJS一起安装的包管理工具, 用于安装依赖。

下载安装node

nodejs.org/en/download…

终端输入 node -v 检查版本,若提示node 不存在,则需要配置全局变量。

配置node环境

  1. 打开配置文件 vi ./.bash_profile
  2. 添加一行PATH(按i进入insert才能编辑)

PATH=$PATH:/usr/local/bin/

把/usr/local/bin/换成你的node全局包路径,路径的查看方式看上面


执行searchFile.js

有node环境下 终端命令行 node searchFile.js 【filePath】【searchPath】【importCount】

filePath: 必传 匹配需要删掉的文件目录

searchPath: 必传 搜索范围

importCount: 必传 引用次数


示例:

node searchFile.js images lib 0


执行效果 👇👇👇


image.png


由于一些图片文件可能已动态字符串的形式引用(比如 'image_$index'),所以删除之前,建议搜索是否有匹配。

node脚本

// 有node环境下 终端命令行 node searchFile.js 【filePath】【searchPath】【importCount】
// node searchFile.js images lib 0
// filePath 文件所在路径; searchPath 引用文件的搜索范围路径; importCount引用次数
let [filePath, searchPath, importCount] = process.argv.splice(2)
const path = require("path");
const fs = require("fs");
filePath = path.resolve(filePath)
searchPath = path.resolve(searchPath)
console.log(`--------`);
console.log(`filePath: ${filePath}`)
console.log(`searchPath: ${searchPath}`)
console.log(`importCount: ${importCount}`)
console.log(`--------`);

const filesList = []
const filesMap = {}
const resultList = []

function readFileList(dir, list = []) {
    const files = fs.readdirSync(dir);
    files.forEach(item => {
        var fullPath = path.join(dir, item);
        const stat = fs.statSync(fullPath);
        if (stat.isDirectory()) {
            readFileList(path.join(dir, item), list);  //递归读取文件
        } else {
            const name = item.match(/(\S*)\./)[1]  // 正则取出不佳后缀的文件名
            if(!filesMap[name]) {
                filesList.push(name);
                filesMap[name] = {
                    importCount: 0,
                    fileName: name
                }
            } 
        }        
    });
    return list;
}

function readSearchFile(dir) {
    const files = fs.readdirSync(dir);
    files.forEach(item => {
        var fullPath = path.join(dir, item);
        const stat = fs.statSync(fullPath);
        if (stat.isDirectory()) {      
            readSearchFile(path.join(dir, item))  //递归读取文件
        } else {
            const buffer= fs.readFileSync(fullPath)
            const bufferStr = String(buffer)
            filesList.forEach(i => {
                if(bufferStr.includes(i)) {
                    filesMap[i].importCount ++
                }
            })
        }        
    });
}

readFileList(filePath, filesList)
readSearchFile(searchPath)

filesList.forEach(i => {
    if(filesMap[i].importCount == importCount) {
        resultList.push(filesMap[i])
    }
})

console.log(resultList)

效果展示

image.png

Flutter产物大小分析

参考文章

blog.csdn.net/u010479969/…

www.jb51.cc/flutter/454…


克隆代码工具sdk-master

github.com/dart-lang/s…


安装依赖

打开克隆的项目,在目录/sdk-master/pkg/vm 中执行命令 pub get


执行指令生成html

  1. 执行如下命令编译出一个arm64架构的App.framework,并将它的包组成结构放到指定目录build/aot.json文件中

flutter --suppress-analytics build aot --output-dir=build/aot --target-platform=android-arm --target=lib/main.dart --release --ios-arch=arm64 --extra-gen-snapshot-options="--dwarf_stack_traces,--print-snapshot-sizes,--print_instructions_sizes_to=build/aot.json"


image.png


image.png

Instructions
:代表AOT编译后生成的二进制代码大小

ReadOnlyData
:代表生成二进制代码的元数据(例如PcDescriptor, StackMap,CodeSourceMap等)和字符串大小

VMIsolate/Isolate
:代表剩下的对象的大小总和(例如代码中定义的常量和虚拟机特定元数据)



  1. 利用sdk-master 工具中的run_binary_size_analysis.dart,生成的aot.json文件转化成结构可视化的网页

注意将/Users/huya/study/、/Users/huya/work/相应项目在本地中存放地址


dart /Users/huya/study/sdk-master/pkg/vm/bin/run_binary_size_analysis.dart /Users/huya/work/flt_hgfm/build/aot.json path_to_webpage_dir


建议在.gitignore中增加 /path_to_webpage_dir/ 避免将生成产物上传git


image.png


浏览器直接打开index.html


image.png


右上角分别有Largest Symbols,与Largest Files,

Largest Symbols: 前100个打包生成的最大的方法。

Largest Files: 前100个打包生成最大的文件路径

image.png


双击任意红框,打开改文件具体方法。


左上角按钮是对展示文件的一些筛选条件

image.png