且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

React Native - 每封邮件发送照片

更新时间:2022-11-27 18:15:08

------ EDITED ANSWER BELOW ------

Okay, so I finally have a Mac and was able to look into this issue in more details.

This is what I found for both Android and iOS.

The assumption is that you are using react-native-camera together with react-native-mail

- 1: Absolute Path

Add property captureTarget={Camera.constants.CaptureTarget.disk} to Camera component like so:

<Camera
  captureTarget={Camera.constants.CaptureTarget.disk}
  ref={(cam) => {
    this.camera = cam;
  }}
  style={styles.preview}
  aspect={Camera.constants.Aspect.fill}>
  <Text style={styles.capture} onPress={this.takePicture.bind(this)}>[CAPTURE]</Text>
</Camera>

Now camera component should return absolute file path instead of uri.

So for Android you should see something like this:

"file:///storage/emulated/0/Pictures/RCTCameraModule/IMG_20160730_060652.jpg"

instead of:

"content://media/external/images/media/86"

and for iOS you should get something like this:

"/Users/anton/Library/Developer/CoreSimulator/Devices/9A15F203-9A58-41C5-A4FC-EA25FAAE92BD/data/Containers/Data/Application/79FF93F9-BA89-4F4C-8809-277BEECD447D/Documents/EFFF0ECE-4063-4FE5-984E-E76506788350.jpg"

instead of:

"assets-library://asset/asset.JPG?id=0058FA4A-268F-408A-9150-017A3DA368D2&ext=JPG"

- 2: Pitfalls

iOS:

If Apple's MFMailComposeViewController crashes and you see the following error message:

This is most likely because you are running the app on iOS 9 Simulator. Solution: either test the app on real device, or download an older Simulator such as iOS 8.4.

More information on this issue can be found here

Android:

As of this writing there is no attachment support for Android.

Solution: (PR has been made to add this feature, but if you can't wait)

Add the following code to file RNMAILModule.java

if (options.hasKey("attachment") && !options.isNull("attachment")) {
  i.putExtra(Intent.EXTRA_STREAM, Uri.parse(options.getMap("attachment").getString("path")));
}

When both Android and iOS work you should have something like this:

And here is the working code:

var Mailer = require('NativeModules').RNMail;
import Camera from 'react-native-camera';

import React, {Component} from 'react';
import
{
  View,
  TouchableHighlight,
  Text,
  StyleSheet,
  Dimensions,
  CameraRoll
}
from 'react-native';

const styles = StyleSheet.create({
  container: {
    flex: 1
  },
  preview: {
    flex: 1,
    justifyContent: 'flex-end',
    alignItems: 'center',
    height: Dimensions.get('window').height,
    width: Dimensions.get('window').width
  },
  capture: {
    flex: 0,
    backgroundColor: '#fff',
    borderRadius: 5,
    color: '#000',
    padding: 10,
    margin: 40
  }
});

class SendPhoto extends Component {
  takePicture() {
    this.camera.capture()
      .then((data) => {
        console.log(data.path)
        Mailer.mail({
          subject: 'Ladunek',
          recipients: ['placeholder@mail.com'],
          body: 'body',
          isHTML: true, // iOS only, exclude if false
          attachment: {
            path: data.path,  // The absolute path of the file from which to read data.
            type: 'jpg',   // Mime Type: jpg, png, doc, ppt, html, pdf
            name: 'Ladunek',   // Optional: Custom filename for attachment
          }
        }, (error, event) => {
            if(error) {
              AlertIOS.alert('Error', 'Could not send mail. Please send a mail to support@example.com');
            }
        })
      })
      .catch(err => console.error(err));
  }

  render() {
    return(
      <View>
        <View style={styles.container}>
          <Camera
            captureTarget={Camera.constants.CaptureTarget.disk}
            ref={(cam) => {
              this.camera = cam;
            }}
            style={styles.preview}
            aspect={Camera.constants.Aspect.fill}>
            <Text style={styles.capture} onPress={this.takePicture.bind(this)}>[CAPTURE]</Text>
          </Camera>
        </View>
      </View>
    );
  }
}
export default SendPhoto;

------ OLD ANSWER BELOW ------

I never used this module before, but it looks like it expects absolute path of the file, however you are providing a file uri.

How are you obtaining this file uri?

Try using react-native-get-real-path module to see if it helps, you can find it here: react-native-get-real-path

i.e. convert your file uri to obtain real path, and use that as path