MAUI安卓应用自动更新:检测新版本并安装APK
MAUI Android 自动更新:APK存储与安装解决思路
一、先解决编译错误核心原因
那些找不到的Context、Intent、FileProvider、Build类都是Android平台专属API,直接在MAUI共享项目里调用会报错,解决方式如下:
- 把相关代码放到
Platforms/Android目录下的专属类中(比如创建AndroidUpdateHelper.cs),或用#if ANDROID条件编译包裹共享项目里的Android专属代码。 - 必须添加以下命名空间:
using Android.App; using Android.Content; using Android.Content.PM; using Android.OS; using Android.Net; using AndroidX.Core.Content; - 确认项目已安装
Xamarin.AndroidX.CoreNuGet包(FileProvider属于这个包,MAUI默认自带,缺失则手动安装)。
二、配置FileProvider(Android 7.0+必做)
Android 7.0后禁止直接用file:// URI访问文件,必须通过FileProvider生成content:// URI,步骤如下:
- 在
Platforms/Android/Resources/xml目录下创建file_paths.xml(没有xml目录就新建):<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <!-- 允许访问应用私有文件目录下的APK --> <files-path name="apk_files" path="."/> <!-- 允许访问应用外部私有目录下的APK --> <external-files-path name="external_apk_files" path="."/> </paths> - 在
AndroidManifest.xml的<application>标签内添加FileProvider配置:<provider android:name="androidx.core.content.FileProvider" android:authorities="${applicationId}.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider>${applicationId}会自动替换为你的应用包名,无需手动修改。
三、APK存储实现
优先使用应用私有目录(无需额外权限,Android 10+更友好),代码示例:
#if ANDROID async Task SaveApkToDevice(string apkDownloadUrl) { using var httpClient = new HttpClient(); var apkBytes = await httpClient.GetByteArrayAsync(apkDownloadUrl); // 保存到应用私有文件目录,路径示例:/data/data/[你的包名]/files/update.apk var savePath = Path.Combine(FileSystem.AppDataDirectory, "update.apk"); await File.WriteAllBytesAsync(savePath, apkBytes); // 保存完成后调用安装方法 await InstallApk(savePath); } #endif
如果要存到外部公共目录(需配置权限),在AndroidManifest.xml添加:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="28" />
Android 10+无需此权限,Scoped Storage机制限制了公共目录直接写入。
四、启动APK安装
处理不同Android版本的URI差异,代码示例:
#if ANDROID async Task InstallApk(string apkFilePath) { var file = new Java.IO.File(apkFilePath); var context = Android.App.Application.Context; Uri apkUri; if (Build.VERSION.SdkInt >= BuildVersionCodes.N) { // Android 7.0+用FileProvider生成安全URI apkUri = FileProvider.GetUriForFile(context, $"{context.PackageName}.fileprovider", file); } else { // 低版本直接用文件URI apkUri = Uri.FromFile(file); } var installIntent = new Intent(Intent.ActionView); installIntent.SetDataAndType(apkUri, "application/vnd.android.package-archive"); // 标记为新任务,避免栈混乱 installIntent.AddFlags(ActivityFlags.NewTask); // 授予URI读取权限 installIntent.AddFlags(ActivityFlags.GrantReadUriPermission); // 启动安装界面 context.StartActivity(installIntent); } #endif
五、额外注意事项
- 测试时需开启应用的「安装未知应用」权限(Android 8.0+要求),代码里可以跳转到权限设置页引导用户开启:
#if ANDROID void OpenUnknownAppPermissionSettings() { var intent = new Intent(); if (Build.VERSION.SdkInt >= BuildVersionCodes.O) { intent.SetAction(Settings.ActionManageUnknownAppSources); intent.SetData(Uri.Parse($"package:{Android.App.Application.Context.PackageName}")); } else { intent.SetAction(Settings.ActionSecuritySettings); } intent.AddFlags(ActivityFlags.NewTask); Android.App.Application.Context.StartActivity(intent); } #endif - 确保下载APK的过程中添加进度提示,避免用户以为应用无响应。
内容的提问来源于stack exchange,提问作者nicetomitja
相关产品推荐
相关产品推荐

