1 import ABI49_0_0ExpoModulesCore 2 import MessageUI 3 import CoreServices 4 import MobileCoreServices 5 import UniformTypeIdentifiers 6 7 struct ExpoSMSContext { 8 let promise: Promise 9 let smsDelegate: SMSDelegate 10 } 11 12 public class ExpoSMSModule: Module, SMSResultHandler { 13 private var smsContext: ExpoSMSContext? 14 private lazy var utils = appContext?.utilities 15 definitionnull16 public func definition() -> ModuleDefinition { 17 Name("ExpoSMS") 18 19 AsyncFunction("isAvailableAsync") { 20 return MFMessageComposeViewController.canSendText() 21 } 22 23 AsyncFunction("sendSMSAsync") { (addresses: [String], message: String, options: SMSOptions, promise: Promise) in 24 try sendSMSAsync(addresses: addresses, message: message, options: options, promise: promise) 25 }.runOnQueue(.main) 26 } 27 sendSMSAsyncnull28 private func sendSMSAsync(addresses: [String], message: String, options: SMSOptions, promise: Promise) throws { 29 if !MFMessageComposeViewController.canSendText() { 30 throw SMSUnavailableException() 31 } 32 33 if smsContext != nil { 34 throw SMSPendingException() 35 } 36 37 let smsDelegate = SMSDelegate(handler: self) 38 let context = ExpoSMSContext(promise: promise, smsDelegate: smsDelegate) 39 40 let messageComposeViewController = MFMessageComposeViewController() 41 messageComposeViewController.messageComposeDelegate = context.smsDelegate 42 messageComposeViewController.recipients = addresses 43 messageComposeViewController.body = message 44 45 for attachment in options.attachments { 46 let utiRef = UTTypeCreatePreferredIdentifierForTag( 47 kUTTagClassMIMEType, attachment.mimeType as CFString, nil) 48 49 if utiRef == nil { 50 throw SMSMimeTypeException(attachment.mimeType) 51 } 52 53 guard let url = URL(string: attachment.uri) else { 54 throw SMSUriException(attachment.uri) 55 } 56 57 do { 58 let data = try Data(contentsOf: url, options: .mappedIfSafe) 59 let attached = messageComposeViewController.addAttachmentData( 60 data, 61 typeIdentifier: attachment.mimeType, 62 filename: attachment.filename) 63 if !attached { 64 throw SMSFileException(attachment.uri) 65 } 66 } catch { 67 context.promise.reject(error) 68 return 69 } 70 } 71 72 smsContext = context 73 utils?.currentViewController()?.present(messageComposeViewController, animated: true, completion: nil) 74 } 75 onSuccessnull76 func onSuccess(_ data: [String: String]) { 77 guard let promise = smsContext?.promise else { 78 log.error("SMS context has been lost") 79 return 80 } 81 smsContext = nil 82 promise.resolve(data) 83 } 84 onFailurenull85 func onFailure(_ error: String) { 86 guard let promise = smsContext?.promise else { 87 log.error("SMS context has been lost") 88 return 89 } 90 smsContext = nil 91 promise.reject(SMSSendingException(error)) 92 } 93 } 94