Expo 图像选择器 uri 不适用于每个 phone

Expo image picker uri does not work on every phone

我正在使用 Expo 构建 React Native 应用程序。我希望用户能够保存个人资料图片。我已经尝试了几个月了。我使用 Expo 图像选择器来执行此操作。但是,我取回的文件在本地系统中。当我尝试登录另一个 phone 时,图像没有显示,可能是因为它仅限于从中获取图像的 phone。我在 iOS 上阅读了一篇关于删除 file:// 的文章,但无论如何它都不起作用。在后端,我使用的是 GraphQL,我只是将 photoUrl 作为字符串存储在 MongoDB 数据库中。我的意思是,那里有很多 React Native 应用程序,因此必须有一个简单的解决方案。

代码:

useEffect(() => {
  (async () => {
    if (Platform.OS !== 'web') {
      const {
        status,
      } = await ImagePicker.requestMediaLibraryPermissionsAsync();
      if (status !== 'granted') {
        alert(
          'Vi behöver din profilbild för att göra det lättare för andra användare att veta vem du är'
        );
      }
    }
  })();
}, []);

const pickImage = async () => {
  let result = await ImagePicker.launchImageLibraryAsync({
    mediaTypes: ImagePicker.MediaTypeOptions.Images,
    allowsEditing: true,
    aspect: [4, 3],
    quality: 1,
  });

  if (!result.cancelled && Platform.OS === 'ios') {
    const photo = result?.uri.replace('file://', '/private');

    setPhotoUrl(photo);
  }
};

您正在为上传方法设置本地图像 uri,因此当您尝试取回它时无法取回,因为您上传到 db 的 uri 是本地 uri。

您必须使用 blob 存储并配置您的后端...

步骤:

  • 从本地 uri 获取文件名
  • 将图像上传到 blob 存储
  • 在你的数据库中将 blob url 保存为 'string'(例如:https://yourblobstorage/profilepicture/filename.png)
  • 最好的办法是将文件名更改为用户 ID 或某种唯一 ID。
  • 所以每次你从你的 blob 中为这个用户获取这个url
  • 更改个人资料图片你也这样做(所以用户个人资料图片名称始终是他的用户ID,这对你来说很简单并且节省了一些space XD)

我的实现:

图像选择器方法:

  const addCameraImage = async () => {
setOverlayVisible(false)
const { granted } = await ImagePicker.requestCameraPermissionsAsync()

if (granted === true) {
  let image = await ImagePicker.launchCameraAsync({
    mediaTypes: ImagePicker.MediaTypeOptions.Images,
    allowsEditing: true,
    aspect: [1, 1],
    quality: 1,
  })

  await uploadImage(image)

} else {
  setPermissionOverlayVisible(true)
}
}

上传图片方法:

  const uploadImage = async (image: ImagePicker.ImagePickerResult) => {
if (image.cancelled === false) {
  setLocalImage(image.uri)
  const filename = image.uri.split('/').pop();

  const file = new ReactNativeFile({
    uri: image.uri,
    name: filename,
    type: `image/${filename.split('.').pop()}`
  });

  try {
    await updateProfilePictureMutation({
      variables: {
        id: data?.user?.id,
        profilePicture: file
      },
      update: (cache, { data }) => {
        try {
          const getUserByIdCachedData = cache.readQuery<GetUserByIdQuery>({ query: GetUserByIdDocument, variables: { id: userId } })
          if (!getUserByIdCachedData) return

          const newData = {
            ...getUserByIdCachedData,
            user: {
              ...getUserByIdCachedData.user,
              profilePicture: data.updateUser.profilePicture
            }
          }

          cache.writeQuery({ query: GetUserByIdDocument, variables: { id: userId }, data: newData })
        } catch (e) {
          console.error(e)
        }
      }
    })
  } catch (e) {
  }

  setLocalImage(null)
}
}

打开一个模式,询问用户是否允许打开设置以启用权限,如果他们之前已经拒绝并尝试拍照:

  const openSettings = () => {
if (Platform.OS === 'ios') {
  Linking.openURL('app-settings:')
  setPermissionOverlayVisible(false)
}
if (Platform.OS === 'android') {
  const pkg = Constants.manifest.releaseChannel ? Constants.manifest.android.package : 'host.exp.exponent'
  IntentLauncher.startActivityAsync(
    IntentLauncher.ACTION_APPLICATION_DETAILS_SETTINGS,
    { data: 'package:' + pkg }
  )
  setPermissionOverlayVisible(false)
}
}

现在这里我一拍完就设置本地图片,这样他们就不用等你把图片上传到blob了,一旦上传了,我就从blob中获取

  const getAvatarImage = () => {
if (updateProfilePictureLoading) return null
if (localImage) {
  return { uri: localImage }
}

if (data?.user?.profilePicture) {
  return { uri: data?.user?.profilePicture }
}

return null
}

我希望这能帮助你多了解一点,我一直在纠结这个问题,但后来我意识到它很简单。

我还在后端对我的上传和从 blob 获取进行了突变和查询。

干杯。