文章目录
思路
- 服务端提供版本信息和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
同系列文章推荐
.net开发安卓入门 - 环境安装
.net开发安卓入门 - Hello world!
.net开发安卓入门 - 基本交互(Button,输入EditText,TextView,Toast)
.net开发安卓入门 - 布局与样式
.net开发安卓入门 - Activity
.net开发安卓入门 - Notification(通知)
.net开发安卓入门 - 四大基本组件
.net开发安卓入门 - Service (服务)
.net开发安卓入门 - 打包(.apk)
.net开发安卓入门 - ImageView 显示网络图片
.net开发安卓入门-文件操作与配置操作
.net开发安卓入门-Dialog
.net开发安卓入门-自动升级(配合.net6 webapi 作为服务端)
vs2022 实现无线调试安卓(Windows)
.net开发安卓从入门到放弃
.net开发安卓从入门到放弃 最后的挣扎(排查程序闪退问题记录-到目前为止仍在继续)
.net开发安卓入门 -记录两个问题处理办法