using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Security; using System.Threading; using BITKit.Apps; using Cysharp.Threading.Tasks; using UnityEngine; using UnityEngine.Events; using HttpClient = System.Net.Http.HttpClient; using OperationCanceledException = System.OperationCanceledException; using UnityWebRequest = UnityEngine.Networking.UnityWebRequest; namespace BITKit { [Serializable] public class UnityApplicationServiceSingleton:IApplicationService { private IApplicationService _applicationServiceImplementation=>ApplicationService.Singleton; public event Action OnClientVersionCheck { add => ApplicationService.OnClientVersionCheck += value; remove => ApplicationService.OnClientVersionCheck -= value; } public event Action OnLatestVersionCheck { add => ApplicationService.OnLatestVersionCheck += value; remove => ApplicationService.OnLatestVersionCheck -= value; } public event Action OnDownloadLatest { add => ApplicationService.OnDownloadLatest += value; remove => ApplicationService.OnDownloadLatest -= value; } public event Action OnDownloadProgress { add => ApplicationService.OnDownloadProgress += value; remove => ApplicationService.OnDownloadProgress -= value; } public event Action OnDownloadComplete { add => ApplicationService.OnDownloadComplete += value; remove => ApplicationService.OnDownloadComplete -= value; } public event Action OnDetectedLatestVersion; public UniTask DownloadLatestVersionAsync() { return _applicationServiceImplementation.DownloadLatestVersionAsync(); } public string DownloadLatestUrl => _applicationServiceImplementation.DownloadLatestUrl; public string CheckLatestVersionUrl => _applicationServiceImplementation.CheckLatestVersionUrl; } /// /// 用于Unity的应用程序服务,详细功能请查看 /// public class ApplicationService : MonoBehaviour,IApplicationService { private static readonly HttpClient Client = new(); public static event Action OnClientVersionCheck; public static event Action OnLatestVersionCheck; public static event Action OnDownloadLatest; public static event Action OnDownloadProgress; public static event Action OnDownloadComplete; internal static IApplicationService Singleton { get; private set; } [SerializeField, SerializeReference, SubclassSelector] private IReference getVersionUrl; [SerializeField, SerializeReference, SubclassSelector] private IReference getLatestUrl; [SerializeReference, SubclassSelector] private ITicker checkTick; [SerializeField] private bool dontDestroyOnLoad; event Action IApplicationService.OnClientVersionCheck { add => OnClientVersionCheck += value; remove => OnClientVersionCheck -= value; } event Action IApplicationService.OnLatestVersionCheck { add => OnLatestVersionCheck += value; remove => OnLatestVersionCheck -= value; } event Action IApplicationService.OnDownloadLatest { add => OnDownloadLatest += value; remove => OnDownloadLatest -= value; } event Action IApplicationService.OnDownloadProgress { add => OnDownloadProgress += value; remove => OnDownloadProgress -= value; } event Action IApplicationService.OnDownloadComplete { add => OnDownloadComplete += value; remove => OnDownloadComplete -= value; } public event Action OnDetectedLatestVersion { add => Singleton.OnDetectedLatestVersion += value; remove => Singleton.OnDetectedLatestVersion -= value; } private UnityWebRequest downloadRequest; public async UniTask DownloadLatestVersionAsync() { var filePath = $"{Application.persistentDataPath}/{Application.productName}-Build_{Application.platform}_{Application.version}."; switch (Application.platform) { case RuntimePlatform.Android: filePath += "apk"; break; default: filePath += "zip"; break; } BIT4Log.Log($"开始下载最新版本,下载地址:{getLatestUrl.Value},保存路径:{filePath}"); OnDownloadLatest?.Invoke(getLatestUrl.Value); downloadRequest = UnityWebRequest.Get(getLatestUrl.Get()); downloadRequest.SendWebRequest().ToUniTask().Forget(); while (downloadRequest.downloadHandler.isDone is false) { OnDownloadProgress?.Invoke(downloadRequest.downloadProgress); destroyCancellationToken.ThrowIfCancellationRequested(); await UniTask.NextFrame(); } await File.WriteAllBytesAsync(filePath, downloadRequest.downloadHandler.data,destroyCancellationToken); OnDownloadComplete?.Invoke(filePath); return filePath; } public string DownloadLatestUrl => getLatestUrl.Value; public string CheckLatestVersionUrl=>getVersionUrl.Value; private bool _isBusy; private void Awake() { Singleton = this; } private void Start() { if (dontDestroyOnLoad) { DontDestroyOnLoad(gameObject); } try { OnTick(0); } catch(OperationCanceledException){} catch (Exception e) { BIT4Log.LogException(e); } destroyCancellationToken.Register(Dispose); checkTick?.Add(OnTick); } private async void OnTick(float deltaTime) { if(_isBusy)return; try { var latestVersion = await Client.GetStringAsync(getVersionUrl.Value); if (destroyCancellationToken.IsCancellationRequested) return; var currentVersion = Application.version; OnClientVersionCheck?.Invoke(currentVersion); OnLatestVersionCheck?.Invoke(latestVersion); } catch (OperationCanceledException) { } catch (Exception e) { BIT4Log.LogException(e); } _isBusy = false; } private void Dispose() { checkTick?.Remove(OnTick); downloadRequest?.Abort(); } } }