【MAUI】自动更新功能的安卓App

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

自动更新功能的安卓App

自动更新主要下面4个步骤

1、获取最新版本号
2、提示用户发现更新等待用户确认更新
3、下载最新的apk包
4、安装apk包

更新服务

为简单示例直接在android平台文件夹下新建静态类UpgradeService.cs
在这里插入图片描述
包含

  • 检查更新
  • 下载文件
  • 安装apk包
    因为存在命名空间冲突问题故需改下命名空间。
       public static class UpgradeService 
    {
        readonly static HttpClient _client;

        static UpgradeService()
        {
            _client = new HttpClient();
        }

        public static async Task<Dictionary<string, string>> CheckUpdatesAsync(string url)
        {
            var result = new Dictionary<string, string>();
            // 获取当前版本号
            var currentVersion = VersionTracking.CurrentVersion;

            var latestVersion = await _client.GetStringAsync(url);

            result.Add("CurrentVersion", currentVersion);
            result.Add("LatestVersion", latestVersion);

            return result;
        }
        
        public static void InstallNewVersion()
        {
            var file = $"{FileSystem.AppDataDirectory}/{"com.shez.addressbook-Signed.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(Android.App.Application.Context, "com.shez.addressbook.fileprovider", apkFile);
                // 设置显式 MIME 数据类型
                intent.SetDataAndType(uri, "application/vnd.android.package-archive");
            }
            else
            {
                intent.SetDataAndType(Android.Net.Uri.FromFile(new Java.IO.File(file)), "application/vnd.android.package-archive");
            }
            //指定以新任务的方式启动Activity
            intent.AddFlags(ActivityFlags.NewTask);

            //激活一个新的Activity
            Android.App.Application.Context.StartActivity(intent);
        }  
        public static async Task DownloadFileAsync(string url, Action<long, long> action)
        {
            var req = new HttpRequestMessage(new HttpMethod("GET"), url);
            var response = _client.SendAsync(req, HttpCompletionOption.ResponseHeadersRead).Result;
            var allLength = response.Content.Headers.ContentLength;
            var stream = await response.Content.ReadAsStreamAsync();

            var file = $"{FileSystem.AppDataDirectory}/{"com.shez.addressbook-Signed.apk"}";
            await using var fileStream = new FileStream(file, FileMode.Create);
            fileStream.Flush();
            await using (stream)
            {
                var buffer = new byte[10240];
                var readLength = 0;
                int length;

                while ((length = await stream.ReadAsync(buffer, 0, buffer.Length)) != 0)
                {
                    readLength += length;
                    action(readLength, allLength!.Value);
                    // 写入到文件
                    fileStream.Write(buffer, 0, length);
                }
            }
        }

    }

这里需要使用到 FileProvider在Android 7之后出于安全考虑不再支持content://URL 或file:///URL这种文件访问方式可参考FileProvider | Android Developers我们先添加一下对应配置

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

在这里插入图片描述

<?xml version="1.0" encoding="utf-8"?>
<resources>
	<paths>
		<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>
</resources>

修改Platforms / Android下面的AndroidManifest.xml文件在application下添加provider再添加一个安卓安装的权限“REQUEST_INSTALL_PACKAGES”
通过WebApi请求获取发布的最新版本号。为简单示例,API读取配置文件获取。

<?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.masa.mauidemo.fileprovider"
			android:exported="false"
			android:grantUriPermissions="true">
			<meta-data
				android:name="android.support.FILE_PROVIDER_PATHS"
				android:resource="@xml/provider_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" />
</manifest>

其中com.shez.addressbook-Signed.apk为apk的文件名称。

测试页面:MainPage.xaml

        <HorizontalStackLayout Margin="0,20,0,0" Spacing="10">
            <Button x:Name="UpdateBtn" Margin="20,10" Text="检查更新" VerticalOptions="Fill"  CornerRadius="25" WidthRequest="200" Clicked="OnUpdateClicked" />
        </HorizontalStackLayout>
        <HorizontalStackLayout Margin="0,20,0,0" Spacing="10">
            <Label x:Name="lblCurrentVersion" Margin="20,10"   Text=""  FontSize="16" HorizontalTextAlignment="Center"  />
        </HorizontalStackLayout>
        <HorizontalStackLayout Margin="0,20,0,0" Spacing="10">
            <Label x:Name="lblPross"  Margin="20,10"  Text="" FontSize="16" HorizontalTextAlignment="Center" />
        </HorizontalStackLayout>

cs代码

为简单测试版本Webapi接口直接读取配置文件版本。
直接文本显示百分比和下载字节数。

    public MainPage()
    {
        InitializeComponent();

        lblCurrentVersion.Text ="当前版本"+ VersionTracking.CurrentVersion;
    }

    private async void OnReLoginClicked(object sender, EventArgs e)
    {
        await Shell.Current.GoToAsync("//LoginPage");
    }

    private async void OnExitClicked(object sender, EventArgs e)
    {
        Environment.Exit(0);
    }
    /// <summary>
    /// 更新
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private async void OnUpdateClicked(object sender, EventArgs e)
    {

        var result = await UpgradeService.CheckUpdatesAsync($"{ Operator.BaseUrl}/api/File/AddressBookVer");

        if (result["CurrentVersion"] != result["LatestVersion"])
        {
            var confirm = await Shell.Current.DisplayAlert("问题?", $"检测到新版本是否升级,版本号为" + result["LatestVersion"], "确定", "取消");
            if (confirm)
            {
                await UpgradeService.DownloadFileAsync($"{Operator.BaseUrl}/api/File/AddressBook", DownloadProgressChanged);//https://你的域名/com.masa.mauidemo.apk
                UpgradeService.InstallNewVersion();
                UpdateBtn.IsEnabled = true;
            }
        }
        else
        {
             await Shell.Current.DisplayAlert("提示",$"当前版本已经是最新版,版本号为" + result["LatestVersion"],"确定");
        }

    }
    private void DownloadProgressChanged(long readLength, long allLength)
    {
        UpdateBtn.IsEnabled = false; 
        var c = (int)(readLength * 100 / allLength);

        if (c > 0 && c % 5 == 0) //刷新进度为每5%更新一次过快的刷新会导致页面显示数值与实际不一致
        {

            var BytesReceived = readLength / 1024; //当前已经下载的Kb
            var TotalBytesToReceive = allLength / 1024; //文件总大小Kb
            lblPross.Text =$"正在下载中{c}% {BytesReceived}/{TotalBytesToReceive}...";

            if (c == 100)
            {
                UpdateBtn.IsEnabled = true;
            }
        }
    }

测试

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

参考https://blog.csdn.net/sunday866/article/details/126405322
并得到老师的指导感谢

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: android