由于Pico老版本VRSDK不支持新设备(其实是支持到了Neo3/Neo3Pro,虽然Pvr_UnitySDKAPI仍然可以用,但对于获取设备SN号,加密和读取文本等使用Pvr_UnitySDKAPI的功能已经失效),全面更新为UnityXR,故重新写了一套Android端的设备加密读取SN号解密功能。
请注意,由于Unity2021.2已经不允许直接把res文件放在Plugins/Android目录下,有一种说法是全面使用aar,故对于老版本PvrAPI开发的项目升级XRSDK来说最好还是使用Unity2020.3.21-2021.2之间的版本。另外,Pico官方给的SDK需要外部加载。
获取SN号(本项目使用的版本为Unity2020.3.32)
与以前的Pvr不同的是目前需要绑定设备
PXR_Enterprise.InitEnterpriseService();
PXR_Enterprise.BindEnterpriseService(toBServiceBind);
获取代码:
return PXR_Enterprise.StateGetDeviceInfo(SystemInfoEnum.EQUIPMENT_SN);
adb.devices可以PC获取设备SN,但是下面这种方式不行了:
源生安卓代码调用设备SN号无法获取!(Neo3之后的设备,G2和Neo2仍然可以)
AndroidJavaObject jo = new AndroidJavaObject("android.os.Build");
string serial = jo.GetStatic<string>("SERIAL");
加密解密
public static class EncryptDecrypt
{
//加解密密钥,字符串长度必须为8(自定义)
public static string key = "11111111";
//加密
public static string DESEnCode(string pToEncrypt)
{
DESCryptoServiceProvider des = new DESCryptoServiceProvider();
byte[] inputByteArray = Encoding.GetEncoding("UTF-8").GetBytes(pToEncrypt);
try
{
des.Key = ASCIIEncoding.ASCII.GetBytes(key);
des.IV = ASCIIEncoding.ASCII.GetBytes(key);
}
catch (Exception)
{
UnityEngine.Debug.Log("加密时密钥格式错误!");
return null;
}
MemoryStream ms = new MemoryStream();
CryptoStream cs = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write);
try
{
cs.Write(inputByteArray, 0, inputByteArray.Length);
cs.FlushFinalBlock();
}
catch (Exception)
{
UnityEngine.Debug.Log("加密错误!");
return null;
}
StringBuilder ret = new StringBuilder();
foreach (byte b in ms.ToArray())
{
ret.AppendFormat("{0:X2}", b);
}
ret.ToString();
return ret.ToString();
}
//解密
public static string DESDeCode(string pToDecrypt)
{
DESCryptoServiceProvider des = new DESCryptoServiceProvider();
byte[] inputByteArray = new byte[pToDecrypt.Length / 2];
for (int x = 0; x < pToDecrypt.Length / 2; x++)
{
int i = (Convert.ToInt32(pToDecrypt.Substring(x * 2, 2), 16));
inputByteArray[x] = (byte)i;
}
try
{
des.Key = ASCIIEncoding.ASCII.GetBytes(key);
des.IV = ASCIIEncoding.ASCII.GetBytes(key);
}
catch (Exception)
{
UnityEngine.Debug.Log("解密时密钥格式错误!");
return null;
}
MemoryStream ms = new MemoryStream();
CryptoStream cs = new CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Write);
try
{
cs.Write(inputByteArray, 0, inputByteArray.Length);
cs.FlushFinalBlock();
}
catch (Exception)
{
UnityEngine.Debug.Log("解密错误");
return null;
}
StringBuilder ret = new StringBuilder();
return Encoding.Default.GetString(ms.ToArray());
}
private static int getNewSeed()
{
byte[] rndBytes = new byte[4];
System.Security.Cryptography.RNGCryptoServiceProvider rng = new System.Security.Cryptography.RNGCryptoServiceProvider();
rng.GetBytes(rndBytes);
return BitConverter.ToInt32(rndBytes, 0);
}
public static string GetRandomString(int len)
{
string s = "123456789abcdefghijklmnpqrstuvwxyzABCDEFGHIJKLMNPQRSTUVWXYZ";
string reValue = string.Empty;
Random rnd = new Random(getNewSeed());
while (reValue.Length < len)
{
string s1 = s[rnd.Next(0, s.Length)].ToString();
if (reValue.IndexOf(s1) == -1) reValue += s1;
}
return reValue;
}
}
string setAName = "A";
string setBName = "B";
string setKey = "11111111";//加密秘钥
private string 内部存储文件内容="";
private string 设备SN号 = "";
//获取激活码
string GetCode(string AName , string BName , string key)
{
EncryptDecrypt.key = key;
return EncryptDecrypt.DESEnCode(AName + "/" + BName + "/" + 设备SN号);
}
//判断
if (内部存储文件内容.Contains(GetCode(setAName , setBName , setKey)))
读取设备里的文件
两种方式:
1.安装后安卓自动安装的源生文件夹内部的文件
/// <summary>
/// 获取Pico下的文件(安装后的Android源生文件夹)
/// </summary>
void GetTxt_Fun1() //目标路径:"/storage/emulated/0/Android/data/com.XX(包名)/files";
{
Debug.Log(Application.persistentDataPath);
string filePath = Application.persistentDataPath + "/k.txt";
if (File.Exists(filePath))
{
string[] fileData = File.ReadAllLines(filePath);
text.text = fileData[0];
}
}
2.外部指定文件夹内的文件
/// <summary>
/// 获取Pico下的文件,指定文件夹
/// </summary>
void GetTxt_Fun2() //目标路径:"/storage/emulated/0/XXX/k2.txt";
{
string filePath = "/storage/emulated/0/XXX" + "/k2.txt";
if (File.Exists(filePath))
{
string[] fileData = File.ReadAllLines(filePath);
text.text = fileData[0];
}
}
需要请求安卓权限
<!--payment-->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!--falcon VIBRATE-->
<uses-permission android:name="android.permission.VIBRATE" />
<!--Miracast -->
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<!--read config-->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_MEDIA_STORAGE" />
<!--set bright -->
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<!--AvrAPI -->
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
<!--change language -->
<uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />