You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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.Core NuGet包(FileProvider属于这个包,MAUI默认自带,缺失则手动安装)。

二、配置FileProvider(Android 7.0+必做)

Android 7.0后禁止直接用file:// URI访问文件,必须通过FileProvider生成content:// URI,步骤如下:

  1. 在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>
    
  2. 在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 02:25:52