Save remote image to camera roll in React Native?

2020-06-19 04:34发布

问题:

I'm getting nothing but errors from the ReactNative CameraRoll's saveImageWithTag function. Saving a local image with something like:

CameraRoll.saveImageWithTag('./path/to/myimage.png');
      .then(res => console.log(res))
      .catch(err => console.log(err));

gives me the error:

Error: The file “myimage.png” couldn’t be opened because there is no such file.(…)

./path/to/myimage.png in this case is the path I'd use to require an image for an Image source. What should the full path be for a local image be? Do I need to store them differently to make them accessible?

回答1:

0. Short answer

Use RNFS to locate the local image.

1. For your title 'Save remote image to camera roll in React Native'

The keyword is remote.

Before using CameraRoll, we should link the library first.

Then, I create one Image and one Button:

  render: function() {
    return (
      <View style={styles.container}>
          <Image ref="logoImage"
            style={{ height:50, width: 50 }}
            source={{uri: 'http://facebook.github.io/react/img/logo_og.png'}}
          />
          <TouchableHighlight style={styles.button} onPress={this._handlePressImage} underlayColor='#99d9f4'>
            <Text style={styles.buttonText}>Save Image</Text>
          </TouchableHighlight>
      </View>
    );
  },

When I press the button, the program will save the image to camera roll:

  _handlePressImage: function() {
    console.log('_handlePressImage.');

    var uri = this.refs.logoImage.props.source;
    console.log(uri);
    CameraRoll.saveImageWithTag(uri, function(result) {
      console.log(result);
    }, function(error) {
      console.log(error);
    });
  },

React Native warns me that the API is deprecated, just use promise instead:

var promise = CameraRoll.saveImageWithTag(uri);
promise.then(function(result) {
  console.log('save succeeded ' + result);
}).catch(function(error) {
  console.log('save failed ' + error);
});

Now, we can see the logo image in our camera roll.

2. For your real problem in your content

Despite your title says remote, your code uses the local path.

Give the path './path/to/myimage.png', I assume that the image path is relative to the .js file. That is, your image is not relative to the final running app, so it can not find the image file.

Now change the Image to use local file:

<Image ref="logoImage"
  style={{ height:50, width: 50 }}
  source={require('./logo_og.png')}
/>

and save the image like this:

var promise = CameraRoll.saveImageWithTag('./logo_og.png');

which results in:

Because CameraRoll API is corresponding to the Native Component, which belongs to the final running app, not the javascript.

3. Use RNFS to save local images

First run the command below:

npm install react-native-fs --save

and then link the library.

After Putting the image under Library/Caches:

we can save the local image:

var cacheImagePath = RNFS.CachesDirectoryPath+"/logo_og.png";
console.log(cacheImagePath);
var promise = CameraRoll.saveImageWithTag(cacheImagePath);
promise.then(function(result) {
  console.log('save succeeded ' + result);
}).catch(function(error) {
  console.log('save failed ' + error);
});

Thanks.



回答2:

Use this saveToCameraRoll method.

import { CameraRoll } from 'react-native';

 CameraRoll.saveToCameraRoll(url)
    .then(alert('Done', 'Photo added to camera roll!')) 
    .catch(err => console.log('err:', err))
}

The user's permission is required in order to access the Camera Roll on devices running iOS 10 or later. Add the NSPhotoLibraryUsageDescription key in your Info.plist with a string that describes how your app will use this data. This key will appear as Privacy - Photo Library Usage Description in Xcode. If you are targeting devices running iOS 11 or later, you will also need to add the NSPhotoLibraryAddUsageDescription key in your Info.plist.