.net开发安卓入门-自动升级(配合.net6 webapi 作为服务端)

news2025/1/13 3:37:09

文章目录

  • 思路
  • 客户端
    • 权限清单(AndroidManifest.xml)
      • 权限列表(完整内容看 权限清单(AndroidManifest.xml))
      • 打开外部应用的权限(完整内容看 权限清单(AndroidManifest.xml))
    • 添加文件如下图
      • provider_paths.xml内容
    • 升级类库代码
      • 调用代码
      • 事件回调
    • 注意:这里是安卓11,因为是已经确定版本了,所以没做判断,正确做法应该如下
  • 服务端接口
    • 注意事项:在iis中或者.netcore中下载apk配置方式不一样
  • 完整代码

思路

  • 服务端提供版本信息和apk下载地址
  • 客户端通过对比版本进行文件下载安装升级

客户端

权限清单(AndroidManifest.xml)

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0.2" package="com.companyname.boshiac.forklift.app" android:installLocation="auto">
	<uses-sdk android:minSdkVersion="29" android:targetSdkVersion="33" />
	<application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme" android:usesCleartextTraffic="true">
		<provider android:name="androidx.core.content.FileProvider" android:authorities="com.companyname.boshiac.forklift.app.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.READ_EXTERNAL_STORAGE" />
	<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
	<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
	<uses-permission android:name="android.permission.RECORD_AUDIO" />
	<uses-permission android:name="android.permission.CAPTURE_AUDIO_OUTPUT" />
	<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
	<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
	<uses-permission android:name="android.permission.DELETE_CACHE_FILES" />
	<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
	<uses-permission android:name="android.permission.INTERNET" />
</manifest>

权限列表(完整内容看 权限清单(AndroidManifest.xml))

安装权限、文件读写权限等都是必要的权限

	<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
	<uses-permission android:name="android.permission.INTERNET" />
	<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
	<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
	<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

打开外部应用的权限(完整内容看 权限清单(AndroidManifest.xml))

在application节点中加入下面代码

<provider android:name="androidx.core.content.FileProvider" android:authorities="com.companyname.boshiac.forklift.app.fileprovider" android:exported="false" android:grantUriPermissions="true">
			<meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/provider_paths" />
		</provider>

添加文件如下图

在这里插入图片描述

provider_paths.xml内容

根据自己的权限需要开放对应的目录权限就可以了

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
  <!--1、对应内部内存卡根目录:Context.getFileDir()-->
  <files-path
      name="int_root"
      path="/" />
  <!--2、对应应用默认缓存根目录:Context.getCacheDir()-->
  <cache-path
      name="app_cache"
      path="/" />
  <!--3、对应外部内存卡根目录:Environment.getExternalStorageDirectory()-->
  <external-path
      name="ext_root"
      path="pictures/" />
  <!--4、对应外部内存卡根目录下的APP公共目录:Context.getExternalFileDir(String)-->
  <external-files-path
      name="ext_pub"
      path="/" />
  <!--5、对应外部内存卡根目录下的APP缓存目录:Context.getExternalCacheDir()-->
  <external-cache-path
      name="ext_cache"
      path="/" />

</paths>

升级类库代码

using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;

namespace BOSHIAC.Forklift.App
{
    internal class UpgradeService
    {
        private string apkUrl;
        private string versionUrl;
        private string version;

        /// <summary>
        /// 更新了
        /// </summary>
        public event Action<string> UpgradeEvent;

        public UpgradeService(string versionUrl, string apkUrl, string currentVersion)
        {
            this.versionUrl = versionUrl;
            this.apkUrl = apkUrl;
            version = currentVersion;
        }

        public void Start()
        {

            Task.Run(async () =>
            {
                var client = new HttpClient();
                while (true)
                {
                    try
                    {
                        var response = await client.GetAsync(versionUrl);
                        var hostVersion = response.Content.ReadAsStringAsync().Result;
                        if (hostVersion != version)
                        {
                            using (var stream = client.GetStreamAsync(apkUrl).Result)
                            {
                                var downloaddir = Application.Context.GetExternalFilesDir(Android.OS.Environment.DirectoryDownloads).AbsolutePath;
                                var fileName = Path.Combine(downloaddir, "forklift.apk");
                                if (File.Exists(fileName))
                                    File.Delete(fileName);
                                using (var fs = new FileStream(fileName, FileMode.CreateNew))
                                {
                                    stream.CopyTo(fs);
                                    fs.Flush();
                                    UpgradeEvent?.Invoke(fileName);
                                    return;
                                }
                            }
                        }
                    }
                    catch (Exception ex)
                    {

                        throw;
                    }
                    finally
                    {
                        Task.Delay(TimeSpan.FromSeconds(30)).Wait();
                    }


                }
            });
        }
    }
}

调用代码

 UpgradeService service = new UpgradeService("http://192.168.69.82/api/Upgrade/Version"
                , "http://192.168.69.82/apks/forklift.apk"
                , this.PackageManager.GetPackageInfo(this.PackageName, 0).VersionName);
            service.UpgradeEvent += Service_UpgradeEvent;
            service.Start();

事件回调

  private void Service_UpgradeEvent(string file)
        {
            this.RunOnUiThread(() =>
            {
               // var f = this.PackageManager.CanRequestPackageInstalls();//  this.GetPackageManager().canRequestPackageInstalls();
                var alertDialog = new Android.App.AlertDialog.Builder(this)
                      .SetTitle("升级提示")
                      .SetMessage("检测到新的版本,必须升级哦!")
                .SetIcon(Resource.Mipmap.ic_launcher)
                .SetPositiveButton("升级", (des, dee) =>
                {
                    try
                    {
                        Intent install = new Intent(Intent.ActionView);
                        Java.IO.File fileName = new Java.IO.File(file);
                        Android.Net.Uri uri = FileProvider.GetUriForFile(Android.App.Application.Context, "com.companyname.boshiac.forklift.app.fileprovider", fileName) ;
                        //打开新版本应用的 
                        install.SetFlags(ActivityFlags.NewTask);
                        install.SetFlags(ActivityFlags.GrantReadUriPermission);
                        install.SetDataAndType(uri, "application/vnd.android.package-archive");// "application/vnd.android.package-archive"
                        StartActivity(install);
                    }
                    catch (System.Exception ex)
                    {

                        ;
                    }
                   
                })
                .SetCancelable(false)
                .Create();

                alertDialog.Show();
            });
        }

注意:这里是安卓11,因为是已经确定版本了,所以没做判断,正确做法应该如下

  Intent i = new Intent(Intent.ActionView);
                var saveFolder = Android.OS.Environment.ExternalStorageDirectory;
                var file = string.Format("{0}/{1}{2}", saveFolder, this.PackageName, ".apk");
                Java.IO.File apkFile = new Java.IO.File(file);
                Intent intent = new Intent(Intent.ActionView);
                intent.SetFlags(ActivityFlags.NewTask);
                if (Build.VERSION.SdkInt >= BuildVersionCodes.N)
                {
                    intent.SetFlags(ActivityFlags.GrantReadUriPermission);
 
                    Android.Net.Uri uri = FileProvider.GetUriForFile(this, PackageName + ".fileprovider", apkFile);
                    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");
                }
                StartActivity(intent);

https://blog.csdn.net/qq_38977099/article/details/119115061

服务端接口

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System.IO;

namespace Boshi_HaiNan_Pda.WebApi.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class UpgradeController : ControllerBase
    {
        private IWebHostEnvironment environment;
        private string versionJsonPath;
        public UpgradeController(IWebHostEnvironment hostingEnvironment)
        {
            environment = hostingEnvironment;
            var dir = System.IO.Path.Combine(environment.WebRootPath, "apks\\");
            if (!Directory.Exists(dir)) Directory.CreateDirectory(dir);
            versionJsonPath = System.IO.Path.Combine(dir, "version.json"); 
        }

        [HttpGet("Version")]
        public string GetVersion()
        {
            if (!System.IO.File.Exists(versionJsonPath))
                return "0.0.0";
            return System.IO.File.ReadAllText(versionJsonPath).ToLower();
        } 
    }
}

注意事项:在iis中或者.netcore中下载apk配置方式不一样

在iis中配置网络上有很多文章,都是配置mime,”application/vnd.android.package-archive“ 这个是没有问题的,如下配置
在这里插入图片描述

在.netcore中需要做如下配置
program.cs 或者startup文件中增加如下代码

 app.UseStaticFiles(new StaticFileOptions
            {
                //FileProvider = new PhysicalFileProvider(Directory.GetCurrentDirectory()),
                //设置不限制content-type 该设置可以下载所有类型的文件,但是不建议这么设置,因为不安全
                //下面设置可以下载apk和nupkg类型的文件
                ContentTypeProvider = new FileExtensionContentTypeProvider(new Dictionary<string, string>
                {
                      { ".apk", "application/vnd.android.package-archive" }
                })
            }).UseStaticFiles();

完整代码

https://download.csdn.net/download/iml6yu/87463366

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

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

相关文章

网络数据包接收流程

1. 网络数据包接收流程简述 典型的以太网卡网络包接收流程如下&#xff1a; 1.网络包通过物理介质传到接收端的phy芯片&#xff1b; 2.phy芯片通过RGMII协议传到MAC芯片rx queue fifo中&#xff1b; 3.MAC芯片通过专用DMA将网络包搬运到网卡驱动程序预先分配好的rx ringbuffer中…

【多线程与高并发】- synchronized锁的认知

synchronized锁的认知 &#x1f604;生命不息&#xff0c;写作不止 &#x1f525; 继续踏上学习之路&#xff0c;学之分享笔记 &#x1f44a; 总有一天我也能像各位大佬一样 &#x1f3c6; 一个有梦有戏的人 怒放吧德德 &#x1f31d;分享学习心得&#xff0c;欢迎指正&#xf…

言简意赅+图解 函数传参问题(传值、传地址 500字解决战斗)

1、传值 2、传地址 不论是传值&#xff0c;还是传地址&#xff0c;形参都是对于实参的一份拷贝 下图为按值传递进行交换&#xff1a; 形参left拷贝一块新空间&#xff0c;形参right拷贝一块新空间 下图为按指针传递进行交换 形参left拷贝一块新的空间&#xff0c;形参right…

研究生薪资管理系统-课后程序(JAVA基础案例教程-黑马程序员编著-第四章-课后作业)

【案例4-5】研究生薪资管理系统 【案例介绍】 案例描述 在学校中&#xff0c;学生每个月需要交相应的生活费&#xff0c;老师每个月有相应的工资&#xff0c;而在职研究生既是老师又是学生&#xff0c;所以在职研究生既需要交学费又会有工资。下面要求编写一个程序来统计在职…

最完整的小红书带货笔记——垂直模式

最完整的小红书带货笔记——垂直模式&#xff0c;小红书直播复盘怎么做&#xff1f;#直播带货笔记 第1篇&#xff0c;带你解锁直播复盘5大要点&#xff01; #小红书店铺#小红书运营 小红书怎么发带货笔记&#xff1f; 做小红书带货的同学注意了&#xff0c;我们带货一定要发笔…

看见统计——第三章 概率分布

看见统计——第三章 概率分布 参考 https://github.com/seeingtheory/Seeing-Theory中心极限定理 概率分布描述了随机变量取值的规律。 随机变量Random Variables &#x1f525; 定义&#xff1a;将样本空间中的结果映射到实数的函数 XXX 称为随机变量(random variable)&a…

【算法基础】链表

一、单链表例题&#xff1a;实现一个单链表&#xff0c;链表初始为空&#xff0c;支持三种操作&#xff1a;向链表头插入一个数&#xff1b;删除第 k个插入的数后面的数&#xff1b;在第 k&#xfffd; 个插入的数后插入一个数。现在要对该链表进行 M次操作&#xff0c;进行完所…

单片机——显示方式

数码LED 一、静态显示方式 1、连接 所有LED的位选均共同连接到VCC或GND&#xff0c;每个LED的8根段选线分别连接一个8位并行I/O口&#xff0c;从该I/O口送出相应的字型码显示字型。 2、这种连接方式的缺点就是需要的数据线太多&#xff1a;我们可以计算一下&#xff1a;8*4133根…

[oeasy]python0088_字节_Byte_存储单位_KB_MB_GB_TB

编码进化 回忆上次内容 上次 回顾了 字符大战的结果 ibm 曾经的 EBCDIC 由于字符不连续的隐患 导致后续 出现 无数问题无法补救 7-bit 的 ASA X3.4-1963 字母序号连续 比较字符时 效率高判断字符 是否是字母 也很容易 获得了 IBM以外公司的 支持 为什么 ASA X3.4-1963 是 7…

PHP 页面静态化

前言随着网站的内容的增多和用户访问量的增多&#xff0c;网站加载会越来越慢&#xff0c;受限于带宽和服务器同一时间的请求次数的限制&#xff0c;&#xff0c;我们往往需要在此时对我们的网站进行代码优化和服务器配置的优化。一、页面静态化概念静态化定义静态化就是指把原…

VNCTF 2023 - Web 象棋王子|电子木鱼|BabyGo Writeups

象棋王子 签到题&#xff0c;jsfuck解密 丢到console得到flag 电子木鱼 后面两道都是代码审计&#xff0c;这题是rust&#xff0c;题目给出了源码&#xff0c;下载下来看 关键代码&#xff1a; 由于限制&#xff0c;quantity只能为正数 功德也只能是正数&#xff08;负数的…

如何下载JDK8源码并导入IDEA

目录一、下载JDK8源码二、将源码导入IDEA一、下载JDK8源码 JDK8源码下载地址&#xff1a; https://hg.openjdk.org/ 1.打开下载地址&#xff0c;JDK8的源码都是基于jdk8u之上&#xff0c;所以点击jdk8u 2.进入页面之后可以看到一些小版本&#xff0c;这里我们选择 jdk8u60&am…

Python 之 Pandas Series 数据结构

文章目录一、Series 结构二、数据结构 Series 创建1. 创建1.1 列表/数组作为数据源创建 Series1.2 字典作为数据源创建 Series1.3 通过标量创建2. 参数说明2.1 index 参数2.2 name 参数2.3 copy 参数三、Series 的索引/切片1. 下标索引2. 标签索引3. 切片四、Series 数据结构的…

WSL1和WSL2相互转换以及安装路径迁移相关问题

目录 1.从WSL 1如何切换到WSL 2&#xff1f; 2.从WSL 2如何切换回WSL 1&#xff1f; 3.WSL1转换为WSL2后&#xff0c;WSL1里面安装的程序和库需要重装吗&#xff1f; 4.WSL2转换为WSL1后&#xff0c;WSL2里面安装的程序和库需要重装吗&#xff1f; 5.如何备份WSL2&#xf…

【内网安全】——Windows权限维持

作者名&#xff1a;白昼安全主页面链接&#xff1a; 主页传送门创作初心&#xff1a; 以后赚大钱座右铭&#xff1a; 不要让时代的悲哀成为你的悲哀专研方向&#xff1a; web安全&#xff0c;后渗透技术每日鸡汤&#xff1a;20岁的年纪不该困在爱与不爱里&#xff0c;对吗在红队…

shiro CVE-2020-13933

0x00 前言 同CVE-2020-1957&#xff0c;补充一下笔记&#xff0c;在CVE-2020-1957的基础上进行了绕过。 影响版本&#xff1a;Apache Shiro < 1.6.0 环境搭建参考&#xff1a;shiro CVE-2020-1957 0x01 漏洞复现 CVE-2020-13933中使用%3b绕过了shiro /*的检测方式&…

使用BP神经网络和Elman Net预测航班价格(Matlab代码实现)

&#x1f468;‍&#x1f393;个人主页&#xff1a;研学社的博客&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5;&#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密…

电脑如何录制屏幕视频?6个屏幕录制的好方法

我们每天消费的大部分媒体都是通过视频。研究表明&#xff0c;与阅读相比&#xff0c;我们通过观看视频保留的信息更多。因此&#xff0c;很容易看出视频在我们的个人生活和职业生活中的重要性。 让我们更深入地了解视频录制软件和市场上的一些最佳选择。 如何确定好的视频录制…

建议收藏,轻松搞懂区块链

未来已来&#xff0c;只是不均衡地分布在当下 大家好&#xff0c;我是菜农&#xff0c;欢迎来到我的频道。 本文共 5844字&#xff0c;预计阅读 30 分钟 区块链是近些年来最热门的前沿技术&#xff0c;被认为是未来十几年对金融、物联网、医疗等诸多领域产生最大影响的"…

Similarity-Preserving KD(ICCV 2019)原理与代码解析

paper&#xff1a;Similarity-Preserving Knowledge Distillationcode&#xff1a;https://github.com/megvii-research/mdistiller/blob/master/mdistiller/distillers/SP.py背景本文的灵感来源于作者观察到在一个训练好的网络中&#xff0c;语义上相似的输入倾向于引起相似的…