Unity3d C#实现文件(json、txt、xml等)加密、解密和加载(信息脱敏)功能实现(含源码工程)
前言
在Unity3d工程中经常有需要将一些文件放到本地项目中,诸如json、txt、csv和xml等文件需要放到StreamingAssets和Resources文件夹目录下,在程序发布后这些文件基本是对用户可见的状态,造成信息泄露,甚至有不法分子会利用这些信息进行一定的破坏行为。在这种背景下是很有必要将本地的一些文件进行加密处理再存储,然后加载后进行解密,这就能规避本地文件带来的风险。而本文就是围绕这个功能实现的一个插件,能快速的对文件进行加密和解密修改。只需要进行简单的配置,然后选中文件进行加密,即可实现该功能。 该项目的Unity3d版本为2020.3.28f1c1 Personal,注意如果版本差异太大可能会无法正确打开使用。
效果
加密配置:
加密前后对比:
自定义加密:
批量直接加密:
加密至StreamingAssets:
自定义解密:
批量解密:
实现
加密的核心功能实现采用的是加密转换的基本操作,根据加密的配置Key和Code进行加密操作,这些配置在保存/修改时会进行修改存储。而Unity3d工程中的新增菜单和窗口采用Unity编辑器拓展MenuItem和EditorWindow来实现。
配置实现
在顶部的菜单栏中新建一个菜单选项“Tools > 加密配置窗口”:
[MenuItem("Tools/加密配置窗口")] public static void ShowRegisterWindow() { EncoderConfigWind wind = (EncoderConfigWind)EditorWindow.GetWindow(typeof(EncoderConfigWind)); }
点击后打开编辑器窗口,这个窗口EncoderConfigWind是继承了Unity的编辑器窗口(EditorWindow)。
然后编写当渲染UI的时候调用OnGUI函数,绘制出配置窗口的明细:
private void OnGUI() { GUILayout.BeginVertical(new GUILayoutOption[0]); GUILayout.Space(10f); GUILayout.Label("加密文件配置", new GUILayoutOption[0]); GUILayout.Space(10f); GUILayout.Label("加密KEY", new GUILayoutOption[0]); this.TempKey = EditorGUILayout.TextArea(this.TempKey, new GUILayoutOption[] { GUILayout.MinHeight(50f) }); GUILayout.Space(10f); GUILayout.Label("加密Code", new GUILayoutOption[0]); this.LegalIVCode = EditorGUILayout.TextArea(this.LegalIVCode, new GUILayoutOption[] { GUILayout.MinHeight(50f) }); GUILayout.Space(10f); GUILayout.Label("加密文件后缀", new GUILayoutOption[0]); this.EncodeSuffix = EditorGUILayout.TextArea(this.EncodeSuffix, new GUILayoutOption[] { GUILayout.MinHeight(20f) }); GUILayout.Space(10f); GUILayout.Label("解密文件后缀", new GUILayoutOption[0]); this.DecodeSuffix = EditorGUILayout.TextArea(this.DecodeSuffix, new GUILayoutOption[] { GUILayout.MinHeight(20f) }); GUILayout.Space(10f); if (GUILayout.Button("保存配置", new GUILayoutOption[0])) { this.SaveConfigs(this.TempKey, this.LegalIVCode, this.EncodeSuffix, this.DecodeSuffix); } GUILayout.Space(10f); if (GUILayout.Button("获取帮助", new GUILayoutOption[0])) { Process.Start("https://blog.csdn.net/qq_33789001"); } GUILayout.EndVertical(); }
如上的代码能绘制出下面的窗口:
其主要的作用就是在打开配置窗口后绘制出窗体,在窗体中提供Key、Code、默认加密/解密文件的后缀等输入框,点击保存配置按钮后会将这些输入信息进行保存,通过File.WriteAllBytes()函数写入到Resources下的配置文件中去,示例代码如下:
File.WriteAllBytes(path+ "/Key.txt", keybytes);
加密实现
加密的实现是通过选择Assets窗口中的文件来进行加密,所有菜单的选项都采用了[MenuItem(“Assets/***”)]的形式进行。为了满足大部分的应用场景提供了多种操作方式,单一自定义加密、批量直接加密和批量的加密到StreamAssets和Resources的方式等,所以写了一个枚举进行操作:
public enum EncodeType { direct = 1, custom = 2, steamingassets = 3, resources = 4, custompath = 5 }
在Assets窗口中新建了如下的菜单选项,并通过加密EncodeType 的枚举值不同的方式进行区分:
[MenuItem("Assets/加密文件/直接加密(批量)")] private static void DoEncodeFileDir() { DoEncodeFiles(EncodeType.direct); } [MenuItem("Assets/加密文件/选路径加密(批量)")] private static void DoEncodeFileSelPath() { DoEncodeFiles(EncodeType.custompath); } [MenuItem("Assets/加密文件/放入StreamAssets(批量)")] private static void DoEncodeFileSa() { DoEncodeFiles(EncodeType.steamingassets); } [MenuItem("Assets/加密文件/放入Resources(批量)")] private static void DoEncodeFileRes() { DoEncodeFiles(EncodeType.resources); } [MenuItem("Assets/加密文件/自定义加密(单一)")] private static void DoEncodeFileCustom() { DoEncodeFiles(EncodeType.custom); }
点击加密选项后,根据选项和选择的文件进行加密处理,样例代码如下:
string[] strs = Selection.assetGUIDs; string path = AssetDatabase.GUIDToAssetPath(strs[0]); string suffix = (Resources.Load("EncodeFile/DeSuffix") as TextAsset).text; string buildPath = EditorUtility.SaveFilePanel("请选择解析保存的路径", GetPrePath(path), GetFileName(path), suffix); string spath = buildPath; if (!string.IsNullOrEmpty(path)) { string text = File.ReadAllText(path); string decode = Decrypt(text); //Debug.Log(spath); File.WriteAllText(spath, decode); AssetDatabase.Refresh();//刷新 } else Debug.LogError("请选择正确的文件进行解析!");
处理的流程是提取选中的文件路径,并读取加密的配置选项,再根据用户的自定义选择保存的目录、文件名称和文件后缀等加密后存储信息,将需要加密的文件进行读取内容,进行加密后,保存到对应的加密后存储位置中去。
解密实现
解密顾名思义就是加密的逆操作,其适用场景是对加密过的文件进行解密后,对文件进行浏览查看或者修改更新操作。对解密文件的操作类似于加密的操作窗口,都是在Assets窗口进行,以[MenuItem(“Assets/***”)]的形式进行,不过细分了入口的菜单:
[MenuItem("Assets/解密文件/直接解析(批量)")] [MenuItem("Assets/解密文件/自定解析(单一)")]
这里就两种方式自定义解析(仅支持单一文件)和批量直接解析的方式。解析的样例代码如下:
string[] strs = Selection.assetGUIDs; string path = AssetDatabase.GUIDToAssetPath(strs[0]); string suffix = (Resources.Load("EncodeFile/DeSuffix") as TextAsset).text; string buildPath = EditorUtility.SaveFilePanel("请选择解析保存的路径", GetPrePath(path), GetFileName(path), suffix); string spath = buildPath; if (!string.IsNullOrEmpty(path)) { string text = File.ReadAllText(path); string decode = Decrypt(text); //Debug.Log(spath); File.WriteAllText(spath, decode); AssetDatabase.Refresh();//刷新 } else Debug.LogError("请选择正确的文件进行解析!");
处理的流程和加密的流程类似,提取选中的文件路径,并读取加密的配置选项,再根据用户的自定义选择保存的目录、文件名称和文件后缀等解密后存储信息,将需要解密的文件进行读取内容,进行解密后,保存到对应的解密后存储位置中去。
加载解密测试
这个才是采用了两种方式进行,是读取Resources的方式和读取StreamingAssetsPath的方式。分别读取CSV、TXT和JSON、XML文件。测试过程尽量简单化,就是将文件读取、解密后,将解密的内容显示到Text上即可,其中需要注意的是如果文件存储到Resources下的话,文件最好是.txt、.json,否则可能读取不到内容。UI和测试脚本的配置如下:
读取Resources目录下的文件代码如下:
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public class LoadResourcesFileTest : MonoBehaviour { [Header("文件名")] public string FileName = ""; [Header("显示内容的Text")] public Text showText; private void Awake() { Debug.LogWarning("Resources文件夹下的文件最好是.txt、.json,否则可能读取不到"); if (!showText) showText = transform.GetComponent(); RequestFile(); } void RequestFile() { TextAsset ta = Resources.Load(FileName) as TextAsset; string EnCodeStr =""; if (ta) EnCodeStr = ta.text; Debug.Log("解析前:" + EnCodeStr); string orgString = Decoder.GetDecodeString(EnCodeStr); if (showText) showText.text = orgString; Debug.Log("解析后:" + orgString); } }
读取StreamingAssetsPath的代码如下:
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Networking; using UnityEngine.UI; public class LoadSAFileTest : MonoBehaviour { [Header("文件名")] public string FileName = ""; [Header("显示内容的Text")] public Text showText; private void Awake() { if (!showText) showText = transform.GetComponent(); string filePath = Application.streamingAssetsPath +"/"+ FileName; StartCoroutine(RequestFile(filePath)); } IEnumerator RequestFile(string uri) { using (UnityWebRequest webRequest = UnityWebRequest.Get(uri)) { // Request and wait for the desired page. yield return webRequest.SendWebRequest(); if (webRequest.result == UnityWebRequest.Result.Success) { Debug.Log("解析前:"+webRequest.downloadHandler.text); string orgString = Decoder.GetDecodeString(webRequest.downloadHandler.text); if (showText) showText.text = orgString; Debug.Log("解析后:" + orgString); } else { Debug.LogError("加载解密文件异常:" + webRequest.error); } } } }
这里的xml读取效果如下:
源码工程
https://download.csdn.net/download/qq_33789001/88915590
无法下载需要稍等,可能审核未通过。
工程说明
工程包含了上述所有的功能和演示场景,包含了所有的编辑器扩展代码和测试功能源码,可以自由修改自定义功能,也可以通过 “Tools” > “加密配置窗口”进行简单的加密配置后快速使用加密功能。
\Assets\TestFiles为加密测试的原文件;
\Assets\Editor为编辑器拓展的源代码;
\Assets\Resources 为测试加载加密文件并解析的文件和配置存储文件;\Assets\Scenes包含测试加载加密后的CSV、TXT、JSON、XML文件的demo场景;
\Assets\Scripts 测试和解密代码;
\Assets\StreamingAssets加密后的测试文件。