V7投稿 | CocosCreator开源框架oops-framework 之 本地存储(七)

引擎: CocosCreator 3.8.0

环境: Mac

Gitee: oops-game-kit


引言


oops-framework是由作者dgflash编写,基于CocosCreator 3.x而实现的开源框架。

该框架以插件形式存在,主要目的是为了降低与项目的耦合,并且通过插件内部的命令快速的获取最新版本。

该框架的特性有:

  • 提供游戏常用的功能库,提高开发效率
  • 提供业务模块代码模版,降低程序设计难度
  • 内置模块低耦合,可根据需要自行删减,以适应不同的类型
  • 提供了常用的插件工具,支持Excel表转Json、支持热更新、AB包
  • 增加了ECS、MVVM框架相关,以及常用的屏幕适配,UI管理,多语言等等

为了方便大家更好的学习和使用该框架,作者很贴心的准备了一些学习资料:

dgflash-哔哩视频

dgflash CSDN博客

dgflash-cocos论坛

Gitee dgflash项目仓库

注:oops-framework框架QQ群: 628575875

在CocosCreator官方商店,可以通过 oops 搜索更多的框架项目Demo进行学习。

1_2


本地存储


在CocosCreator中,本地存储主要使用sys.localStorage 接口,主要接口有:

接口 描述
setItem(key, value) 保存指定索引的数据
getItem(key) 获取指定索引的数据
removeItem(key) 移除指定索引的数据
clear() 清空所有数据

数据以 key-value的格式进行存储,最后以sqlite数据库格式 明文 保存。

// 保存简单数据
sys.localStorage.setItem('gold', 100);
// 保存复杂数据
let userData = {
    name: 'Tracer',
    level: 1,
    gold: 100
};
sys.localStorage.setItem('userData', JSON.stringify(userData));

// 读取数据
let data = sys.localStorage.getItem('gold');
console.log(data);

注: 内容参考官方文档:存储和读取用户数据


StorageManager


oops-framework 框架中,本地存储是通过 StorageManager来实现的, 在Oop.ts中调用的入口:

export class oops {
  /** 本地存储 */
  static storage: StorageManager = new StorageManager();
}

StorageManager的实现,是对CocosCreator本地存储的额外包装,增加了新的特性,主要有:

  • 设置用户ID,将key用户ID组合,避免存储数据被覆盖
  • 增加了MD5、AES的第三方库加密,key使用MD5加密, value使用AES加密,增加的数据的安全性
  • 在模拟器或浏览器的调试下,不会触发数据加密,方便明文调试

提供的主要参数或接口有:

接口 返回类型 说明
init(key: string, iv: string) void 初始化密钥
setUser(id: string) void 初始化用户ID,默认为空
set(key: string, value: any) void 存储数据
get(key: string, defaultValue: any = “”) string 获取数据
getNumber(key: string, defaultValue: number = 0) number 获取number类型数据
getBoolean(key: string) boolean 获取boolean类型数据
getJson(key: string, defaultValue?: any) any 获取Json类型数据
remove(key: string) void 移除指定字段的数据
clear() void 清空所有数据

以音频管理的初始化为例,看下简单示例:

let data = oops.storage.get(LOCAL_STORE_KEY);

加密

加密相关使用的是NPM第三方加密库: crypto-es, 支持对称加密、哈希函数、数字签名和公钥加密等。

注: 更多内容可参考: NPM crypto-es

关于加密相关,在框架中已经提供,在 node_modules/crypto-es目录中。

如果想自己安装,需要安装NPM,终端安装命令:

npm install -g yarn
yarn add crypto-es

注: NPM的安装可参考: Mac 安装使用NPM

框架针对于 crypto-es 封装了一个工具类: EncryptUtil.ts ,主要接口有:

接口 说明
initCrypto(key, iv) 初始化加密库的key和iv
md5(msg) 获取md5加密字段
aesEncrypt(msg, key, iv) AES加密
aesDecrypt(msg, key, iv) 获取AES解密数据

注: key和iv的设定在 resources/config.json中有设定


初始化

本地存储的初始化主要包含两个方面:

  1. key和iv的初始化,这个在框架的Root.ts获取 resources/config.json 完成初始化的
// Root.ts
onLoad() {
  if (!isInited) {

    let config_name = "config";
    oops.res.load(config_name, JsonAsset, () => {
      var config = oops.res.get(config_name);
      // 初始化本地存储加密
			var key = oops.config.game.localDataKey;
      var iv = oops.config.game.localDataIv;
      oops.storage.init(key, iv);      
    });
  }
}
  1. 用户ID的初始化,在请求服务器获取用户ID后,进行初始化,示例代码:
var uid = 10000;                // 用户唯一编号数据
oops.storage.setUser(uid);

注:本地模拟,没用用户ID,框架会默认为""


保存数据

数据的保存主要通过接口: set(key: string, value: any)

set(key: string, value: any) {
	// 根据用户ID连接key
  var keywords = `${key}_${this._id}`;

  if (null == key) {
    console.error("存储的key不能为空");
    return;
  }
  // 检测是否对key进行MD5加密
  if (!PREVIEW) {
    keywords = EncryptUtil.md5(keywords);
  }
  if (null == value) {
    console.warn("存储的值为空,则直接移除该存储");
    this.remove(key);
    return;
  }
  if (typeof value === 'function') {
    console.error("储存的值不能为方法");
    return;
  }
  // 转换object,number类型的value
  if (typeof value === 'object') {
    try {
      value = JSON.stringify(value);
    }
    catch (e) {
      console.error(`解析失败,str = ${value}`);
      return;
    }
  }
  else if (typeof value === 'number') {
    value = value + "";
  }
	// 检测是否对value进行AES加密
  if (!PREVIEW && null != this._key && null != this._iv) {
    value = EncryptUtil.aesEncrypt(`${value}`, this._key, this._iv);
  }
  sys.localStorage.setItem(keywords, value);
}

框架主要做的事情:

  • 将key字段以 key_用户ID 的方式进行连接,并检测是否进行MD5加密
  • 检测value字段的类型,是否为null、function等不合法类型
  • 转换value字段数据,将number转换为字符串、将object转换为json字符串
  • 检测value字段是否进行AES加密
  • 调用引擎提供的接口存储

Map数据存储


框架对于基础数据类型的支持是很好,但对 Map对象的支持不太好,我们可以通过ES6的特性将Map转换为数组, 获取的时候将数组转换为Map对象,简单的示例:

let map = new Map();
map.set("a", 1);
map.set("b", "hello");
map.set("c", true);

// 将map转换为数组
let mapToArray = Array.from(map);
console.log(mapToArray);  // [["a", 1], ["b", "hello"], ["c", true]] 
// 将数组转换为map
let arrayToMap = new Map(mapToArray);
console.log(arrayToMap);   // Map (3) {"a" => 1, "b" => "hello", "c" => true}

示例:

// 保存数据
private saveMapData() {
  let map = new Map();
  map.set("a", 1);
  map.set("b", "hello");
  map.set("c", true);
  // 将map转换为数组
  let mapToArray = Array.from(map);
  // 存储数据
  oops.storage.set("MapData", mapToArray);
}

// 获取数据
private getMapData():any {
  let map = null;
  let data = oops.storage.getJson("MapData", []);
  if (Object.keys(data).length <= 0) {
    map = new Map();
  } else {
    map = new Map(data);
  }
  return map;
}
// mapData: Map(3) {'a' => 1, 'b' => 'hello', 'c' => true}
console.log("mapData:", this.getMapData());

最后,祝大家学习生活工作愉快!