当前位置: 首页 > news >正文

Android 平台 MAUI 应用更新服务

该代码是面向 Android 平台 的 MAUI(.NET Multi-platform App UI)应用更新服务实现,实现了IUpgradeService接口,核心功能涵盖版本检查、APK 下载与安装,整体设计兼顾异常处理、用户体验与 Android 版本兼容性。

一、添加 IUpgradeService.cs 接口

/// <summary>/// 升级服务接口类/// </summary>public interface IUpgradeService{/// <summary>/// 检查更新/// </summary>/// <param name="latestVersion">最新版本</param>/// <returns></returns>bool CheckUpdatesAsync(string latestVersion);/// <summary>/// 下载安装文件/// </summary>/// <param name="url">下载URL</param>/// <param name="action">进度条处理方法</param>/// <returns></returns>Task DownloadFileAsync(string url, Action<long, long> action, CancellationToken cancellationToken = default);/// <summary>/// 安装APK的方法/// </summary>void InstallNewVersion();}

二、在 Platforms/Android 目录下创建 UpgradeService.cs 文件,实现 IUpgradeService 接口

 public class UpgradeService : IUpgradeService{readonly HttpClient _client;public UpgradeService(){_client = new HttpClient();}/// <summary>/// 检查当前应用版本是否需要更新/// </summary>/// <param name="latestVersion">服务器提供的最新版本号字符串(如 "1.2.3")</param>/// <returns>true表示需要更新,false表示不需要或版本相同</returns>public bool CheckUpdatesAsync(string latestVersion){try{// 获取当前版本(MAUI 6+ 推荐方式)var currentVersionStr = VersionTracking.Default.CurrentVersion;// 使用Version类进行专业比较var current = ParseVersion(currentVersionStr);var latest = ParseVersion(latestVersion);return latest > current;}catch{// 出现任何异常时保守返回true(建议更新)return true;}}/// <summary>/// 安全解析版本字符串(支持不同长度和格式)/// </summary>private Version ParseVersion(string versionStr){// 处理可能的null/emptyif (string.IsNullOrWhiteSpace(versionStr))return new Version(0, 0);// 分割版本号组成部分var parts = versionStr.Split('.').Select(p => int.TryParse(p, out int num) ? num : 0).ToArray();// 根据长度创建Version对象return parts.Length switch{1 => new Version(parts[0], 0),2 => new Version(parts[0], parts[1]),3 => new Version(parts[0], parts[1], parts[2]),4 => new Version(parts[0], parts[1], parts[2], parts[3]),_ => new Version(0, 0)};}/// <summary>/// 下载并安装APK/// </summary>/// <param name="url"></param>/// <param name="progressAction"></param>/// <param name="cancellationToken"></param>/// <returns></returns>/// <exception cref="ArgumentNullException"></exception>public async Task DownloadFileAsync(string url, Action<long, long> progressAction, CancellationToken cancellationToken = default){// 验证输入参数if (string.IsNullOrEmpty(url))throw new ArgumentNullException(nameof(url));if (progressAction == null)throw new ArgumentNullException(nameof(progressAction));// 生成唯一的临时文件名,避免冲突var fileName = "com.jiajing.iotplatform.apk";var tempFilePath = Path.Combine(FileSystem.AppDataDirectory, $"{fileName}.tmp");var finalFilePath = Path.Combine(FileSystem.AppDataDirectory, fileName);try{// 使用using确保HttpClient正确释放(如果不是全局单例的话)using var request = new HttpRequestMessage(HttpMethod.Get, url);// 异步获取响应,支持取消操作using var response = await _client.SendAsync(request,HttpCompletionOption.ResponseHeadersRead,cancellationToken);// 确保请求成功response.EnsureSuccessStatusCode();// 获取文件总大小,处理可能为null的情况var totalLength = response.Content.Headers.ContentLength ?? -1;var downloadedLength = 0L;// 读取响应流并写入文件using var stream = await response.Content.ReadAsStreamAsync(cancellationToken);await using var fileStream = new FileStream(tempFilePath, FileMode.Create, FileAccess.Write, FileShare.None, 8192, true);var buffer = new byte[8192]; // 使用8KB缓冲区(更适合大多数场景)int bytesRead;// 循环读取流,支持取消操作while ((bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length, cancellationToken).ConfigureAwait(false)) > 0){// 写入文件await fileStream.WriteAsync(buffer, 0, bytesRead, cancellationToken).ConfigureAwait(false);// 更新进度downloadedLength += bytesRead;progressAction(downloadedLength, totalLength);}// 确保所有数据都写入磁盘await fileStream.FlushAsync(cancellationToken).ConfigureAwait(false);// 下载完成后重命名临时文件(避免部分下载的文件被误认)if (File.Exists(finalFilePath))File.Delete(finalFilePath);File.Move(tempFilePath, finalFilePath);}catch (Exception){// 处理其他异常if (File.Exists(tempFilePath))File.Delete(tempFilePath);throw;}}/// <summary>/// 安装新版本/// </summary>public void InstallNewVersion(){var file = $"{FileSystem.AppDataDirectory}/{"com.jiajing.iotplatform.apk"}";var apkFile = new Java.IO.File(file);var intent = new Intent(Intent.ActionView);// 判断Android版本if (Build.VERSION.SdkInt >= BuildVersionCodes.N){//给临时读取权限intent.SetFlags(ActivityFlags.GrantReadUriPermission);var uri = FileProvider.GetUriForFile(AndroidApp.Application.Context, "com.jiajing.iotplatform.fileprovider", apkFile);// 设置显式 MIME 数据类型intent.SetDataAndType(uri, "application/vnd.android.package-archive");}else{intent.SetDataAndType(AndroidNet.Uri.FromFile(new Java.IO.File(file)), "application/vnd.android.package-archive");}//指定以新任务的方式启动Activityintent.AddFlags(ActivityFlags.NewTask);//激活一个新的ActivityAndroidApp.Application.Context.StartActivity(intent);}}

三、修改 MauiProgram.cs 文件,注册升级服务

#if ANDROID 是必不可少的,该条件编译指令能确保相关逻辑只在 Android 环境中执行.

    
public static class MauiProgram
{public static MauiApp CreateMauiApp(){ #if ANDROID    // Android 添加自定义升级服务builder.Services.AddSingleton<IUpgradeService, Platforms.Android.UpgradeService>();#endif } 
}

四、添加检查更新方法

Razor页面
    <!--版本更新弹框--><Modal Title="检测到新版本,是否更新?"@bind-Visible="@UpdateConfirm"Closable="false"Centered="true"OnOk="@OnConfirmUpdateAsync"><Space>【版本】: V @AppVersion.Version</Space><Space>【内容】:@AppVersion.ReleaseNotes</Space></Modal><!--下载进度弹框--><Modal Title="正在更新,请稍后..."@bind-Visible="@UpdateDialog"Closable="false" MaskClosable="false"Centered="true"Footer=null><Space>下载进度: @BytesReceived KB / @TotalBytesToReceive KB </Space><AntDesign.Progress StrokeWidth="20" Percent="@Percent" /></Modal>
Razor页面
/// <summary>
/// 最新版本信息
/// </summary>
public AppVersionInfo AppVersion = new();/// <summary>
/// 进度百分比
/// </summary>
public int Percent { get; set; }/// <summary>
/// 总字节数
/// </summary>
public long TotalBytesToReceive { get; set; }/// <summary>
///  已下载字节数
/// </summary>
public long BytesReceived { get; set; }/// <summary>
/// 是否显示进度框
/// </summary>
public bool UpdateDialog;/// <summary>
/// 升级提示并确认框
/// </summary>
public bool UpdateConfirm;/// <summary>
/// 检查是否软件是否为最新版本
/// </summary>
/// <returns></returns>
public async Task GetVersionNew()
{try{// 数据服务:调用编辑服务var response = await VersionService.GetVersionAsync();if (response != null && response.Code == ApiCode.Success){AppVersion = response.Data;// 检查是否为最新版本,非最新版本则提示更新if (UpgradeService.CheckUpdatesAsync(AppVersion.Version)){UpdateConfirm = true;}}}catch (Exception e){await dialogService.ErrorSnackbarAsync($"读取最新版本报错:{e.Message}");}
}/// <summary>
/// 下载新版本并安装
/// </summary>
/// <returns></returns>
public async Task OnConfirmUpdateAsync()
{try{// 启动版本升级 UpdateDialog = true;// 下载文件await UpgradeService.DownloadFileAsync(AppVersion.DownloadUrl, DownloadProgressChanged);// 安装新版本UpgradeService.InstallNewVersion();}catch (Exception e){await dialogService.ErrorSnackbarAsync($"下载新版本及安装时报错:{e.Message}");}finally{UpdateDialog = false;}
}/// <summary>
/// 下载进度
/// </summary>
/// <param name="readLength"></param>
/// <param name="allLength"></param>
private void DownloadProgressChanged(long readLength, long allLength)
{InvokeAsync(() =>{var c = (int)(readLength * 100 / allLength);// 刷新进度为每5%更新一次if (c > 0 && c % 5 == 0){Percent = c; //下载完成百分比BytesReceived = readLength / 1024; //当前已经下载的KbTotalBytesToReceive = allLength / 1024; //文件总大小KbStateHasChanged();}});
}#endregion

五、效果图

image image

http://www.rkmt.cn/news/8017.html

相关文章:

  • SQL脚本:查询指定SQL的统计信息(cursor,awr)
  • 本地(或自下载)浏览器插件 安装指南
  • 路由查看命令
  • Linux 基础命令01
  • 面向多模态检索的向量数据库对比分析和技术选型:Elasticsearch、Milvus、Pinecone、FAISS、Chroma、PGVector、Weaviate、Qdrant
  • 终结AI幻觉:Amazon Bedrock如何用形式化方法重塑可信AI
  • 技术解读 | OceanBase 数据库诊断与调优的关键技术与方法
  • 我代表编程导航,向大家道歉!
  • cf div2 1051 E(视角转换,构造+思维)
  • openHarmony之开源三方库zlib适配讲解 - 实践
  • phoenix 导出sql执行结果到文件中
  • LK32V12A 过压/过流保护开关芯片 OVP过压45V 过流2.2A电流 SOT-23L
  • 深入解析:HTML元素周期表
  • APP 内测分发的核心逻辑与流程,虾分发让效率翻倍
  • 深入解析:【vue+exceljs+file-saver】纯前端:下载excel和上传解析excel
  • 解码C语言关键字
  • Windows环境中安装Zookeeper
  • ​​电流探头选型技术指南:精准捕获电流信号的艺术​​
  • slurm启动验证命令
  • 实用指南:LeetCode //C - 836. Rectangle Overlap
  • 深入解析:[Android] 安卓手机翻页时钟Flip Clock - World Clock v1.5.0.0
  • 深入解析:多模态大模型3:TAViS
  • 基于STM32F103C8T6与DS18B20的温度测量系统
  • Oxygen Forensic Detective 18.0 发布,新增功能简介
  • Windows如何美化cmd窗口
  • MX Round 7 解题报告
  • 实用指南:售价3499美元,英伟达Jetson Thor实现机器人与物理世界的实时智能交互
  • 逻辑回归 vs 支持向量机 vs 随机森林:哪个更适合小数据集? - 指南
  • 券多多系统-开发记录
  • US$189 Yanhua Mini ACDP Module3 Read amp; Write BMW DME ISN Code by OBD