如何使用 expo 图像选择器将简单图像从移动设备上传到 AWS S3?

How to upload a simple image from a mobile device using expo image picker to AWS S3?

我将 Expo 与 React Native 结合使用,我真的被困在这个问题上... Expo 不支持 firebase 云存储,我多年来一直使用它来上传我的图像。所以我只剩下我从未使用过的 AWS S3。我已经在 github 上找到了这个例子:https://github.com/expo/image-upload-example/ 但我无法理解后端部分是什么以及使用的 apiURl 是什么......我很抱歉我没有提供任何代码尝试但我完全迷失了并且我无法真正看到巨大的AWS 上的 bla bla bla 文档数量。

我已经在 AWS S3 控制台中创建了它,以便可以公开访问我创建的存储桶。我对此没有问题。我不需要授权用户上传图片,任何其他限制只需要完成一个简单的上传。

因此,如果有人可以帮助我完成此代码。提前致谢。

我没有专门使用过 Expo,但我已经设置了我的 RN 项目,以便能够上传到 s3。鉴于您发布的示例,它与我最终所做的非常相似。

显然,您需要做的第一件事就是在 AWS S3 上设置一个存储桶。在 AWS 控制台中,您应该能够找到您的特定访问密钥和访问机密,您将需要这两者以及您的存储桶名称。

您发布的示例背后的想法以及我最终所做的是拥有一个受控服务器,您可以在其中安全地使用访问密钥和秘密来创建一个唯一的 "signed" url可用于将图像直接上传到您的存储桶中。你不想在你的客户端上这样做 b/c 在你的客户端上有一个秘密只是要求被黑客攻击。假设客户端上没有任何东西是完全安全的。

我已经在构建一个节点服务器作为我的应用程序的后端,所以我已经准备好了这部分 运行。如果您不熟悉创建后端服务器,我建议您查看如何设置 Express 服务器 here. You can host the app for free (with limitations) on a service such as heroku. There is even a great article covering this whole process in a bit more detail here. Basically you create a an app with a distinct GET route that can be hit by your client app. That route will accept a query parameter with the file name of the file that is going to be uploaded. You should use the official aws sdk,它将获取您的访问密钥、机密、存储桶名称和文件名,然后生成一个唯一的 url 将被发送回您的客户端应用程序。

本质上,您的客户端应用程序将做的是准备需要上传的文件。您应该准备好文件的文件名,然后向您刚刚在 Express 应用程序上设置的 url 路由发送 GET 请求。当您从服务器收到响应时,它应该包含唯一的 url。然后,我使用 react native fetch blob 库对您刚刚收到的唯一 url 执行 PUT 请求。如果一切顺利,它 应该 将文件安全地直接上传到该存储桶。确保将 header 中的 Content-Type 设置为您要上传的文件类型。

我知道这不是一堆用于上传的代码,但它应该可以帮助您了解需要什么并让您朝着正确的方向前进。

我有同样的问题很长时间了。这就是我所做的。

确保您按照放大指南设置应用程序。 amplify initamplify add authamplify push,然后 amplify add storage,然后执行此操作。

import Amplify, { Storage } from 'aws-amplify'
import config from './src/aws-exports'
// import awsconfig from './aws-exports';
// Might need to switch line 7 to awsconfig 
Amplify.configure(config)

import { StatusBar } from 'expo-status-bar';
import React, { useState, useEffect } from 'react';
import { Button, Image, View, Platform, StyleSheet, Text, TextInput } from 'react-native';
import * as ImagePicker from 'expo-image-picker';

function App() {
  const [image, setImage] = useState(null)
  const [name, setName] = useState('Evan Erickson')

  useEffect(() => {
    (async () => {
      if (Platform.OS !== 'web') {
        const { status } = await ImagePicker.requestMediaLibraryPermissionsAsync();
        if (status !== 'granted') {
          alert('Sorry, we need camera roll permissions to make this work!');
        }
      }
    })();
  }, []);

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

    async function pathToImageFile(data) {
      try {
        const response = await fetch(data);
        const blob = await response.blob();
        await Storage.put(`customers/${name}`, blob, {
          contentType: 'image/jpeg', // contentType is optional
        });
      } catch (err) {
        console.log('Error uploading file:', err);
      }
    }
    // later
    pathToImageFile(result.uri);
  }

  return (
    <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
      <Button title="Pick an image from camera roll" onPress={pickImage} />
      {image && <Image source={{ uri: image }} style={{ width: 200, height: 200 }} />}
      <Button title="Upload image" onPress={() => {alert(image)}} />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
});

export default withAuthenticator(App)```