feat: 完成多项功能迭代与项目配置优化
1. 新增WiFi连接UI预制体与多语言文案 2. 重构BLE通信通知处理逻辑 3. 调整数据库总工作时长类型为float 4. 更新项目与Android构建配置 5. 主页添加消杀数据上传进度提示
This commit is contained in:
parent
a7024a6e19
commit
1847d74de2
@ -6,18 +6,21 @@ using System.IO;
|
|||||||
|
|
||||||
public class iOSWiFiBuildPostProcessor
|
public class iOSWiFiBuildPostProcessor
|
||||||
{
|
{
|
||||||
|
private const string WIFI_INFO_ENTITLEMENT = "com.apple.developer.networking.wifi-info";
|
||||||
|
|
||||||
[PostProcessBuild]
|
[PostProcessBuild]
|
||||||
public static void OnPostProcessBuild(BuildTarget target, string pathToBuiltProject)
|
public static void OnPostProcessBuild(BuildTarget target, string pathToBuiltProject)
|
||||||
{
|
{
|
||||||
if (target != BuildTarget.iOS) return;
|
if (target != BuildTarget.iOS) return;
|
||||||
|
|
||||||
|
// ===== 1. 配置 Info.plist =====
|
||||||
string plistPath = Path.Combine(pathToBuiltProject, "Info.plist");
|
string plistPath = Path.Combine(pathToBuiltProject, "Info.plist");
|
||||||
PlistDocument plist = new PlistDocument();
|
PlistDocument plist = new PlistDocument();
|
||||||
plist.ReadFromString(File.ReadAllText(plistPath));
|
plist.ReadFromString(File.ReadAllText(plistPath));
|
||||||
|
|
||||||
PlistElementDict rootDict = plist.root;
|
PlistElementDict rootDict = plist.root;
|
||||||
|
|
||||||
// 添加位置权限描述(iOS 获取 WiFi 需要)
|
// 添加位置权限描述(iOS 13+ 获取 WiFi 需要)
|
||||||
rootDict.SetString("NSLocationWhenInUseUsageDescription", "需要位置权限来获取当前 WiFi 信息");
|
rootDict.SetString("NSLocationWhenInUseUsageDescription", "需要位置权限来获取当前 WiFi 信息");
|
||||||
|
|
||||||
// 添加蓝牙权限描述
|
// 添加蓝牙权限描述
|
||||||
@ -30,15 +33,44 @@ public class iOSWiFiBuildPostProcessor
|
|||||||
bgModes.AddString("bluetooth-central");
|
bgModes.AddString("bluetooth-central");
|
||||||
|
|
||||||
File.WriteAllText(plistPath, plist.WriteToString());
|
File.WriteAllText(plistPath, plist.WriteToString());
|
||||||
|
|
||||||
// 添加 CoreBluetooth.framework
|
// ===== 2. 配置 Xcode 项目 =====
|
||||||
string projPath = PBXProject.GetPBXProjectPath(pathToBuiltProject);
|
string projPath = PBXProject.GetPBXProjectPath(pathToBuiltProject);
|
||||||
PBXProject proj = new PBXProject();
|
PBXProject proj = new PBXProject();
|
||||||
proj.ReadFromString(File.ReadAllText(projPath));
|
proj.ReadFromString(File.ReadAllText(projPath));
|
||||||
string targetGuid = proj.GetUnityMainTargetGuid();
|
string targetGuid = proj.GetUnityMainTargetGuid();
|
||||||
|
|
||||||
proj.AddFrameworkToProject(targetGuid, "CoreBluetooth.framework", false);
|
proj.AddFrameworkToProject(targetGuid, "CoreBluetooth.framework", false);
|
||||||
|
|
||||||
|
// ===== 3. 添加 Access WiFi Information 权限(iOS 14+ 必需)=====
|
||||||
|
string entitlementsFileName = "app.entitlements";
|
||||||
|
string entitlementsPath = Path.Combine(pathToBuiltProject, entitlementsFileName);
|
||||||
|
|
||||||
|
// 创建或读取 entitlements 文件
|
||||||
|
PlistDocument entitlements = new PlistDocument();
|
||||||
|
if (File.Exists(entitlementsPath))
|
||||||
|
{
|
||||||
|
entitlements.ReadFromString(File.ReadAllText(entitlementsPath));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
entitlements.root.SetString("aps-environment", "development");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加 WiFi 信息访问权限(iOS 14+)
|
||||||
|
entitlements.root.SetBoolean(WIFI_INFO_ENTITLEMENT, true);
|
||||||
|
File.WriteAllText(entitlementsPath, entitlements.WriteToString());
|
||||||
|
|
||||||
|
// 设置 entitlements 文件到 Xcode 项目
|
||||||
|
proj.SetBuildProperty(targetGuid, "CODE_SIGN_ENTITLEMENTS", entitlementsFileName);
|
||||||
|
|
||||||
|
// 同时设置 framework target
|
||||||
|
string frameworkTargetGuid = proj.GetUnityFrameworkTargetGuid();
|
||||||
|
if (!string.IsNullOrEmpty(frameworkTargetGuid))
|
||||||
|
{
|
||||||
|
proj.SetBuildProperty(frameworkTargetGuid, "CODE_SIGN_ENTITLEMENTS", entitlementsFileName);
|
||||||
|
}
|
||||||
|
|
||||||
File.WriteAllText(projPath, proj.WriteToString());
|
File.WriteAllText(projPath, proj.WriteToString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,16 +4,16 @@ apply plugin: 'com.android.library'
|
|||||||
dependencies {
|
dependencies {
|
||||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||||
// Android Resolver Dependencies Start
|
// Android Resolver Dependencies Start
|
||||||
implementation 'com.google.android.gms:play-services-base:18.10.0' // Assets/Firebase/Editor/DatabaseDependencies.xml:20
|
implementation 'com.google.android.gms:play-services-base:18.10.0' // Assets/Firebase/Editor/DatabaseDependencies.xml:17
|
||||||
// implementation 'com.google.firebase:firebase-analytics:23.0.0' // Assets/Firebase/Editor/AnalyticsDependencies.xml:13
|
// implementation 'com.google.firebase:firebase-analytics:23.0.0' // Assets/Firebase/Editor/AnalyticsDependencies.xml:11
|
||||||
implementation 'com.google.firebase:firebase-analytics:23.2.0' // Assets/Firebase/Editor/DatabaseDependencies.xml:18
|
implementation 'com.google.firebase:firebase-analytics:23.2.0' // Assets/Firebase/Editor/DatabaseDependencies.xml:15
|
||||||
implementation 'com.google.firebase:firebase-analytics-unity:13.5.0' // Assets/Firebase/Editor/AnalyticsDependencies.xml:18
|
implementation 'com.google.firebase:firebase-analytics-unity:13.5.0' // Assets/Firebase/Editor/AnalyticsDependencies.xml:16
|
||||||
implementation 'com.google.firebase:firebase-app-unity:13.12.0' // Assets/Firebase/Editor/AppDependencies.xml:25
|
implementation 'com.google.firebase:firebase-app-unity:13.12.0' // Assets/Firebase/Editor/AppDependencies.xml:22
|
||||||
implementation 'com.google.firebase:firebase-auth:24.1.0' // Assets/Firebase/Editor/AuthDependencies.xml:16
|
implementation 'com.google.firebase:firebase-auth:24.1.0' // Assets/Firebase/Editor/AuthDependencies.xml:13
|
||||||
implementation 'com.google.firebase:firebase-auth-unity:13.12.0' // Assets/Firebase/Editor/AuthDependencies.xml:23
|
implementation 'com.google.firebase:firebase-auth-unity:13.12.0' // Assets/Firebase/Editor/AuthDependencies.xml:20
|
||||||
implementation 'com.google.firebase:firebase-common:22.0.1' // Assets/Firebase/Editor/AppDependencies.xml:16
|
implementation 'com.google.firebase:firebase-common:22.0.1' // Assets/Firebase/Editor/AppDependencies.xml:13
|
||||||
implementation 'com.google.firebase:firebase-database:22.0.1' // Assets/Firebase/Editor/DatabaseDependencies.xml:16
|
implementation 'com.google.firebase:firebase-database:22.0.1' // Assets/Firebase/Editor/DatabaseDependencies.xml:13
|
||||||
implementation 'com.google.firebase:firebase-database-unity:13.12.0' // Assets/Firebase/Editor/DatabaseDependencies.xml:25
|
implementation 'com.google.firebase:firebase-database-unity:13.12.0' // Assets/Firebase/Editor/DatabaseDependencies.xml:22
|
||||||
// Android Resolver Dependencies End
|
// Android Resolver Dependencies End
|
||||||
**DEPS**}
|
**DEPS**}
|
||||||
|
|
||||||
|
|||||||
@ -19,7 +19,7 @@ dependencyResolutionManagement {
|
|||||||
// Android Resolver Repos Start
|
// Android Resolver Repos Start
|
||||||
def unityProjectPath = $/file:///**DIR_UNITYPROJECT**/$.replace("\\", "/")
|
def unityProjectPath = $/file:///**DIR_UNITYPROJECT**/$.replace("\\", "/")
|
||||||
maven {
|
maven {
|
||||||
url (unityProjectPath + "/Assets/GeneratedLocalRepo/Firebase/m2repository") // Assets/Firebase/Editor/AnalyticsDependencies.xml:18, Assets/Firebase/Editor/AppDependencies.xml:25, Assets/Firebase/Editor/AuthDependencies.xml:23, Assets/Firebase/Editor/DatabaseDependencies.xml:25
|
url (unityProjectPath + "/Assets/GeneratedLocalRepo/Firebase/m2repository") // Assets/Firebase/Editor/AnalyticsDependencies.xml:16, Assets/Firebase/Editor/AppDependencies.xml:22, Assets/Firebase/Editor/AuthDependencies.xml:20, Assets/Firebase/Editor/DatabaseDependencies.xml:22
|
||||||
}
|
}
|
||||||
mavenLocal()
|
mavenLocal()
|
||||||
// Android Resolver Repos End
|
// Android Resolver Repos End
|
||||||
|
|||||||
@ -1508,6 +1508,11 @@
|
|||||||
"key": "100302",
|
"key": "100302",
|
||||||
"zh": "恢复出厂设置失败,请稍后重试",
|
"zh": "恢复出厂设置失败,请稍后重试",
|
||||||
"en": "Reset failed, please try again later"
|
"en": "Reset failed, please try again later"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "100303",
|
||||||
|
"zh": "获取到{0}条消杀数据,正在上传,请稍后",
|
||||||
|
"en": "Uploading {0} elimination records, please wait..."
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -50,7 +50,6 @@ namespace Kill.Bluetooth
|
|||||||
public event Action<StatisticsData> OnStatisticsDataReceived; // 收到统计数据
|
public event Action<StatisticsData> OnStatisticsDataReceived; // 收到统计数据
|
||||||
public event Action<SensorData> OnSensorDataReceived; // 收到传感器数据
|
public event Action<SensorData> OnSensorDataReceived; // 收到传感器数据
|
||||||
public event Action<MosquitoData> OnMosquitoDataReceived; // 收到蚊虫数据通知
|
public event Action<MosquitoData> OnMosquitoDataReceived; // 收到蚊虫数据通知
|
||||||
public event Action<byte[]> OnDataReceived; // 收到原始数据
|
|
||||||
public event Action<string> OnRawDataReceived; // 收到原始数据(十六进制字符串)
|
public event Action<string> OnRawDataReceived; // 收到原始数据(十六进制字符串)
|
||||||
public event Action<string> OnRawDataSent; // 发送原始数据(十六进制字符串)
|
public event Action<string> OnRawDataSent; // 发送原始数据(十六进制字符串)
|
||||||
public event Action<string> OnCommunicationError; // 通信错误
|
public event Action<string> OnCommunicationError; // 通信错误
|
||||||
@ -1954,7 +1953,6 @@ namespace Kill.Bluetooth
|
|||||||
if (success)
|
if (success)
|
||||||
{
|
{
|
||||||
mosquitoDataCount=(int)count;
|
mosquitoDataCount=(int)count;
|
||||||
OnDataReceived+=HandleMosquitoDataNotification;
|
|
||||||
Log($"蚊虫数据请求成功,期望接收 {count} 条数据");
|
Log($"蚊虫数据请求成功,期望接收 {count} 条数据");
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -1965,15 +1963,12 @@ namespace Kill.Bluetooth
|
|||||||
}
|
}
|
||||||
public int mosquitoDataCount=0;
|
public int mosquitoDataCount=0;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 处理蚊虫数据通知 (通知类型 0x0B)
|
/// 处理蚊虫数据通知
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void HandleMosquitoDataNotification(byte[] notifyData)
|
private void HandleMosquitoDataNotification(byte[] notifyData)
|
||||||
{
|
{
|
||||||
if(mosquitoDataCount<=0)
|
if(mosquitoDataCount<=0)
|
||||||
{
|
|
||||||
OnDataReceived-=HandleMosquitoDataNotification;
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
if (notifyData == null || notifyData.Length < 20)
|
if (notifyData == null || notifyData.Length < 20)
|
||||||
{
|
{
|
||||||
LogError("蚊虫数据通知格式错误,数据长度不足20字节");
|
LogError("蚊虫数据通知格式错误,数据长度不足20字节");
|
||||||
@ -2421,10 +2416,15 @@ namespace Kill.Bluetooth
|
|||||||
private void HandleReceivedFrame(BLEFrame frame)
|
private void HandleReceivedFrame(BLEFrame frame)
|
||||||
{
|
{
|
||||||
bool wasWaitingResponse = IsWaitingResponse;
|
bool wasWaitingResponse = IsWaitingResponse;
|
||||||
|
|
||||||
// 检查是否是对等待命令的响应
|
// 优先处理设备主动通知,避免被等待响应的流程拦截
|
||||||
if (IsWaitingResponse && frame.Command == LastCommand)
|
if (frame.ReadWrite == BLEConstants.RW_NOTIFY)
|
||||||
{
|
{
|
||||||
|
HandleNotification(frame.Command, frame.Data);
|
||||||
|
}
|
||||||
|
else if (IsWaitingResponse && frame.Command == LastCommand)
|
||||||
|
{
|
||||||
|
// 匹配到等待的响应
|
||||||
IsWaitingResponse = false;
|
IsWaitingResponse = false;
|
||||||
_responseTimer = 0;
|
_responseTimer = 0;
|
||||||
|
|
||||||
@ -2432,11 +2432,6 @@ namespace Kill.Bluetooth
|
|||||||
_pendingCallback?.Invoke(response);
|
_pendingCallback?.Invoke(response);
|
||||||
_pendingCallback = null;
|
_pendingCallback = null;
|
||||||
}
|
}
|
||||||
else if (frame.ReadWrite == BLEConstants.RW_NOTIFY)
|
|
||||||
{
|
|
||||||
// 处理设备主动通知
|
|
||||||
OnDataReceived?.Invoke(frame.Data);
|
|
||||||
}
|
|
||||||
else if (IsWaitingResponse)
|
else if (IsWaitingResponse)
|
||||||
{
|
{
|
||||||
// 尝试处理非匹配的响应,可能是硬件响应延迟
|
// 尝试处理非匹配的响应,可能是硬件响应延迟
|
||||||
@ -2455,6 +2450,22 @@ namespace Kill.Bluetooth
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 通用的设备通知分发器,按命令类型路由到对应处理逻辑
|
||||||
|
/// </summary>
|
||||||
|
private void HandleNotification(byte command, byte[] data)
|
||||||
|
{
|
||||||
|
switch (command)
|
||||||
|
{
|
||||||
|
case BLEConstants.NOTIFY_MOSQUITO_DATA:
|
||||||
|
HandleMosquitoDataNotification(data);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Log($"未处理的设备通知 0x{command:X2}");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 响应超时处理
|
/// 响应超时处理
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@ -270,7 +270,7 @@ namespace Kill.Managers
|
|||||||
public string bind_time;
|
public string bind_time;
|
||||||
public string device_model;
|
public string device_model;
|
||||||
public string firmware_version;
|
public string firmware_version;
|
||||||
public int? total_work_hours;
|
public float? total_work_hours;
|
||||||
public int? total_mosquitoes_killed;
|
public int? total_mosquitoes_killed;
|
||||||
public string location;
|
public string location;
|
||||||
public string last_online_time;
|
public string last_online_time;
|
||||||
|
|||||||
@ -1400,6 +1400,8 @@ namespace Kill.UI.Pages
|
|||||||
Coroutine waitToPostMosquitoDatas=null;
|
Coroutine waitToPostMosquitoDatas=null;
|
||||||
private void OnMosquitoDataReceived(MosquitoData mosquitoData)
|
private void OnMosquitoDataReceived(MosquitoData mosquitoData)
|
||||||
{
|
{
|
||||||
|
if(mosquitoDatas==null)
|
||||||
|
return;
|
||||||
DateTime now=DateTime.Now;
|
DateTime now=DateTime.Now;
|
||||||
mosquitoDatas.Add(mosquitoData);
|
mosquitoDatas.Add(mosquitoData);
|
||||||
if(waitToPostMosquitoDatas!=null)
|
if(waitToPostMosquitoDatas!=null)
|
||||||
@ -1469,6 +1471,9 @@ namespace Kill.UI.Pages
|
|||||||
{
|
{
|
||||||
if (success)
|
if (success)
|
||||||
{
|
{
|
||||||
|
string tip=LanguageManager.Instance.GetLanguage("100303");
|
||||||
|
tip=tip.Replace("{0}",count.ToString());
|
||||||
|
ToastUI.ShowText(tip);
|
||||||
Debug.Log($"已请求 {count.Count} 条蚊虫数据,等待接收...");
|
Debug.Log($"已请求 {count.Count} 条蚊虫数据,等待接收...");
|
||||||
mosquitoDatas=new List<MosquitoData>();
|
mosquitoDatas=new List<MosquitoData>();
|
||||||
aimMosquitoDataCount=(int)count.Count;
|
aimMosquitoDataCount=(int)count.Count;
|
||||||
|
|||||||
@ -13,7 +13,7 @@ PlayerSettings:
|
|||||||
useOnDemandResources: 0
|
useOnDemandResources: 0
|
||||||
accelerometerFrequency: 100
|
accelerometerFrequency: 100
|
||||||
companyName: photonmatrix
|
companyName: photonmatrix
|
||||||
productName: photonmatrix
|
productName: Photon Matrix
|
||||||
defaultCursor: {fileID: 0}
|
defaultCursor: {fileID: 0}
|
||||||
cursorHotspot: {x: 0, y: 0}
|
cursorHotspot: {x: 0, y: 0}
|
||||||
m_SplashScreenBackgroundColor: {r: 0.08627451, g: 0.08627451, b: 0.08627451, a: 1}
|
m_SplashScreenBackgroundColor: {r: 0.08627451, g: 0.08627451, b: 0.08627451, a: 1}
|
||||||
@ -176,7 +176,7 @@ PlayerSettings:
|
|||||||
VisionOS: 0
|
VisionOS: 0
|
||||||
iPhone: 0
|
iPhone: 0
|
||||||
tvOS: 0
|
tvOS: 0
|
||||||
overrideDefaultApplicationIdentifier: 0
|
overrideDefaultApplicationIdentifier: 1
|
||||||
AndroidBundleVersionCode: 1
|
AndroidBundleVersionCode: 1
|
||||||
AndroidMinSdkVersion: 33
|
AndroidMinSdkVersion: 33
|
||||||
AndroidTargetSdkVersion: 0
|
AndroidTargetSdkVersion: 0
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user