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

需求

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

功能实现

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

  • file_paths.xml
  • AndroidMainfest.xml

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">
		<provider
			android:name="androidx.core.content.FileProvider"
			android:authorities="com.companyname.mauiupdateapp.fileprovider"
			android:exported="false"
			android:grantUriPermissions="true">
			<meta-data
				android: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事件实现软件安装。

复制代码
<Button
    x:Name="UpdateBtn"
    Clicked="OnCheckUpdateClicked"
    HorizontalOptions="Fill"
    Text="安装Apk" />

按钮事件实现:

csharp 复制代码
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;
	}
}

更新服务实现:

csharp 复制代码
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 ANDROID
        return new MauiUpdateApp.Platforms.Android.UpdateHandler();
#else
        return new DefaultUpdateHandler();
#endif
    }
}

public class DefaultUpdateHandler : IUpdateHandler
{
    public async Task InstallUpdateAsync()
    {
        // 默认实现,非 Android 平台使用
        if (App.Current?.MainPage != null)
        {
            await App.Current.MainPage.DisplayAlertAsync("更新", "此平台不支持自动更新", "确定");
        }
    }
}

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

csharp 复制代码
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;
            }

            // 安装 APK
            InstallApk(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

相关推荐
芝麻科技4 天前
【翻译】MAUI 的.NET 11预览版:使用内联C#表达式简化XAML
maui
芝麻科技2 个月前
MAUI库推荐三:Syncfusion.Maui.Toolkit
maui
芝麻科技2 个月前
MAUI库推荐二:MPowerKit
maui
LateFrames4 个月前
以小白视角尝试 WPF / WinUI3 / MAUI / MAUI Blazor 构建 Windows 桌面程序
windows·wpf·maui·mauiblazor·winui3
绿荫阿广5 个月前
用纯.NET开发并制作一个智能桌面机器人(六):使用.NET开发一个跨平台功能完善的小智AI客户端
c#·.net·asp.net core·maui·winui
yuanpan6 个月前
认识跨平台UI框架Flutter和MAUI区别,如何选。
flutter·ui·maui
绿荫阿广7 个月前
记一次.NET MAUI项目中绑定Android库实现硬件控制的开发经历
.net·maui
初级代码游戏8 个月前
Maui劝退:用windows直接真机调试iOS,无须和Mac配对
macos·ios·配置·maui·热重载
初级代码游戏9 个月前
Xamarin劝退之踩坑笔记
笔记·maui·xamarin