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

React Native Expo应用Assets文件保存至物理设备:APK失效问题解决

问题:Expo打包APK后无法保存Assets中的图片到设备相册

在React Native Expo应用的Assets文件夹中添加了图片,希望用户能将这些图片保存到物理设备。代码在Expo Go中正常运行,但安装APK后失效。

原测试代码

import React from 'react';
import {View, Text, Button, Image} from 'react-native'
import * as MediaLibrary from 'expo-media-library';
import {Asset} from 'expo-asset';
import { useRoute } from '@react-navigation/native';

const Test = () => {

  //Example Image Url = require('../assets/nk/myimage.jpg')
  const route = useRoute(); 
  const saveFileToMediaLibrary = async () => {
    try {
      const asset = Asset.fromModule(route.params.u);
      // Download the asset to the local file system
      await asset.downloadAsync();
      // Get the local URI of the downloaded file
      const fileUri = asset.localUri;
    // File saved successfully
      console.log('File saved to media library:', fileUri);
      
      // Save the file to the media library
      const perm = await MediaLibrary.requestPermissionsAsync();
        if (perm.status != "granted") {
          return;
        }

        try {
          const asset = await MediaLibrary.createAssetAsync(fileUri);
          console.log(asset);
          const album = await MediaLibrary.getAlbumAsync("My App Images");
          if (album == null) {
            await MediaLibrary.createAlbumAsync("My App Images", asset, false);
          } else {
            await MediaLibrary.addAssetsToAlbumAsync([asset], album, false);
          }
        } catch (e) {
          alert("Something Went Wrong..."+ e);
        }
    } catch (error) {
      alert('Error to save file in media library', fileUri);
    }
  };

  return (
    <View>
      <Button title="Download File" onPress={()=>{saveFileToMediaLibrary()}} />
      <Image 
      source={route.params.u} style={{width:100,height:100}}
      />
    </View>
  );
};
export default Test;

解决方案

1. 处理打包后Asset路径差异

Expo Go与打包后的APK中,Asset的本地URI格式存在差异,直接使用asset.localUri无法被MediaLibrary识别。需要借助expo-file-system将Asset复制到临时目录,再用临时路径进行保存。

先安装依赖:

npx expo install expo-file-system

修改文件路径获取逻辑:

import * as FileSystem from 'expo-file-system';

// 替换原Asset下载与URI获取代码
const asset = Asset.fromModule(route.params.u);
await asset.downloadAsync();
// 复制Asset到临时目录
const tempUri = `${FileSystem.cacheDirectory}${asset.name || 'saved_image'}.jpg`;
await FileSystem.copyAsync({
  from: asset.localUri,
  to: tempUri
});
const fileUri = tempUri; // 使用临时路径执行后续操作

2. 完善权限配置

在app.json中明确声明所需权限,打包APK时必须配置:

{
  "expo": {
    "android": {
      "permissions": [
        "android.permission.READ_EXTERNAL_STORAGE",
        "android.permission.WRITE_EXTERNAL_STORAGE",
        "android.permission.MANAGE_EXTERNAL_STORAGE"
      ]
    }
  }
}

注:Android 13+需额外添加READ_MEDIA_IMAGES权限,可根据系统版本动态处理。

3. 修复变量名冲突

原代码内部try块重新定义了asset变量,会覆盖外部Asset实例,建议重命名:

// 内部try块中
const mediaAsset = await MediaLibrary.createAssetAsync(fileUri);

4. 优化错误提示

原catch块中alert参数存在未定义风险,调整为:

catch (error) {
  alert(`保存失败:${error.message}`);
  console.error('保存错误详情:', error);
}

完整修改后的代码

import React from 'react';
import {View, Text, Button, Image} from 'react-native'
import * as MediaLibrary from 'expo-media-library';
import {Asset} from 'expo-asset';
import { useRoute } from '@react-navigation/native';
import * as FileSystem from 'expo-file-system';

const Test = () => {
  const route = useRoute(); 

  const saveFileToMediaLibrary = async () => {
    try {
      const asset = Asset.fromModule(route.params.u);
      await asset.downloadAsync();
      
      // 复制到临时目录解决打包后路径问题
      const tempUri = `${FileSystem.cacheDirectory}${asset.name || 'saved_image'}.jpg`;
      await FileSystem.copyAsync({
        from: asset.localUri,
        to: tempUri
      });

      const perm = await MediaLibrary.requestPermissionsAsync();
      if (perm.status !== "granted") {
        alert('需要相册权限才能保存图片');
        return;
      }

      try {
        const mediaAsset = await MediaLibrary.createAssetAsync(tempUri);
        const album = await MediaLibrary.getAlbumAsync("My App Images");
        if (!album) {
          await MediaLibrary.createAlbumAsync("My App Images", mediaAsset, false);
        } else {
          await MediaLibrary.addAssetsToAlbumAsync([mediaAsset], album, false);
        }
        alert('图片保存成功');
      } catch (e) {
        alert(`保存到相册失败:${e.message}`);
        console.error('相册操作错误:', e);
      }
    } catch (error) {
      alert(`准备文件失败:${error.message}`);
      console.error('文件处理错误:', error);
    }
  };

  return (
    <View style={{padding: 20}}>
      <Button title="下载图片" onPress={saveFileToMediaLibrary} />
      <Image 
        source={route.params.u} 
        style={{width:100,height:100, marginTop: 20}}
      />
    </View>
  );
};
export default Test;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 04:47:14