1. Android APP统一存储数据规范
基于Android系统对存储卡访问的各种特性,在充分保证基线的产品交互体验前提下,定义Android APP各业务开发中的可选存储路径,对应存储特性,各自适合存储文件范围和存储路径格式规范。
存储类型 | 根路径 | 特性 | 存储文件范围 | 业务路径格式 |
内置数据分区 | /data/../<packagename>/files/ (对应:Context.getFilesDir()) | 1.APP被安装时系统分配在data分区上的存储路径; 2.APP访问不需要申请权限;APP私有,安全性最高; 3.(非root或非共享UID)其它APP无权访问 4.files和cache的区别:cache存储偏临时性的文件,在系统存储空间紧张时会被系统auto clean,应用设置中“清理缓存”会清理掉cache内文件; 5.APP卸载时或“清理数据”时,此2种路径下的所有文件都会被系统自动清理; | 1.数据文件体积小(KB级别); 2.运行时只能在data区加载的文件(如:动态下载的so库,插件apk或hotfix Dex文件等) 3.安全性要求高的私密性文件; 4.记录方便用户继续使用的历史行为数据,不希望被频繁重置到默认值的数据文件; | 各存储类型根路径下各业务相对路径格式: ./<一级业务>/<子业务>/<子路径>/, 1.APP内各业务统一路径标准后,为了避免业务间冲突,请各业务找基线APP申请和注册<一级业务>,插件的还涉及<子业务>的注册,<子路径>由各业务内部自行分配;但要严格根据存储特性和适合的文件范围选择存储路径;<子业务>和<子路径>是可选的; 2.各一级业务存储路径层级尽量不要超过3级,层次越深,遍历计算各级文件大小和删除时效率越低; 3.示例: <一级业务> 基线:./app <子业务>: 下载:./app/download/ 播放器:./app/player/ 泡泡:./paopao 插件: ./plugins <子业务> ./plugins/<插件包名>/ ... |
/data/../<packagename>/cache/ (对应:Context.getCacheDir()) | 1.文件体积小(KB级别); 2.被频繁删除或重置后不影响用户历史状态功能的文件; 3.存储数据安全性相对较高,不希望被第三方获取到的临时文件 | |||
内置存储卡(或分区)(APP私有存储路径) | <内存储卡根路径>/ Android/data/<packagename>/files/ | 1.系统为每个APP分配的基于不可插拔内置存储卡(或分区)的路径; 2.APP私有的在存储卡上的空间,读写不需要特殊权限; 3. 三方应用在获取到存储卡动态权限后可以读写该目录下文件,在存储安全性相比data区要低; 4.files和cache的区别:cache存储偏临时性的文件,在系统存储空间紧张时会被系统auto clean,应用设置中“清理缓存”会清理掉cache内文件; 5.APP卸载时或“清理数据”时,此2种路径下的所有文件都会被系统自动清理; | 1.存储体积较大的文件(例如:分发或自动更新的APK,下载的视频类文件,图片,ZIP压缩包等体积较大的文件); 3.没有单独的编辑删除入口,频繁删除或重置后不影响用户历史状态功能的文件放在cache目录中; | |
<内存储卡根路径> / Android/data/<packagename>/cache/ | ||||
存储卡非APP私有存储路径 | 存储卡上非APP私有存储的其它路径(包括内置或可插拔的外置存储卡的非APP私有存储路径) | 1.Android 6.0+和部分OEM定制6.0-系统要动态申请存储卡读写权限,用户授权后才能读写; 3.非系统指定的APP私有路径,卸载APP或清除数据时,对应的数据不会被清除,持久性强; 4.放置到公共存储卡上,其实更容易被工具类APP清理缓存时引导用户做清理, | 因涉及用户动态权限,卸载APP后无法自动清理干净,一般不建议在此类路径下存储文件,有特殊需求的需要提出来Review审核 | 不建议使用的存储路径,暂时不做规范 |
SharedPreferences | /data/../<packagename>/shared_prefs/ | 存储SharedPreferences文件 | 存储全局性的开关,基类型的键值对数据 | 涉及历史数据兼容性,此类数据存储体积上相对较小,暂时不做清理和统一要求;但需要业务内定期静态清理废弃的字段或表;单个表添加的数据项得设置上限值(一般1000条以内),做LRU替换 |
Databse | /data/../<packagename>/databases/ | 存储APP内基于系统Sqlite数据库存储的 | 存储按数据库表格式访问的数据 |
2. Android APP统一访问存储卡路径的API
根据第1节的介绍,基线APP内各业务一般只需要在内置数据区和存储卡APP私有路径上存取文件或数据,按基线APP中运行的业务特性提供不同的根路径获取API
1>基线维护的所有业务,或以aar,jar等依赖基线基础库接入基线的业务,使用基线基础库提供的适配层API(便于在Android新系统或定制机型上存储特性变更时,由基线APP基础库修改API内部逻辑做兼容)
内置数据区files根路径: File getInternalDataFilesDir(Context mContext, String subFolder);
内置数据区cache根路径:File getInternalDataCacheDir(Context mContext, String subFolder);
内置存储卡APP私有存储files根路径:File getInternalStorageFilesDir(Context mContext, String subFolder)
内置存储卡APP私有存储cache根路径:File getInternalStorageCacheDir(Context mContext, String subFolder)
注:以上API细节定义和说明参考wiki:Android存储介绍及API定义
2>基线对接的native库,由native提供API和接收路径参数,按照第1节中描述的存储特性,由基线APP层传递相应的根路径给native业务;
3>独立不依赖基线APP基础库的业务按照当前系统API来获取各自存储根路径(Android新系统或厂商定制系统上存储特性变更时,自行解决兼容性)
内置数据区files根路径:Context.getFilesDir()
内置数据区cache根路径:Context.getExternalCacheDir()
内置存储卡APP私有存储files根路径:Context.getExternalFilesDir()
内置存储卡APP私有存储cache根路径:Context.getExternalCacheDir()
4>垂直插件业务:各个插件按照3>中独立业务形式使用API,但插件中心会Hook Context中4个API来锁定根路径(对应到基线基础库的4个API上的根路径);
3.缓存清理规范
用户在基线APP的“清理缓存”入口触发清理时,可以提供2个层次的清理选项
1.自动清理
临时数据:图片,网络请求的缓存临时数据(如:okhttp,fresco下载缓存的文件),直接删除后对用户体验影响可以忽略,直接扫描后清理;
2.深度清理
1>自动扫描清理cache目录:按第1节规范的路径,接入基线APP的按要求统一存放路径,对数据分区和内置存储卡APP私有目录的cache目录和各级子目录(非白名单路径)下的文件直接进行清理,静默删除,不需要用户确认(类似于系统应用设置中“清理缓存”操作);
白名单路径:存放在cache目录下,删除后影响用户下次操作体验,删除后重复下载耗费流量,或其它特殊需求目录或文件;需要各业务找基线技术和产品申请配置白名单,白名单支持云端动态更新,白名单以相对路径中<子业务>或<子路径>名称匹配,不能直接配置 <一级业务>为白名单(避免不被删除的缓存文件范围过大);
2> 用户交互式清理:对files路径或各级子路径,做扫描,扫描出的文件和目录不直接删除,UI上展示出“文件用途,删除后的影响,文件大小”等信息,由用户自主选择和确认后删除; 各业务产品自己定义交互提示信息和涉及的文件路径范围;
3. 技术接口
1>基线业务,泡泡,Native库等业务,由基线APP在临时kill掉主进程,启独立子进程删除对应文件,删除后自动重启APP(参考地区模式切换的产品形态,产品定义必要的交互提示)效果上类似与系统应用设置中“清除数据”;独立业务可以提供独立清理API给基线APP调用清理对应文件,但各业务要确保文件能删除干净;
2>各插件业务的清理,由基线的插件中心统一做清理。
注:各业务的SharedPreferences,数据库,或其他独立文件中有记录或依赖被删除文件的,请自行内部判断检查文件被删除后可能导致业务逻辑异常的情况
参考:
1,Android官方文档对数据存储说明:Data Storage
2.基线APP实践和测试总结的存储特性:Android存储介绍及API定义
3.stackoverflow :when to clear the cache dir in Android