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

MAUI项目在Android平台通过U盘实现软件更新

需求

项目使用MAUI开发的用Android工控机进行相关功能的实现。作为操作设备的屏幕嵌入到仪器中,要使用串口操作实现对仪器的控制。想要实现在有软件更新时,可以通过U盘实现对软件的升级。

功能实现

这里需要使用到 FileProvider,在Android 7之后出于安全考虑不再支持content://URL 或file:///URL这种文件访问方式。在Platforms/Android中主要添加/修改下面两个文件:

  • file_paths.xml
  • AndroidMainfest.xml

image

Platforms/Android/Resources下面新建xml文件夹,并添加 provider_paths.xml文件。

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android"><root-path name="root" path="" /><files-path name="files" path="" /><cache-path name="cache" path="" /><external-path name="camera_photos" path="" /><external-files-path name="external_file_path" path="" /><external-cache-path name="external_cache_path" path="" />
</paths>

修改Platforms/Android下面的AndroidManifest.xml文件,在application下添加provider,再添加一个安卓安装的权限

  • REQUEST_INSTALL_PACKAGES(安装应用)
  • WRITE_EXTERNAL_STORAGE(写入外部存储中的文件)
  • READ_EXTERNAL_STORAGE(读取外部存储中的文件)

AndroidManifest.xml文件内容如下:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"><application android:allowBackup="true" android:icon="@mipmap/appicon" android:roundIcon="@mipmap/appicon_round" android:supportsRtl="true"><providerandroid:name="androidx.core.content.FileProvider"android:authorities="com.companyname.mauiupdateapp.fileprovider"android:exported="false"android:grantUriPermissions="true"><meta-dataandroid:name="android.support.FILE_PROVIDER_PATHS"android:resource="@xml/file_paths" /></provider></application><uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /><uses-permission android:name="android.permission.INTERNET" /><uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" /><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"  /><uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"  /><uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
</manifest>

在MainPage页面添加一个按钮用于实现软件安装功能,简化了项目实现,没有采用MVVM模式,直接通过Clicked事件实现软件安装。

<Buttonx:Name="UpdateBtn"Clicked="OnCheckUpdateClicked"HorizontalOptions="Fill"Text="安装Apk" />

按钮事件实现:

private async void OnCheckUpdateClicked(object? sender, EventArgs e)
{await CheckForUpdates();
}private async Task CheckForUpdates()
{try{UpdateBtn.IsEnabled = false;await _updateService.InstallUpdateAsync();}catch (Exception ex){await DisplayAlertAsync("错误", $"异常: {ex.Message}", "确定");}finally{UpdateBtn.IsEnabled = true;}
}

更新服务实现:

public class UpdateService
{public async Task InstallUpdateAsync(){// 调用平台特定的更新逻辑await UpdateHandlerFactory.Create().InstallUpdateAsync();}
}public interface IUpdateHandler
{Task InstallUpdateAsync();
}public static class UpdateHandlerFactory
{public static IUpdateHandler Create(){
#if ANDROIDreturn new MauiUpdateApp.Platforms.Android.UpdateHandler();
#elsereturn new DefaultUpdateHandler();
#endif}
}public class DefaultUpdateHandler : IUpdateHandler
{public async Task InstallUpdateAsync(){// 默认实现,非 Android 平台使用if (App.Current?.MainPage != null){await App.Current.MainPage.DisplayAlertAsync("更新", "此平台不支持自动更新", "确定");}}
}

实现Android平台的安装Apk功能:

using Android.Content;
using MauiUpdateApp.Services;
using Android.App;
namespace MauiUpdateApp.Platforms.Android;
public class UpdateHandler : IUpdateHandler
{private static readonly HttpClient client = new HttpClient();public async Task InstallUpdateAsync(){try{var activity = Platform.CurrentActivity;if (activity == null){if (App.Current?.MainPage != null){await App.Current.MainPage.DisplayAlertAsync("错误", "无法获取当前活动", "确定");}return;}PickOptions options = new() { PickerTitle = "Please select a comic file", };var results = await FilePicker.Default.PickAsync(options);if (results is null){return;}// 安装 APKInstallApk(results.FullPath, activity);}catch (Exception ex){// 处理错误Console.WriteLine($"更新失败: {ex.Message}");if (App.Current?.MainPage != null){await App.Current.MainPage.DisplayAlertAsync("错误", $"更新失败: {ex.Message}", "确定");}}}private static void InstallApk(string apkPath, Activity? activity){var file = new Java.IO.File(apkPath);var uri = AndroidX.Core.Content.FileProvider.GetUriForFile(activity, $"{activity.PackageName}.fileprovider", file);var intent = new Intent(Intent.ActionView);intent.SetDataAndType(uri, "application/vnd.android.package-archive");intent.AddFlags(ActivityFlags.GrantReadUriPermission);intent.AddFlags(ActivityFlags.NewTask);activity.StartActivity(intent);}
}

以上为整个项目实现安装Apk的代码,想要获取源码的话,可以从
https://github.com/mzy666888/MauiUpdateApp中获取,欢迎给个Star

参考:https://www.cnblogs.com/MASA/p/16612541.html

http://www.jsqmd.com/news/440485/

相关文章:

  • Flutter 三方库 cryptography_plus 的鸿蒙化适配指南 - 掌控高保真加密协议、安全脱敏实战、鸿蒙级精密防御专家
  • 省选前突击Linux
  • AI Agent框架探秘:拆解 OpenHands(11)--- Runtime主要组件
  • QPSK调制在AWGN和Rayleigh信道下的误码率和误比特率性能对比(源码+lw+部署文档+讲解等)
  • 深入解析:Linux网络---网络层
  • B4451 [GESP202512 四级] 建造
  • day1-5德语英语b2
  • 逆向工程与二次开发:从一个 Java 大作业项目的改造之旅
  • 基于Simulink模块搭建下4-DPSK通过AWGN下的误码率和误比特率仿真(源码+lw+部署文档+讲解等)
  • 提示工程架构师的AI上下文工程长短期记忆机制设计秘籍大公开
  • 对使用的屏幕的整理
  • 多径衰落信道下OFDM传输信道估计算法误码率比较(源码+lw+部署文档+讲解等)
  • 搜维尔科技:Manus数据手套登录人工智能大会-构建下一代远程操控基础
  • ollama本地模型使用
  • 探索大数据领域数据产品的发展前景
  • BISHI92 【模板】前缀函数(kmp)
  • 2026年角钢厂家实力推荐榜:镀锌角钢/S355J0/AH36/Q355B/5#角钢/S275/Q420/电钢角钢/欧标日标角钢,精选源头工厂,坚固耐用的结构之选! - 品牌企业推荐师(官方)
  • 2024智能家居Agentic AI技术白皮书解读:提示工程架构师划重点
  • 告别“美丽刑具”!2026职场女性“久穿不累”高跟鞋选购全攻略 - 数字营销分析
  • 虚拟环境工具下创建独立的 3.11 环境 - yi
  • 旺旺的零食健康吗?从爱至尊、Want Power、FixXBody,看旺旺如何布局“更轻负担”零食 - Top品牌推荐官
  • jenkins对接gitlab
  • Flutter 三方库 vane 的鸿蒙化适配指南 - 构建工业级 Dart 服务端、中间件驱动的高性能 API、鸿蒙全栈开发实战
  • 阿里oceanbase-ce:纯纯手工创建实例、初始化 ...
  • C#静态构造函数真的总是最先执行吗?
  • 每日一题:什么是限流?.NET 中如何实现?
  • 前后端交互中时间的格式化与解析,将会面临哪些问题?
  • yolo go onnx
  • 2026.3.5总结 安装claude code 并在vscode上调用
  • gcsfuse中的锁与偏序理论