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

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

文章目录

  • 思路
  • 客户端
    • 权限清单(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-pathname="int_root"path="/" /><!--2、对应应用默认缓存根目录:Context.getCacheDir()--><cache-pathname="app_cache"path="/" /><!--3、对应外部内存卡根目录:Environment.getExternalStorageDirectory()--><external-pathname="ext_root"path="pictures/" /><!--4、对应外部内存卡根目录下的APP公共目录:Context.getExternalFileDir(String)--><external-files-pathname="ext_pub"path="/" /><!--5、对应外部内存卡根目录下的APP缓存目录:Context.getExternalCacheDir()--><external-cache-pathname="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

相关文章:

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

文章目录思路客户端权限清单&#xff08;AndroidManifest.xml&#xff09;权限列表(完整内容看 权限清单&#xff08;AndroidManifest.xml&#xff09;&#xff09;打开外部应用的权限(完整内容看 权限清单&#xff08;AndroidManifest.xml&#xff09;&#xff09;添加文件如下…...

分享111个HTML艺术时尚模板,总有一款适合您

分享111个HTML艺术时尚模板&#xff0c;总有一款适合您 111个HTML艺术时尚模板下载链接&#xff1a;https://pan.baidu.com/s/1sYo2IPma4rzeku3yCG7jGw?pwdk8dx 提取码&#xff1a;k8dx Python采集代码下载链接&#xff1a;采集代码.zip - 蓝奏云 时尚理发沙龙服务网站模…...

spring之Spring AOP基于注解

文章目录前言一、Spring AOP基于注解的所有通知类型1、前置通知2、后置通知3、环绕通知4、最终通知5、异常通知二、Spring AOP基于注解之切面顺序三、Spring AOP基于注解之通用切点三、Spring AOP基于注解之连接点四、Spring AOP基于注解之全注解开发前言 通知类型包括&#x…...

LeetCode题目笔记——6362. 合并两个二维数组 - 求和法

文章目录题目描述题目链接题目难度——简单方法一&#xff1a;常规双指针遍历代码/Python方法二&#xff1a;字典\哈希表代码/Python总结题目描述 给你两个 二维 整数数组 nums1 和 nums2. nums1[i] [idi, vali] 表示编号为 idi 的数字对应的值等于 vali 。nums2[i] [idi, …...

【C#基础】C# 常用语句讲解

序号系列文章3【C#基础】C# 数据类型总结4【C#基础】C# 变量和常量的使用5【C#基础】C# 运算符总结文章目录前言语句概念1&#xff0c;迭代语句1.1 for 语句1.2 foreach 语句1.3 while 语句1.4 do 语句2&#xff0c;选择语句2.1&#xff0c;if 语句2.2&#xff0c;else 语句2.3…...

腾讯云——负载均衡CLB

负载均衡 CLB 提供四层&#xff08;TCP 协议/UDP 协议/TCP SSL 协议&#xff09;和七层&#xff08;HTTP 协议/HTTPS 协议&#xff09;负载均衡。您可以通过 CLB 将业务流量分发到多个后端服务器上&#xff0c;消除单点故障并保障业务可用性。CLB 自身采用集群部署&#xff0c;…...

6.关于系统服务的思考—— native vs java

文章目录native服务 以sensor service为例Native 服务java 服务&#xff0c; 以vibrate为例java 服务 以一个demo为例native服务 以sensor service为例 service启动 SystemServer.startBootstrapServices---->>>mSystemServiceManager.startService—>>>Sen…...

SQL语句创建视图:

前言 &#x1f388;个人主页:&#x1f388; :✨✨✨初阶牛✨✨✨ &#x1f43b;推荐专栏: &#x1f354;&#x1f35f;&#x1f32f; c语言初阶 &#x1f511;个人信条: &#x1f335;知行合一 &#x1f349;本篇简介:>:介绍数据库中有关视图的知识,参考学校作业. 金句分享:…...

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

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

JavaWeb9-volatile解决内存可见性和指令重排序问题

目录 1.解决内存可见性问题 2.解决指令重排序问题 3.volatile缺点 4.特使使用场景 volatile&#xff08;易变的&#xff0c;易挥发的&#xff0c;不稳定的&#xff09;可以解决内存可见性和指令重排序的问题。 1.解决内存可见性问题 代码在写入 volatile 修饰的变量时&am…...

Docker - 镜像操作命令

镜像名称一般分为两部分组成:[repository]:[tag]在没有指定tag时&#xff0c;默认是latest&#xff0c;代表最新版本的镜像1.下载docker镜像 docker pull repository:tag2.查看本地所有镜像 docker images3.创建镜像别名 docker tag repository:tag repository111:tag4.查看镜像…...

全栈之路-前端篇 | 第三讲.基础前置知识【前端标准与研发工具】学习笔记

欢迎关注「全栈工程师修炼指南」公众号 点击 &#x1f447; 下方卡片 即可关注我哟! 设为「星标⭐」每天带你 基础入门 到 进阶实践 再到 放弃学习&#xff01; 涉及 企业运维、网络安全、应用开发、物联网、人工智能、大数据 学习知识 “ 花开堪折直须折&#xff0c;莫待无花…...

Tomcat 线上调优记录

原始Tomcat配置 启动参数Plaintext-Xms256m -Xmx512m -XX:MaxPermSize128m Tomcat 参数配置XML<Executor name"tomcatThreadPool" namePrefix"catalina-exec-" maxThreads"1500" minSpareThreads"50" maxIdleTime"600000&q…...

学习 Python 之 Pygame 开发坦克大战(四)

学习 Python 之 Pygame 开发坦克大战&#xff08;四&#xff09;坦克大战添加音效1. 初始化音效2. 加入游戏开始音效和坦克移动音效3. 添加坦克开火音效4. 添加装甲削减音效5. 添加坦克爆炸音效6. 添加子弹击中边界音效坦克大战添加音效 我的素材放到了百度网盘里&#xff0c;…...

New和Malloc的使用及其差异

1&#xff0c;new的使用关于new的定义&#xff1a;new其实就是告诉计算机开辟一段新的空间&#xff0c;但是和一般的声明不同的是&#xff0c;new开辟的空间在堆上&#xff0c;而一般声明的变量存放在栈上。通常来说&#xff0c;当在局部函数中new出一段新的空间&#xff0c;该…...

2023年细胞生物学复习汇总

细胞分化 1.什么是细胞分化&#xff1f;细胞分化的特点是什么&#xff1f; 答&#xff1a;&#xff08;1&#xff09;细胞分化&#xff08;cell differentiation&#xff09;是指同一来源的细胞逐渐产生出形态结构、功能特征各不相同的细胞类群的过程&#xff0c;其结果是在空间…...

光伏VSG-基于虚拟同步发电机的光伏并网逆变器系统MATLAB仿真

采用MATLAB2021b仿真&#xff01;&#xff01;&#xff01;仿真模型1光伏电池模块&#xff08;采用MATLAB自带光伏模块&#xff09;、MPPT控制模块、升压模块、VSG控制模块、电流滞环控制模块。2s时改变光照强度 &#xff01;&#xff01;&#xff01;VSG输出有功功率、无功功率…...

高可用 - 02 Keepalived_VRRP工作原理

文章目录Keepalived VS HeartbeatKeepalived的用途VRRP与工作原理物理路由器和虚拟路由器Keepalived VS Heartbeat Keepalived是Linux下一个轻量级的高可用解决方案&#xff0c;它与Heartbeat、RoseHA实现的功能类似&#xff0c;都可以实现服务或者网络的高可用&#xff0c;但…...

vue实现xml在线编辑功能

先看效果 避免误会 这是一个在线编辑器 我们可以在这上面随意的编写xml代码格式 我们修改上面的内容之后 就可以在控制台输出内容 如果这正是您想要的东西 那就可以先创建一个vue项目 我们先引入依赖 npm install brace -S npm install element-ui -S npm install vue-cli…...

GitHub Workflow

GitHub Workflow 基本流程 把远程仓库克隆到本地 git clone xxxx.git在本地切换至新的分支 git checkout -b new_branch修改本地仓库的文件 项目修改完成后&#xff0c;查看修改的内容 git diff上传修改之后的内容到本地暂存区 git add modified_files将本地暂存区的代码更新…...

【杂谈】-递归进化:人工智能的自我改进与监管挑战

递归进化&#xff1a;人工智能的自我改进与监管挑战 文章目录 递归进化&#xff1a;人工智能的自我改进与监管挑战1、自我改进型人工智能的崛起2、人工智能如何挑战人类监管&#xff1f;3、确保人工智能受控的策略4、人类在人工智能发展中的角色5、平衡自主性与控制力6、总结与…...

Admin.Net中的消息通信SignalR解释

定义集线器接口 IOnlineUserHub public interface IOnlineUserHub {/// 在线用户列表Task OnlineUserList(OnlineUserList context);/// 强制下线Task ForceOffline(object context);/// 发布站内消息Task PublicNotice(SysNotice context);/// 接收消息Task ReceiveMessage(…...

JVM垃圾回收机制全解析

Java虚拟机&#xff08;JVM&#xff09;中的垃圾收集器&#xff08;Garbage Collector&#xff0c;简称GC&#xff09;是用于自动管理内存的机制。它负责识别和清除不再被程序使用的对象&#xff0c;从而释放内存空间&#xff0c;避免内存泄漏和内存溢出等问题。垃圾收集器在Ja…...

1.3 VSCode安装与环境配置

进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件&#xff0c;然后打开终端&#xff0c;进入下载文件夹&#xff0c;键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...

ardupilot 开发环境eclipse 中import 缺少C++

目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...

图表类系列各种样式PPT模版分享

图标图表系列PPT模版&#xff0c;柱状图PPT模版&#xff0c;线状图PPT模版&#xff0c;折线图PPT模版&#xff0c;饼状图PPT模版&#xff0c;雷达图PPT模版&#xff0c;树状图PPT模版 图表类系列各种样式PPT模版分享&#xff1a;图表系列PPT模板https://pan.quark.cn/s/20d40aa…...

【HarmonyOS 5 开发速记】如何获取用户信息(头像/昵称/手机号)

1.获取 authorizationCode&#xff1a; 2.利用 authorizationCode 获取 accessToken&#xff1a;文档中心 3.获取手机&#xff1a;文档中心 4.获取昵称头像&#xff1a;文档中心 首先创建 request 若要获取手机号&#xff0c;scope必填 phone&#xff0c;permissions 必填 …...

CMake控制VS2022项目文件分组

我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...

消息队列系统设计与实践全解析

文章目录 &#x1f680; 消息队列系统设计与实践全解析&#x1f50d; 一、消息队列选型1.1 业务场景匹配矩阵1.2 吞吐量/延迟/可靠性权衡&#x1f4a1; 权衡决策框架 1.3 运维复杂度评估&#x1f527; 运维成本降低策略 &#x1f3d7;️ 二、典型架构设计2.1 分布式事务最终一致…...

算法打卡第18天

从中序与后序遍历序列构造二叉树 (力扣106题) 给定两个整数数组 inorder 和 postorder &#xff0c;其中 inorder 是二叉树的中序遍历&#xff0c; postorder 是同一棵树的后序遍历&#xff0c;请你构造并返回这颗 二叉树 。 示例 1: 输入&#xff1a;inorder [9,3,15,20,7…...