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

如何在React Native Expo应用内安装下载的.apk文件?

问题

我需要在Expo应用内实现更新功能,安装下载的.apk文件。以下是我的代码:

import React from "react";
import { Button, View } from "react-native";
import * as FileSystem from "expo-file-system";
import { startActivityAsync } from "expo-intent-launcher";

export function Updater() {
  async function updateApk() {
    const uri = "https://expo.dev/artifacts/eas/my_apk_name.apk";
    const localUri = FileSystem.documentDirectory + "test.apk";

    try {
      await FileSystem.downloadAsync(uri, localUri);

      await startActivityAsync("android.intent.action.INSTALL_PACKAGE", {
        data: localUri,
        flags: 1,
      });
    } catch (error) {
      alert(`Error during installing APK: ${error}`);
    }
  }

  return (
    <View>
      <Button title="Reset APK" onPress={updateApk} />
    </View>
  );
}

文件可成功下载并存储,但调用startActivityAsync时出现错误:

Encountered an exception while calling native method:
Exception occurred while executing exported method startActivity on module ExpoIntentLauncher:
file://data/user/0/com.my.app.id/files/test.apk exposed beyond app through Intent.getData()

尝试先将uri传入FileSystem.getContentUriAsync(),此时无错误,但Intent返回结果为0且无任何反应。app.json中的权限配置如下:

"permissions": [
   "READ_EXTERNAL_STORAGE",
   "WRITE_EXTERNAL_STORAGE",
   "CAMERA"
]

疑问:是否需要额外权限?或是Expo无法实现该功能?是否需将文件保存到其他路径?试过android.intent.action.VIEW同样无效。测试环境为Android 13物理设备,应用由EAS构建。

解决方案
  • 补充必要权限:Android 13及以上版本,安装未知来源APK需要REQUEST_INSTALL_PACKAGES权限,先在app.json里添加:

    "permissions": [
       "READ_EXTERNAL_STORAGE",
       "WRITE_EXTERNAL_STORAGE",
       "CAMERA",
       "REQUEST_INSTALL_PACKAGES"
    ]
    

    然后在代码中动态请求这个权限,避免被系统拦截:

    import * as Permissions from 'expo-permissions';
    
    async function requestInstallPermission() {
      const { status } = await Permissions.askAsync(Permissions.REQUEST_INSTALL_PACKAGES);
      if (status !== 'granted') {
        alert('需要开启「安装未知应用」权限才能完成更新');
        return false;
      }
      return true;
    }
    

    在updateApk函数开头先调用这个权限请求,确认授权后再继续执行下载和安装流程。

  • 修正Intent配置与Uri处理:
    直接用file://格式的Uri会触发Android的文件暴露限制,必须用getContentUriAsync生成系统认可的内容Uri,同时要使用正确的Action和Flags:

    async function updateApk() {
      const hasPermission = await requestInstallPermission();
      if (!hasPermission) return;
    
      const uri = "https://expo.dev/artifacts/eas/my_apk_name.apk";
      const localUri = FileSystem.documentDirectory + "test.apk";
    
      try {
        await FileSystem.downloadAsync(uri, localUri);
        // 生成可被系统访问的内容Uri
        const contentUri = await FileSystem.getContentUriAsync(localUri);
    
        await startActivityAsync("android.intent.action.VIEW", {
          data: contentUri,
          type: 'application/vnd.android.package-archive', // 指定APK文件类型
          flags: 0x00000001 | 0x00000040, // 授予读取权限 + 新任务启动安装界面
        });
      } catch (error) {
        alert(`Error during installing APK: ${error}`);
      }
    }
    

    注意:android.intent.action.INSTALL_PACKAGE在Android 8.0+已被弃用,改用VIEW配合type参数就能触发系统的安装流程;Flags里的FLAG_GRANT_READ_URI_PERMISSION能让安装程序获取文件读取权限,FLAG_ACTIVITY_NEW_TASK确保安装界面在独立任务中打开,避免返回异常。

  • 路径选择说明:
    FileSystem.documentDirectory是应用私有目录,Android 13对其访问限制严格,但通过getContentUriAsync生成的Uri已经可以被系统安装程序正常访问,不需要更换存储路径。如果非要使用外部存储,可选择FileSystem.externalDirectory,但需要额外的存储权限,反而不如私有目录便捷。

  • EAS构建注意事项:
    确保EAS构建时app.json的权限配置已正确同步到AndroidManifest.xml,无需手动修改原生代码,重新构建即可生效。

内容的提问来源于stack exchange,提问作者Episodex

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 05:15:46