You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Expo中MailComposer.composeAsync返回Promise未定义问题求助

问题:Expo MailComposer.composeAsync返回undefined,无法链式执行文件删除操作

我在Expo Snack开发Android应用,功能流程为:从网络下载.mobi文件 → 将文件附加到邮件草稿 → 删除该.mobi文件。但根据Expo文档,MailComposer.composeAsync(options)应返回包含MailComposerStatus的Promise,实际却始终拿到undefined,导致无法链式调用.then()执行后续的文件删除操作。

原代码

import React, { useState } from 'react';
import { Text, View, StyleSheet, Alert, Button } from 'react-native';
import Constants from 'expo-constants';
import * as FileSystem from 'expo-file-system';
import * as MailComposer from 'expo-mail-composer';


export default function App() {
 
const [stxt, setStxt] = useState("123");

  return (
    <View style={styles.container}>
      <Text style={styles.paragraph}>{stxt}</Text>
      <Text style={styles.paragraph}>{data}</Text>
      <Button title="Send" onPress={btnclicked}/>
    </View>
  );
}

let data = "outside app() const text";

const btnclicked = () => {
  FileSystem.downloadAsync('https://filesamples.com/samples/ebook/mobi/sample1.mobi',FileSystem.documentDirectory + 'test.mobi')
  .then(({ uri }) => {MailComposer.composeAsync({recipients:["test@gmail.com"], attachments:[uri]}); })
  .then(({ res }) => {console.log(res)} )
  .catch(error => {console.error(error);});
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    paddingTop: Constants.statusBarHeight,
    backgroundColor: '#ecf0f1',
    padding: 8,
  },
  paragraph: {
    margin: 24,
    fontSize: 30,
    fontWeight: 'bold',
    textAlign: 'center',
  },
});

问题原因

第一个.then()回调中,调用MailComposer.composeAsync()后没有返回该Promise对象,导致链式调用的下一个.then()接收到的是undefined,无法获取邮件操作状态。

修复方案

修改点:

  1. 在第一个.then()中返回MailComposer.composeAsync()的Promise,让链式调用能正确获取后续的状态值
  2. 使用FileSystem.deleteAsync()直接删除文件(若只需删除而非移动,比moveAsync更直接)
  3. 根据返回的status判断执行文件删除的时机(可根据需求调整逻辑)

修复后的代码

import React, { useState } from 'react';
import { Text, View, StyleSheet, Alert, Button } from 'react-native';
import Constants from 'expo-constants';
import * as FileSystem from 'expo-file-system';
import * as MailComposer from 'expo-mail-composer';


export default function App() {
 
const [stxt, setStxt] = useState("123");

  return (
    <View style={styles.container}>
      <Text style={styles.paragraph}>{stxt}</Text>
      <Text style={styles.paragraph}>{data}</Text>
      <Button title="Send" onPress={btnclicked}/>
    </View>
  );
}

let data = "outside app() const text";
const filePath = `${FileSystem.documentDirectory}test.mobi`; // 提取文件路径为变量,方便复用

const btnclicked = () => {
  FileSystem.downloadAsync('https://filesamples.com/samples/ebook/mobi/sample1.mobi', filePath)
  // 关键:返回MailComposer的Promise
  .then(({ uri }) => {
    return MailComposer.composeAsync({
      recipients: ["test@gmail.com"],
      attachments: [uri]
    });
  })
  .then(({ status }) => {
    console.log('邮件操作状态:', status);
    // 无论用户操作结果如何,都删除文件(可根据需求调整,比如仅在sent/saved时删除)
    return FileSystem.deleteAsync(filePath);
  })
  .then(() => {
    console.log('文件已成功删除');
  })
  .catch(error => {
    console.error('操作出错:', error);
    // 出错时也尽量清理文件
    FileSystem.deleteAsync(filePath).catch(err => console.error('删除失败:', err));
  });
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    paddingTop: Constants.statusBarHeight,
    backgroundColor: '#ecf0f1',
    padding: 8,
  },
  paragraph: {
    margin: 24,
    fontSize: 30,
    fontWeight: 'bold',
    textAlign: 'center',
  },
});

说明

修复后,你可以通过status值判断邮件操作结果:

  • MailComposerStatus.SENT:邮件已发送
  • MailComposerStatus.SAVED:邮件已保存为草稿
  • MailComposerStatus.CANCELLED:用户取消了邮件操作
  • MailComposerStatus.UNKNOWN:状态未知

你可以根据业务需求调整文件删除的触发条件,比如仅在邮件成功发送/保存后删除文件。

内容的提问来源于stack exchange,提问作者difoxy2

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 20:15:43