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

news2024/11/15 15:59:48

自动更新功能的安卓App

  • 自动更新主要下面4个步骤
    • 更新服务
    • 测试页面:MainPage.xaml
    • 测试

自动更新主要下面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
并得到老师的指导,感谢!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/165870.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Spring资源管理,Spring资源管理源码分析

文章目录一、Java标准资源管理1、Java 标准资源定位2、Java URL 协议扩展基于 java.net.URLStreamHandlerFactory基于 java.net.URLStreamHandler3、Java 标准资源管理扩展的步骤4、Spring为什么不用Java标准的资源管理二、Spring资源接口与实现1、Spring基本资源接口InputStre…

C++ 简单实现RPC网络通讯

RPC是远程调用系统简称&#xff0c;它允许程序调用运行在另一台计算机上的过程&#xff0c;就像调用本地的过程一样。RPC 实现了网络编程的“过程调用”模型&#xff0c;让程序员可以像调用本地函数一样调用远程函数。最近在做的也是远程调用过程&#xff0c;所以通过重新梳理R…

项目管理平台,如何助力CMMI3-5级高效落地?

近日CoCode旗下Co-ProjectV3.0智能项目管理平台全面升级&#xff0c;CoCode产品4大版本全新发布&#xff0c;用户不限版本30天免费试用&#xff1b;平台全面支持CMMI3-5级&#xff0c;助力CMMI高效落地。 一、4大版本全新发布 不限版本30天免费试用 Co-Project V3.0智能项目管理…

FPGA:组合逻辑电路的设计

文章目录组合逻辑电路的设计组合逻辑电路的设计步骤组合逻辑电路的设计举例例1例2组合逻辑电路的设计 根据实际逻辑问题&#xff0c;求出所要求逻辑功能的最简单逻辑电路。 组合逻辑电路的设计步骤 1.逻辑抽象&#xff1a;根据实际逻辑问题的因果关系确定输入、输出变量&…

【寒假每日一题】DAY8 倒置字符串

牛客网链接&#xff1a;传送门 【❤️温馨提示】自己做一遍&#xff0c;再看解析效果更佳哟 描述 将一句话的单词进行倒置&#xff0c;标点不倒置。输入描述&#xff1a; 每个测试输入包含1个测试用例&#xff1a; I like beijing. 输入用例长度不超过100输出描述&#xff1a…

Open3D 点云投影至指定平面(Python版本)

文章目录 一、简介二、实现代码三、实现效果参考资料一、简介 假设给定的平面为 a x + b y + c z + 1 = 0 ax+by+cz+1=0

Python基础(二十四):面向对象核心知识

文章目录 面向对象核心知识 一、面向对象三大特性 1、封装 2、继承 3、多态

音频音量调整中的ramp up down

在日常生活中不管是打电话还是听音乐&#xff0c;都会遇到音量不合适而去调整音量的情况。如果音量调整软件处理不好&#xff0c;就会听到pop noise。产生pop noise的原因是音量直接从当前值骤变到目标值&#xff0c;而不是缓慢的变。如果缓慢的变就不会有pop noise了。图1显示…

select for update是行锁还是表锁,还真得看情况

背景 看到许多写select for update是行锁还是表锁的文章&#xff0c;但每篇文章的结论好像都不太一样。同时&#xff0c;是行锁还是表锁的问题直接影响着系统的性能&#xff0c;所以特意为大家调研一番&#xff0c;也就有了本篇文章&#xff0c;一共为大家汇总验证了20个场景下…

MES系统选型攻略,优秀MES系统应具备哪些性质

在众多MES系统中&#xff0c;企业怎样才能找到最适合自己的产品&#xff1f;那么&#xff0c;一套高质量的MES系统&#xff0c;究竟有什么特点&#xff1f;随着全球经济一体化的发展&#xff0c;中美两国之间的贸易战争日趋白热化&#xff0c;中国作为一个生产大国&#xff0c;…

行为型模式 - 迭代器模式iterator

模式的定义与特点 迭代器模式&#xff08;iterator Pattern&#xff09;&#xff0c;为的提是可以顺序访问一个聚集中的元素而不必暴露聚集的内部表象。多个对象聚在一起形成的总体称之为聚集&#xff0c;聚集对象是能够包容一组对象的容器对象。迭代子模式将迭代逻辑封装到一个…

ffmpeg源码编译vs2013版本

完整版安装ffmpeg 一、安装choco 1.Set-ExecutionPolicy AllSigned 2.Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.N…

链队基本操作(笔记版)

本节主要针对链栈的基本操作进行解析。 # coding:___utf-8___ # author:Guoxuan Sun time:2023/1/12 #链栈的基本操作 #链栈的创建与顺序栈的区别就是每个结点都有一个指针域 #同时链栈也是有两个指针front和rear #链栈中的front指针指向的结点是第一个结点&#xff0c;不是空…

关于MySQL中的存储引擎

存储引擎&#xff1a;&#xff08;了解内容&#xff09; 1、什么是存储引擎&#xff0c;有什么用&#xff1f; 存储引擎是mysql中特有的一个术语&#xff0c;其他数据库中没有。 存储引擎就是一个表存储/组织数据的方式。不同的存储引擎&#xff0c;表存储数据的方式不同。 目前…

基于Androidstudio的宠物交友app

需求信息&#xff1a; 客户端&#xff1a; 1&#xff1a;登录注册&#xff1a;用户可以通过自己的信息进行账号的注册 2&#xff1a;宠物信息&#xff1a;列表显示发布的宠物想&#xff0c;可以通过条件对宠物信息进行筛选&#xff0c;以及沟通意向点亮 3&#xff1a;宠物圈&am…

java调用python文件的几种方式

java调用python的契机来自于一个项目需要用到算法&#xff0c;但是算法工程师们写的python&#xff0c;于是就有了java后端调用python脚本的需求&#xff0c;中间遇到了许多问题&#xff0c;特此记录整理了一次。1、java调用python的方式有哪几种1.1 方法一&#xff1a;jpython…

选择排序.

一、简单选择排序 void select_sort(int a[], int len){ //len为数组长度for (int i 0; i < len-1; i){//n个数需要比较n-1趟int min i;//记录最小值的位置for (int j i1; j < len-1; j){if (a[j] < a[min]) min j;//更新最小值的位置} if (min ! i) swap(a[i], …

vue3 项目篇商场 之 初始化项目

目录vue3 项目篇商场 之 初始化项目1&#xff1a;安装 rem 适配src 同级目录下创建 postcss.config.jsmain.ts2 :使用字体图标加字体图标 &#xff08; Symbol 这个选项&#xff09;public / index.html使用效果3 sass4&#xff1a;vant3引入 按需引入 ( 非 vite )4-1 babel.co…

2022年,开源社最亮的星

开源社成立于 2014 年&#xff0c;是由志愿贡献于开源事业的个人成员&#xff0c;依 “贡献、共识、共治” 原则所组成&#xff0c;始终维持厂商中立、公益、非营利的特点&#xff0c;是最早以 “开源治理、国际接轨、社区发展、开源项目” 为使命的开源社区联合体。本次年度评…

常用的专业数据恢复软件有哪些?恢复数据就看这10个!

互联网时代&#xff0c;我们都习惯使用电脑来进行办公&#xff0c;电脑里面都保存着我们很多数据。数据的日积月累&#xff0c;会导致电脑的运行速度减缓&#xff0c;为此我们都会定期对电脑进行清理。 如果在清理过程中&#xff0c;不小心误删或者格式化了数据&#xff0c;有…