Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React native - send photo per mail

Tags:

react-native

i am trying to send a recently in app - captured photo by mail and am encountering the following error:

(for the mailing functionality i am using this module : var Mailer = require('NativeModules').RNMail;

I am trying to send a photo by mail with the help of this module and get the following error:

index.ios.bundle:28842Exception '-[MFMailComposeInternalViewController addAttachmentData:mimeType:fileName:] attachment must not be nil.' was thrown while invoking mail on target RNMail with params (
        {
        attachment =         {
            name = Ladunek;
            path = "assets-library://asset/asset.JPG?id=3B7DBB2E-1271-4D86-A5F2-A0CEEE7CC4DE&ext=JPG";
            type = jpg;
        };
        body = "body";
        isHTML = 1;
        recipients =         (
            "[email protected]"
        );
        subject = Ladunek;
    },
    9
)

This is the invoking code :

.then((data, path) => {
        console.log(data)
        console.log(data.path)
        Mailer.mail({
          subject: 'Ladunek',
          recipients: ['[email protected]'],
          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 [email protected]');
            }
        });
      })

Is the path invalid? Or might it be something else.

EDIT

I am obtaining the file path with this module react-native-camera like so:

Event:

takePicture() {
    this.camera.capture()
      .then((data, path) =>

Element:

<Camera
              ref={(cam) => {
                this.camera = cam;
              }}
              style={{
                    flex: 1,
                    justifyContent: 'flex-end',
                    alignItems: 'center',
                    height: 400,
                    width: Dimensions.get('window').width
                  }}
              aspect={Camera.constants.Aspect.fill}>
              <Text style={{
                        flex: 0,
                        backgroundColor: '#fff',
                        borderRadius: 5,
                        color: '#000',
                        padding: 10,
                        margin: 40
                      }} onPress={this.takePicture.bind(this)}>{cameraIcon}</Text>
            </Camera>

UPDATE2

After including an obj-c file for uri to path transformation I am receiving the following error now:

ExceptionsManager.js:76 JSON value '<null>' of type NSNull cannot be converted to NSString

Did I "remove" the wrong lines from the following code? :/

Obj-c File content:

#import "RCTBridgeModule.h"
#import <AssetsLibrary/AssetsLibrary.h>
#import <UIKit/UIKit.h>
@interface ReadImageData : NSObject <RCTBridgeModule>
@end

@implementation ReadImageData

RCT_EXPORT_MODULE();

RCT_EXPORT_METHOD(readImage:(NSString *)input callback:(RCTResponseSenderBlock)callback)
{

  // Create NSURL from uri
  NSURL *url = [[NSURL alloc] initWithString:input];

  // Create an ALAssetsLibrary instance. This provides access to the
  // videos and photos that are under the control of the Photos application.
  //ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];

  // Using the ALAssetsLibrary instance and our NSURL object open the image.
  //[library assetForURL:url resultBlock:^(ALAsset *asset) {

    // Create an ALAssetRepresentation object using our asset
    // and turn it into a bitmap using the CGImageRef opaque type.
    //CGImageRef imageRef = [asset thumbnail];

    // Create UIImageJPEGRepresentation from CGImageRef
   // NSData *imageData = UIImageJPEGRepresentation([UIImage imageWithCGImage:imageRef], 0.1);

    // Convert to base64 encoded string
    // NSString *base64Encoded = [imageData base64EncodedStringWithOptions:0];

    callback(@[url]);

  //} failureBlock:^(NSError *error) {
    //NSLog(@"that didn't work %@", error);
  //}];



}
@end
like image 820
noa-dev Avatar asked Jul 01 '16 09:07

noa-dev


People also ask

How to send an email in React Native?

Another, more robust approach to sending emails in React Native will be with external third-party services. Instead of launching a user’s email app to send an email, we’ll start sending emails to users in the background. These can be registration emails, password resets or anything else that makes sense to be sent once triggered.

How to upload file/image to server with form data in React Native?

How to Upload File/Image to Server with Form Data in React Native 1 Uploading File in React Native 2 To Make a React Native App 3 Installation of Dependency 4 Linking of Dependency 5 CocoaPods Installation 6 Code for the File Upload in React Native 7 Server Side PHP Code 8 To Run the React Native App 9 Output Screenshots More ...

How do I use Expo for React Native with express?

We do this using Expo for React Native, and that’s it, no third party packages or native bridges — just the official modules of Expo. As a backend we simply use Node.js with Express, where we receive the image converted to base64 via a Post Request and save it directly to our server as an image file using the FileSystem Module (fs). Here we go:

How to make a react native app with npm?

We are going to use react-native init to make our React Native App. Assuming that you have node installed, you can use npm to install the react-native-cli command line utility. Open the terminal and go to the workspace and run


1 Answers

------ 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:

enter image description here

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:

enter image description here enter image description here

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: ['[email protected]'],
          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 [email protected]');
            }
        })
      })
      .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

like image 94
Antoni4 Avatar answered Sep 27 '22 02:09

Antoni4