BITKit/Src/Unity/Scripts/Application/ApplicationService.cs

208 lines
5.9 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Security;
using System.Threading;
using BITKit.Apps;
using BITKit.HttpNet;
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<string> OnClientVersionCheck
{
add => ApplicationService.OnClientVersionCheck += value;
remove => ApplicationService.OnClientVersionCheck -= value;
}
public event Action<string> OnLatestVersionCheck
{
add => ApplicationService.OnLatestVersionCheck += value;
remove => ApplicationService.OnLatestVersionCheck -= value;
}
public event Action<string> OnDownloadLatest
{
add => ApplicationService.OnDownloadLatest += value;
remove => ApplicationService.OnDownloadLatest -= value;
}
public event Action<float> OnDownloadProgress
{
add => ApplicationService.OnDownloadProgress += value;
remove => ApplicationService.OnDownloadProgress -= value;
}
public event Action<string> OnDownloadComplete
{
add => ApplicationService.OnDownloadComplete += value;
remove => ApplicationService.OnDownloadComplete -= value;
}
public event Action OnDetectedLatestVersion;
public UniTask<string> DownloadLatestVersionAsync()
{
return _applicationServiceImplementation.DownloadLatestVersionAsync();
}
public string DownloadLatestUrl => _applicationServiceImplementation.DownloadLatestUrl;
public string CheckLatestVersionUrl => _applicationServiceImplementation.CheckLatestVersionUrl;
}
/// <summary>
/// 用于Unity的应用程序服务,详细功能请查看<see cref="IApplicationService"/>
/// </summary>
public class ApplicationService : MonoBehaviour,IApplicationService
{
public static event Action<string> OnClientVersionCheck;
public static event Action<string> OnLatestVersionCheck;
public static event Action<string> OnDownloadLatest;
public static event Action<float> OnDownloadProgress;
public static event Action<string> OnDownloadComplete;
internal static IApplicationService Singleton { get; private set; }
[SerializeField, SerializeReference, SubclassSelector]
private IReference getVersionUrl;
[SerializeField, SerializeReference, SubclassSelector]
private IReference getLatestUrl;
[SerializeField, SerializeReference, SubclassSelector]
private WebProvider webProvider;
[SerializeReference, SubclassSelector] private ITicker checkTick;
[SerializeField] private bool dontDestroyOnLoad;
event Action<string> IApplicationService.OnClientVersionCheck
{
add => OnClientVersionCheck += value;
remove => OnClientVersionCheck -= value;
}
event Action<string> IApplicationService.OnLatestVersionCheck
{
add => OnLatestVersionCheck += value;
remove => OnLatestVersionCheck -= value;
}
event Action<string> IApplicationService.OnDownloadLatest
{
add => OnDownloadLatest += value;
remove => OnDownloadLatest -= value;
}
event Action<float> IApplicationService.OnDownloadProgress
{
add => OnDownloadProgress += value;
remove => OnDownloadProgress -= value;
}
event Action<string> 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<string> 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<ApplicationService>($"开始下载最新版本,下载地址:{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 webProvider.GetAsync(getVersionUrl.Get(), destroyCancellationToken);
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();
}
}
}