外贸网站平台都有哪些平台,购物网站排名第一的有哪些,建设银行购物网站,如何注册公司名字目录 1、具体的效果2、代码实现2.1 基本原理2.2 开发环境2.3 具体代码2.3.1 基本设置2.3.2 系统的权限授予2.3.3 进度条的layout文件2.3.4 核心的升级文件 3、代码下载4、知识点5、参考文献 1、具体的效果
有事需要在程序内集成自动更新的功能#xff0c;网上找了下#xff… 目录 1、具体的效果2、代码实现2.1 基本原理2.2 开发环境2.3 具体代码2.3.1 基本设置2.3.2 系统的权限授予2.3.3 进度条的layout文件2.3.4 核心的升级文件 3、代码下载4、知识点5、参考文献 1、具体的效果
有事需要在程序内集成自动更新的功能网上找了下改改适配下Xamarin.Android效果如下
2、代码实现
2.1 基本原理
这个功能本质上就是使用一个Intent打开一个apk文件进行预览。Android系统遇到预览apk文件时就会弹出“是否进行安装更新”这类的安装框。
2.2 开发环境
VS2022.NET7Xamarin.Android、实体手机的Android版本11
2.3 具体代码
2.3.1 基本设置
1、允许访问http 为了安全从Android 7.0之后不允许直接访问http的资源因为我们会把安装包放在http的网络环境中因此需要进行一个设置在AndroidManifest.xml中application节点中直接添加android:usesCleartextTraffictrue即可。Android访问http的方案说明 2、设置FileProvider 同样为了安全在Android7.0之后系统安装APP必须使用FileProvider因此需要在AndroidManifest.xml中进行配置provider 3、权限设置 为了能够下载、存放、读取安装包需要一系列的权限。需要在AndroidManifest.xml中进行配置
因此最终的配置文件内容如下
?xml version1.0 encodingutf-8?
manifest xmlns:androidhttp://schemas.android.com/apk/res/android android:versionCode1 android:versionName1.2 packagecom.updateapp android:installLocationautouses-sdk android:minSdkVersion28 android:targetSdkVersion33 /!--为了能够安装apk文件需要下面的一系列授权--uses-permission android:nameandroid.permission.ACCESS_NETWORK_STATE /uses-permission android:nameandroid.permission.INTERNET /uses-permission android:nameandroid.permission.ACCESS_WIFI_STATE /uses-permission android:nameandroid.permission.MOUNT_UNMOUNT_FILESYSTEMS /uses-permission android:nameandroid.permission.READ_EXTERNAL_STORAGE /uses-permission android:nameandroid.permission.WRITE_EXTERNAL_STORAGE /uses-permission android:nameandroid.permission.REQUEST_INSTALL_PACKAGES /application android:allowBackuptrue android:iconmipmap/ic_launcher android:labelstring/app_name android:supportsRtltrue android:themestyle/AppTheme android:usesCleartextTraffictrue !--这句话是为了可以访问http的资源--!--下面的配置是为了设置FileProvider,其中用到了file_paths配置文件具体如下--provider android:nameandroidx.core.content.FileProvider android:authoritiescom.updateapp.fileprovider android:exportedfalse android:grantUriPermissionstruemeta-data android:nameandroid.support.FILE_PROVIDER_PATHS android:resourcexml/file_paths/meta-data/provider/application
/manifest在Resources文件下创建xml文件夹并创建file_paths.xml配置文件代码如下
?xml version1.0 encodingutf-8?
paths xmlns:androidhttp://schemas.android.com/apk/res/android!--安装包文件存储路径--external-files-pathnamemy_downloadpathDownload /external-pathname.path. /
/paths以上就是第一步程序的基本配置
2.3.2 系统的权限授予
除了AndroidManifest.xml中进行配置权限外还需要进行权限的程序判定及授权
protected override void OnCreate(Bundle savedInstanceState)
{base.OnCreate(savedInstanceState);Xamarin.Essentials.Platform.Init(this, savedInstanceState);SetContentView(Resource.Layout.activity_main);Toolbar toolbar FindViewByIdToolbar(Resource.Id.toolbar);SetSupportActionBar(toolbar);FloatingActionButton fab FindViewByIdFloatingActionButton(Resource.Id.fab);fab.Click FabOnClick;//版本跟踪这个是和Android不一样的地方VersionTracking.Track();//初始化自动升级的功能autoUpdaternew AutoUpdater(this);try{//6.0之后才能使用动态授权if(Build.VERSION.SdkIntBuildVersionCodes.M){string[] permissions {Manifest.Permission.ReadExternalStorage,Manifest.Permission.WriteExternalStorage,Manifest.Permission.AccessWifiState,Manifest.Permission.Internet};Liststring permissionList new Liststring();for (int i 0; i permissions.Length; i){if(ActivityCompat.CheckSelfPermission(this, permissions[i])!Permission.Granted){ permissionList.Add(permissions[i]);}}//if(permissionList.Count0){//更新程序autoUpdater.checkUpdate();}else{//获取授权ActivityCompat.RequestPermissions(this, permissions, 100);}}}catch(Exception e){Toast.MakeText(this,发生异常e.Message,ToastLength.Long).Show();}
}public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults)
{Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);bool checkPermissionFlag true;if (requestCode 100){for(int i 0; i permissions.Length; i){if (grantResults[i] Permission.Granted){checkPermissionFlag checkPermissionFlag true;}else{checkPermissionFlag checkPermissionFlag false;}}if(!checkPermissionFlag){//授权程序Snackbar.Make(View.Inflate(this,Resource.Id.activity_main_layout,null),需要授权,Snackbar.LengthIndefinite).SetAction(ok,new ActionView(delegate (View obj){ActivityCompat.RequestPermissions(this, permissions, 100);})).Show();}else{//更新程序Toast.MakeText(this, 授权后可以进行更新程序啦, ToastLength.Long).Show();autoUpdater.checkUpdate();}}base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}2.3.3 进度条的layout文件
在layout文件夹中添加progress.xml文件
?xml version1.0 encodingutf-8?
LinearLayout xmlns:androidhttp://schemas.android.com/apk/res/androidandroid:orientationverticalandroid:layout_widthmatch_parentandroid:layout_heightmatch_parentLinearLayoutandroid:idid/titleBarandroid:layout_widthmatch_parentandroid:layout_heightwrap_contentandroid:orientationhorizontalTextViewandroid:idid/txtStatusandroid:layout_widthwrap_contentandroid:layout_heightwrap_contentandroid:text状态android:textSize10spandroid:textStylenormal /ProgressBarandroid:idid/progressstyle?android:attr/progressBarStyleHorizontalandroid:layout_widthmatch_parentandroid:layout_heightwrap_contentandroid:layout_toLeftOfid/txtStatus //LinearLayout
/LinearLayout2.3.4 核心的升级文件
using Android.App;
using Android.Content;
using Android.Net;
using Android.OS;
using Android.Runtime;
using Android.Systems;
using Android.Util;
using Android.Views;
using Android.Widget;
using Java.IO;
using Java.Net;
using Java.Util.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Remoting.Contexts;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Xamarin.Essentials;
using Context Android.Content.Context;
using Environment Android.OS.Environment;namespace UpdateApp
{public class AutoUpdater{private Android.App.AlertDialog confirmDialog null; //确认是否下载的对话框private Android.App.AlertDialog loadingDialog null; //正在下载的对话框public MainActivity mainActivity;private UpdateHandler updateHandler;// 保存APK的文件名private static string saveFileName my.apk;private static File apkFile;// 进度条与通知UI刷新的handler和msg常量public ProgressBar mProgress;public TextView txtStatus;public int progress;// 当前进度public AutoUpdater(MainActivity activity) {mainActivity activity;updateHandler new UpdateHandler(this);apkFile new File(mainActivity.GetExternalFilesDir(Environment.DirectoryDownloads), saveFileName);}//主方法public void checkUpdate(){//新开启一个线程进行下载及逻辑判断Task.Run(() {//获取本地的版本名称一般而言就是1.0、1.1、1.2的纯数字string localVersionName VersionTracking.CurrentVersion;//获取服务器的版本string remoteServerVersion 2.2; //远程获取服务器上最新版本这儿省事儿了直接默认取了一个较大的值if (Convert.ToDouble(localVersionName) Convert.ToDouble(remoteServerVersion)){//启动升级的界面updateHandler.SendEmptyMessage((int)UpdateStatusEnum.BeginLoad);}});}//弹框进行下载public void ShowUpdateDialog(){Android.App.AlertDialog.Builder builder null;builder new Android.App.AlertDialog.Builder(mainActivity);confirmDialog builder.SetTitle(软件版本更新).SetMessage(有最新的软件包请下载并安装!).SetPositiveButton(立即下载, (s, e) { //确定按钮及内部方法ShowDownloadDialog();confirmDialog.Dismiss();}).SetNegativeButton(以后再说, (s, e) { //界面上的关闭按钮及方法confirmDialog.Dismiss();}).Create();confirmDialog.Show();}//弹出确认下载的进度条的内容private void ShowDownloadDialog(){CancellationTokenSource cts new CancellationTokenSource();CancellationToken cancellationToken cts.Token;Android.App.AlertDialog.Builder builder null;builder new Android.App.AlertDialog.Builder(mainActivity);View view mainActivity.LayoutInflater.Inflate(Resource.Layout.progress, null, false);mProgress view.FindViewByIdProgressBar(Resource.Id.progress);txtStatus view.FindViewByIdTextView(Resource.Id.txtStatus);loadingDialog builder.SetView(view).SetTitle(正在更新).SetNegativeButton(取消下载, (s, e) { //界面上的关闭按钮及方法cts.Cancel();}).Create();loadingDialog.Show();DownloadApk(cancellationToken);}//下载APPprivate void DownloadApk(CancellationToken cancellationToken){Task.Run(() {try { URL url new URL(http://xxx/xxx/xxx/com.updateapp.apk);//apk的网络地址URLConnection conn url.OpenConnection();conn.Connect();int length conn.ContentLength;System.IO.Stream ins conn.InputStream;FileOutputStream fos new FileOutputStream(apkFile);int count 0;byte[] buf new byte[1024];while (!cancellationToken.IsCancellationRequested){int numread ins.Read(buf);count numread;progress (int)(((float)count / length) * 100);//下载进度Message message new Message();message.What (int)UpdateStatusEnum.Loading;Bundle extras new Bundle();extras.PutInt(progress, progress);message.Data extras;updateHandler.SendMessage(message);if (numread 0){Message msg new Message();//下载完成msg.What (int)UpdateStatusEnum.Finish; extras.PutInt(progress, 100);msg.Data extras;updateHandler.SendMessage(msg);//关闭下载框if(loadingDialog!null) loadingDialog.Dismiss(); break;}fos.Write(buf, 0, numread);}fos.Close();ins.Close();}catch (System.OperationCanceledException el){Log.Info(info, 用户取消了操作el.Message);}catch (AggregateException e){foreach (Exception ex in e.InnerExceptions){Log.Info(info, 发生异常 ex.Message);}}}, cancellationToken);}public void installAPK(){try{if(!apkFile.Exists()){Toast.MakeText(mainActivity, 下载的文件不存在, ToastLength.Short).Show();return;}//这儿是整个的核心Intent intent new Intent();intent.SetAction(Intent.ActionView);intent.AddFlags(ActivityFlags.NewTask);intent.AddFlags(ActivityFlags.GrantReadUriPermission);intent.AddFlags(ActivityFlags.GrantWriteUriPermission);if (Build.VERSION.SdkInt Android.OS.BuildVersionCodes.N){string packageName mainActivity.ApplicationContext.PackageName;string authority new StringBuilder(packageName).Append(.fileprovider).ToString();Android.Net.Uri apkUri FileProvider.GetUriForFile(mainActivity, authority, apkFile);intent.SetDataAndType(apkUri, application/vnd.android.package-archive);}else{intent.SetDataAndType(Android.Net.Uri.FromFile(apkFile), application/vnd.android.package-archive);}mainActivity.StartActivity(intent);}catch (Exception ex){Toast.MakeText(mainActivity, 安装installAPK发生异常ex.Message, ToastLength.Short).Show();}}}//状态枚举 public enum UpdateStatusEnum:int{ BeginLoad1,Loading2,Finish3}//Handler事件public class UpdateHandler : Android.OS.Handler{private WeakReferenceAutoUpdater weakReference;[Obsolete]public UpdateHandler(AutoUpdater autoUpdater){weakReference new WeakReferenceAutoUpdater(autoUpdater);}public override void HandleMessage(Message msg){AutoUpdater targetActivity;bool isGetSuccess weakReference.TryGetTarget(out targetActivity);if (isGetSuccess){switch (msg.What){case (int)UpdateStatusEnum.BeginLoad:targetActivity.ShowUpdateDialog();break;case (int)UpdateStatusEnum.Loading://获取状态数据并进行展示int progress msg.Data.GetInt(progress);targetActivity.txtStatus.SetText(progress %,TextView.BufferType.Normal);targetActivity.mProgress.SetProgress(progress, true);break;case (int)UpdateStatusEnum.Finish:Toast.MakeText(targetActivity.mainActivity, 下载完毕, ToastLength.Long).Show();targetActivity.installAPK();break;default:break;}}base.HandleMessage(msg);}}}上面是这个的核心
3、代码下载
代码下载
4、知识点
1、Handler的用法C#与Java还是不同的这里涉及到的知识点是匿名类和委托。C#的匿名类是一个field的集合不能包含方法 2、Android中更新应用的逻辑 每个 Android 应用均有一个唯一的应用 ID像 Java 或 Kotlin 软件包名称一样例如 com.example.myapp。此 ID 可以作为每个应用在设备上的唯一标识。Android 设备一次只能安装一个具有指定应用 ID 的应用。 为了让 Android 平台接受更新更新必须满足以下条件 应用更新的应用 ID 必须与已安装应用的应用 ID 相同。 应用更新的签名证书必须与已安装应用的签名证书相同或者必须包含有效的 proof-of-rotation。 应用更新的版本代码必须高于或等于已安装应用的版本代码。 在某些情况下用户可能需要接受更新。 请注意如果多个更新具有相同的签名证书并且具有相同或更高的版本代码Android 内部并没有防范措施能够阻止不同的安装程序更新应用。 如要安装不符合上述条件的应用用户必须先卸载当前已安装的版本而卸载操作会清除设备上的所有应用数据。 5、参考文献
主要参考了前两个 1、Android App自动安装 2、Android APP 自动更新实现(适用Android9.0) 3、【Android】APP检测版本升级更新、apk安装 4、Andrioid FileProvider在Xamarin.Forms中的使用 5、Xamarin.Android 中 Handler 的使用