使用 React Native 将图像上传到 Firebase

Posted

技术标签:

【中文标题】使用 React Native 将图像上传到 Firebase【英文标题】:Upload an image to Firebase with React Native 【发布时间】:2020-06-21 14:46:25 【问题描述】:

我正在尝试将照片上传器制作到 firebase 以响应本机。我遵循了一个教程并采用了一对一的代码。但是,在我想执行代码之后,一切似乎都可以正常工作,直到必须上传代码,然后我收到以下错误:

可能的未处理承诺拒绝(id:0):错误:未知错误 已经发生了。 fn@http://localhost:8081/index.bundle?platform=android&dev=true&minify=false:2132:45 http://localhost:8081/index.bundle?platform=android&dev=true&minify=false:127402:44 putFile@http://localhost:8081/index.bundle?platform=android&dev=true&minify=false:137147:104 上传图片@http://localhost:8081/index.bundle?platform=android&dev=true&minify=false:210966:91 touchableHandlePress@http://localhost:8081/index.bundle?platform=android&dev=true&minify=false:54240:47 touchableHandlePress@[本机代码] _performSideEffectsForTransition@http://localhost:8081/index.bundle?platform=android&dev=true&minify=false:52872:36 _performSideEffectsForTransition@[本机代码] _receiveSignal@http://localhost:8081/index.bundle?platform=android&dev=true&minify=false:52798:46 _receiveSignal@[native code] touchableHandleResponderRelease@http://localhost:8081/index.bundle?platform=android&dev=true&minify=false:52677:26 touchableHandleResponderRelease@[本机代码] invokeGuardedCallbackImpl@http://localhost:8081/index.bundle?platform=android&dev=true&minify=false:8997:21 调用GuardedCallback@http://localhost:8081/index.bundle?platform=android&dev=true&minify=false:9093:42 invokeGuardedCallbackAndCatchFirstError@http://localhost:8081/index.bundle?platform=android&dev=true&minify=false:9097:36 执行调度@http://localhost:8081/index.bundle?platform=android&dev=true&minify=false:9204:48 执行DispatchesInOrder@http://localhost:8081/index.bundle?platform=android&dev=true&minify=false:9224:26 执行DispatchesAndRelease@http://localhost:8081/index.bundle?platform=android&dev=true&minify=false:9329:35 forEach@[本机代码] forEachAccumulated@http://localhost:8081/index.bundle?platform=android&dev=true&minify=false:9319:22 runEventsInBatch@http://localhost:8081/index.bundle?platform=android&dev=true&minify=false:9353:27 runExtractedPluginEventsInBatch@http://localhost:8081/index.bundle?platform=android&dev=true&minify=false:9441:25 http://localhost:8081/index.bundle?platform=android&dev=true&minify=false:10467:42 批量更新$1@http://localhost:8081/index.bundle?platform=android&dev=true&minify=false:21921:20 批量更新@http://localhost:8081/index.bundle?platform=android&dev=true&minify=false:10415:36 _receiveRootNodeIDEvent@http://localhost:8081/index.bundle?platform=android&dev=true&minify=false:10466:23 接收触摸@http://localhost:8081/index.bundle?platform=android&dev=true&minify=false:10496:34 __callFunction@http://localhost:8081/index.bundle?platform=android&dev=true&minify=false:2650:49 http://localhost:8081/index.bundle?platform=android&dev=true&minify=false:2363:31 __guard@http://localhost:8081/index.bundle?platform=android&dev=true&minify=false:2604:15 callFunctionReturnFlushedQueue@http://localhost:8081/index.bundle?platform=android&dev=true&minify=false:2362:21 callFunctionReturnFlushedQueue@[本机代码]

有人熟悉将图片上传到 Firebase 吗?在本教程中,他们使用 uuid,但由于某种原因,当我尝试使用它时应用程序会中断,所以我将其省略了。这是对应的代码:

import React, Component from 'react';
import Platform, StyleSheet, Text, View, Image, Button, ScrollView, ImageBackground, Dimensions,TouchableOpacity,  FlatList,
  AsyncStorage from 'react-native';
import  Avatar, ListItem  from 'react-native-elements';
import Icon from 'react-native-vector-icons/FontAwesome';
import ImagePicker from 'react-native-image-picker';
import firebase from 'react-native-firebase';






const SCREEN_WIDTH = Dimensions.get("window").width;
const list = [
  
    title: '',
    icon: 'cake',
    url: 'ProfileSettings',
  ,


]

const options = 
  title: 'Select Image',
  storageOptions: 
    skipBackup: true,
    path: 'images'
  
;

const ImageRow = ( image, windowWidth, popImage ) => (
  <View>
    <Image
      source= uri: image 
      style=[styles.img,  width: windowWidth / 2 - 15 ]
      onError=popImage
    />
  </View>
);




class profileScreen extends Component 

  constructor(props)
    super(props);
    this.state = 
      first: '',
      place: '',
      province: '',
      uid: '',
      profileImg: '',
      email: '',
      imgSource: '',
      uploading: false,
      progress: 0,
      images: []

    




getUserData = (user) => 
  console.log(user);
  let ref = firebase.database().ref('Users/' + user);
  ref.on('value' , snapshot =>
      var state = snapshot.val();
      this.setState(
        first: state.firstname,
        place: state.place,
        province: state.province,
        uid: user,
        profileImg: state.profileImg,
        birthday: state.birthday,
        email: state.email,
        year: state.registered.split("-",1)
      )
    )




  componentDidMount()
    let user = firebase.auth().currentUser;
    console.log(user);
    console.log('test');
    this.getUserData(user.uid); 
    let images;
    AsyncStorage.getItem('images')
      .then(data => 
        images = JSON.parse(data) || [];
        this.setState(
          images: images
        );
      )
      .catch(error => 
        console.log(error);
      );
  

   /**
   * Select image method
   */
  pickImage = () => 
    ImagePicker.showImagePicker(options, response => 
      if (response.didCancel) 
        console.log('You cancelled image picker ????');
       else if (response.error) 
        alert('And error occured: ', response.error);
       else 
        const source =  uri: response.uri ;
        this.setState(
          imgSource: source,
          imageUri: response.uri
        );
        console.log(source);
      
    );
  ;
  /**
   * Upload image method
   */
  uploadImage = () => 
    const ext = this.state.imageUri.split('.').pop();      // Extract image extension
const filename = `unique image' + $ext`;             // Generate unique name
const imageRef = firebase.storage().ref('tutorials/images').child(filename +ext);
let mime = 'image/jpg';
imageRef.put(this.state.imageUri,  contentType: mime ).then((snapshot)=>
    console.log('Image uploaded successfully.')
).catch((error)=>
    console.log('Image uploading failed:' + error);
);

  ;
  /**
   * Remove image from the state and persistance storage
   */
  removeImage = imageIndex => 
    let images = this.state.images;
    images.pop(imageIndex);
    this.setState( images );
    AsyncStorage.setItem('images', JSON.stringify(images));
  ;



  render() 
    const  uploading, imgSource, progress, images  = this.state;
    const windowWidth = Dimensions.get('window').width;
    const disabledStyle = uploading ? styles.disabledBtn : ;
    const actionBtnStyles = [styles.btn, disabledStyle];
    return (
      <ScrollView  style=styles.scorllVert>
      <View style= alignItems: 'flex-start', justifyContent: 'center', marginBottom: 40 >
          <View style=styles.intro>

          <Text style=styles.introText>Hoi, ik ben this.state.first"\n"<Text style=styles.introTextSpan>Lid geworden in this.state.year</Text></Text>

             this.state.profileImg ?
                <Avatar size="large" rounded source=uri: this.state.profileImg, onPress=() => console.log("Works!") activeOpacity=0.7 />
                :
                <Avatar size="large" rounded title="GLR" onPress=() => console.log("Works!") activeOpacity=0.7 />
            



          </View>
          <View style=styles.divider>

          </View>
          <View style=styles.about>
           <Text style=styles.profileName>Over</Text>
            <View style=styles.aboutLiving>
              <Icon name='home'  style=styles.icon/>
              <Text style=styles.aboutText>Woont in this.state.place, this.state.province</Text>
            </View>
          </View>

          <View style=styles.divider>

          </View>
          <View style=styles.about>
           <Text style=styles.profileName>Door this.state.first  versterkt</Text>
            <View style=styles.aboutLiving>
              <Icon name='check-circle'  style=[styles.icon, styles.iconGreen]/>
              <Text style=styles.aboutText>E-mail adres</Text>
            </View>
          </View>

          <View style=styles.divider>

          </View>

          <View style=styles.about>
           <Text style=styles.profileName>Recente activiteiten</Text>
          <Text >N.v.t.</Text>

          <TouchableOpacity
              style=actionBtnStyles
              onPress=this.pickImage
              disabled=uploading
            >
              <View>
                <Text style=styles.btnTxt>Pick image</Text>
              </View>
            </TouchableOpacity>

            imgSource !== '' && (
              <View>
                <Image source=imgSource style=styles.image />
                uploading && (
                  <View
                    style=[styles.progressBar,  width: `$progress%` ]
                  />
                )
                <TouchableOpacity
                  style=actionBtnStyles
                  onPress=this.uploadImage
                  disabled=uploading
                >
                  <View>
                    uploading ? (
                      <Text style=styles.btnTxt>Uploading ...</Text>
                    ) : (
                      <Text style=styles.btnTxt>Upload image</Text>
                    )
                  </View>
                </TouchableOpacity>
              </View>
            )

            <View>
              <Text
                style=
                  fontWeight: '600',
                  paddingTop: 20,
                  alignSelf: 'center'
                
              >
                images.length > 0
                  ? 'Your uploaded images'
                  : 'There is no image you uploaded'
              </Text>
            </View>
            <FlatList
              numColumns=2
              style= marginTop: 20 
              data=images
              renderItem=( item: image, index ) => (
                <ImageRow
                  windowWidth=windowWidth
                  image=image
                  popImage=() => this.removeImage(index)
                />
              )
              keyExtractor=index => index
            />


          </View>





      </View>
      </ScrollView>

    );
  


  

  const styles = StyleSheet.create(
    profileName:
      fontWeight: 'bold',
      fontSize: 22,
      marginTop: 20,
    ,
    list:
      marginTop: 40,
      width: '100%'
    ,intro:
      flex: 1,
      flexDirection: 'row',
      flexWrap: 'wrap',
      alignItems: 'flex-start',
      padding: 25,
      marginBottom: 30,
      paddingTop: 80,
    ,
    introText:
      marginLeft: 0,
      marginRight: 50,
      fontSize: 22,
      fontWeight: "700",
      marginTop:15,
    ,
    introTextSpan:
      marginLeft: 0,
      marginRight: 40,
      fontSize: 15,
      fontWeight: "200",
      marginTop:50,
    ,
    divider:
      width: SCREEN_WIDTH-50,
      padding: 10,
      borderBottomColor: 'grey',
      borderBottomWidth: 0.5,
      marginTop: 10,
      marginLeft: 25
    ,
    about:
      paddingLeft: 25,
    ,
    aboutLiving:
      flexDirection: 'row',
      flexWrap: 'wrap',
      alignItems: 'flex-start',
      paddingTop: 10
    ,
    icon:
      fontSize: 18
    ,
    aboutText:
      marginLeft: 30
    ,
    iconGreen:
      color: 'green'
    
    ,
    button: 
        marginTop: 30,
        marginBottom: 20,
        paddingVertical: 10,
        alignItems: 'center',
        backgroundColor: '#019BB4',
        width: 300
    ,
    buttonText: 
        fontSize: 20,
        fontWeight: 'bold',
        color: '#fff'
    ,
    scorllVert:
      marginBottom: 40
    ,
    btn: 
      paddingLeft: 20,
      paddingRight: 20,
      paddingTop: 10,
      paddingBottom: 10,
      borderRadius: 20,
      backgroundColor: 'rgb(3, 154, 229)',
      marginTop: 20,
      alignItems: 'center'
    ,
    disabledBtn: 
      backgroundColor: 'rgba(3,155,229,0.5)'
    ,
    btnTxt: 
      color: '#fff'
    ,
    image: 
      marginTop: 20,
      minWidth: 200,
      height: 200,
      resizeMode: 'contain',
      backgroundColor: '#ccc',
    ,
    img: 
      flex: 1,
      height: 100,
      margin: 5,
      resizeMode: 'contain',
      borderWidth: 1,
      borderColor: '#eee',
      backgroundColor: '#ccc'
    ,
    progressBar: 
      backgroundColor: 'rgb(3, 154, 229)',
      height: 3,
      shadowColor: '#000',
    
  )



  export default profileScreen;

我对本机反应还很陌生,想上传图片,有没有人可以帮助我完成这项工作?即使有其他方法,我也愿意接受!

【问题讨论】:

【参考方案1】:

尝试将您的 uploadImage 函数包装在 try..catch 中,看看是否可以在 catch 中获得更清晰的错误消息

【讨论】:

【参考方案2】:

试试这个代码上传图片,

const ext = this.state.imageUri.split('.').pop();      // Extract image extension
const filename = `unique image' + $ext`;             // Generate unique name
const imageRef = firebase.storage().ref('tutorials/images).child(filename +ext);
let mime = 'image/jpg';
imageRef.put(this.state.imageUri,  contentType: mime ).then((snapshot)=>
    console.log('Image uploaded successfully.')
).catch((error)=>
    console.log('Image uploading failed');
);

【讨论】:

感谢您的帮助,但只有 1 个问题,imageRef.put( 之后的 imageUrl 来自哪里? 是同一个状态变量(imageUri)。我正在更新代码。 我用你的函数更新了上面的代码,但遗憾的是它没有上传图片并以“图片上传失败:错误:发生未知错误”结束 那么请在 Firebase 控制台的Rules 标签(第二个标签)下的Storage 部分检查您的规则。如果您未通过身份验证,默认规则不允许您编写任何内容。如果您不希望任何身份验证来写入访问权限,那么您只需将该行修改为 allow read, write; 规则全部允许:rules_version = '2'; 2 service firebase.storage 3 match /b/bucket/o 4 match /allPaths=** 5 allow read, write; 6 7 8

以上是关于使用 React Native 将图像上传到 Firebase的主要内容,如果未能解决你的问题,请参考以下文章

将图像路径转换为 ​​blob react native

在 react-native 中将图像上传到亚马逊 s3

如何将 React Native 应用程序上的本地图像文件上传到 Rails api?

将图像从 Firebase 存储链接到 Firestore 文档并在 React Native 中显示它们

在 React Native 中将图像上传到 Firebase 存储时出现错误 400 Bad Request

如何在 fetch 中传递 POST 参数以在 React Native 中将图像上传到服务器?