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

思路

  • 服务端提供版本信息和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开发安卓入门 -记录两个问题处理办法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值