How to launch the iOS mail app in Swift? - ios

I'm creating an iOS application with a password reset feature that sends an email to the user. After sending the email I want to display a UIAlertController to the user asking them if they would like to open the mail application.
I've seen various posts on here along the lines of:
let url = NSURL(string: "mailto:")
UIApplication.sharedApplication().openURL(url!)
This works but unfortunately it starts a new message which is not what I want. I only want to launch the application so the user can see their inbox.

Not tested myself but maybe this answer will help you:
Apparently Mail supports a second url scheme message:// which (I suppose) allows you to open a specific message if it was fetched by your application. If you do not provide a full message url, it will just open Mail:
let mailURL = URL(string: "message://")!
if UIApplication.shared.canOpenURL(mailURL) {
UIApplication.shared.openURL(mailURL)
}
Taken from: Launch Apple Mail App from within my own App?

The Swift 3.0.1 way of just opening the Mail app goes as follows:
private func openMailClient() {
let mailURL = URL(string: "message://")!
if UIApplication.shared.canOpenURL(mailURL) {
UIApplication.shared.openURL(mailURL)
}
}
As "dehlen" correctly stated, using the message:// scheme will only open the mail app, if no further information is provided.

Obviously a few years later...I had to add a completion handler for Xcode 10.2.1 swift 5.
This works perfectly-
let emailURL = NSURL(string: "message://")!
if UIApplication.shared.canOpenURL(emailURL as URL)
{
UIApplication.shared.open(emailURL as URL, options: [:],completionHandler: nil)
}

Since UIApplication.shared.openURL() method has been deprecated and we can use URL() directly in place of NSURL(), the updated version of this question's answer is:
let mailURL = URL(string: "message://")!
if UIApplication.shared.canOpenURL(mailURL) {
UIApplication.shared.open(mailURL, options: [:], completionHandler: nil)
}

This will work with Xcode 11.5:
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
switch indexPath.row {
case 5:
openEmailApp(email: "email#gmail.com")
default:
break
}
}
func openEmailApp(email: String) {
if let url = URL(string: "mailto: \(email)") {
UIApplication.shared.open(url)

Related

ios 11 imessage extension message.url does not open safari

I'm adding an iMessage extension target to my app. The extension is supposed to send a message that has a url attribute. The behaviour I'm expecting when a user touches the message is to open the browser using the url attribute of the message.
I have a button in my messageView which executes this code:
#IBAction func labelButton(_ sender: Any) {
let layout = MSMessageTemplateLayout()
layout.imageTitle = "iMessage Extension"
layout.caption = "Hello world!"
layout.subcaption = "Test sub"
guard let url: URL = URL(string: "https://google.com") else { return }
let message = MSMessage()
message.layout = layout
message.summaryText = "Sent Hello World message"
message.url = url
activeConversation?.insert(message, completionHandler: nil)
}
If I touch the message, it expands the MessageViewController
I have then added this:
override func didSelect(_ message: MSMessage, conversation: MSConversation) {
if let message = conversation.selectedMessage {
// message selected
// Eg. open your app:
self.extensionContext?.open(message.url!, completionHandler: nil)
}
}
And now, when I touch the message, it opens my main app but still not my browser.
I have seen on another post (where I cannot comment, thus I opened this post) that it is impossible to open in Safari but I have a news app which inserts links to articles and allows with a click on the message to open the article in a browser window, while the app is installed.
So, can someone please tell how I can proceed to force opening the link in a browser window?
Thank you very much.
Here is a trick to insert a link in a message. It does not allow to create an object that has an url attribute but just to insert a link directly which will open in the default web browser.
activeConversation?.insertText("https://google.com", completionHandler: nil)
I have published a sample on github showing how to launch a URL from inside an iMessage extension. It just uses a fixed URL but the launching code is what you need.
Copying from my readme
The obvious thing to try is self.extensionContext.open which is documented as Asks the system to open a URL on behalf of the currently running app extension.
That doesn't work. However, you can iterate back up the responder chain to find a suitable handler for the open method (actually the iMessage instance) and invoke open with that object.
This approach works for URLs which will open a local app, like settings for a camera, or for web URLs.
The main code
#IBAction public func onOpenWeb(_ sender: UIButton) {
guard let url = testUrl else {return}
// technique that works rather than self.extensionContext.open
var responder = self as UIResponder?
let handler = { (success:Bool) -> () in
if success {
os_log("Finished opening URL")
} else {
os_log("Failed to open URL")
}
}
let openSel = #selector(UIApplication.open(_:options:completionHandler:))
while (responder != nil){
if responder?.responds(to: openSel ) == true{
// cannot package up multiple args to openSel so we explicitly call it on the iMessage application instance
// found by iterating up the chain
(responder as? UIApplication)?.open(url, completionHandler:handler) // perform(openSel, with: url)
return
}
responder = responder!.next
}
}

Open URL from UIButton in CollectionViewCell

I have a UIButton in my UICollectionViewCell and it's getting data from JSON. Now I need to open a URL from each button (each button have a different url that also comes from JSON).
I managed to open the URL with:
let weburl = "http://example.com"
UIApplication.shared.openURL(URL(string: weburl)!)
But now I need to kinda pass an url to each button. Any ideas of how can i achieve this?
You can have an array of urls:
let urls = [url1, url2, ...]
And then assign the tag property of each button to the index of its corresponding url. Now you can easily manage what you want:
#IBAction func handleTouch(_ sender: UIButton) {
// assumes that the buttons' tags start at 0, which isn't a good idea.
// see #rmaddy comment bellow
let url = urls[sender.tag]
// use the version of the open method shown bellow because the other one becomes deprecated in iOS 10
UIApplication.shared.open(URL(string: url)!, options: [:], completionHandler: nil)
}
EDIT
Other solution would be to just store the url in the cell itself, and in the button handler open the url corresponding to its cell.
FYI openURL is deprecated in iOS 10. I suggest the following if you need to support older versions of ios:
let url = URL(string: "alexa://")!
if #available(iOS 10, *) {
UIApplication.shared.open(url, options: [:], completionHandler: {
(success) in
guard success else {
//Error here
}
//Success here
})
} else {
if let success = UIApplication.shared.openURL(url) {
//Success here
} else {
//Error here
}
}
Otherwise just use UIApplication.shared.open. Also I would add a URL field to the data model you are passing to your tableViewCell and just look up the URL from the model.

Call phone action don't work in swift

Hello I've button action for call number , but when I used it don't call and nothing shows.
My codes under below.
#IBAction func callPhone(sender: AnyObject) {
UIApplication.shared().canOpenURL((NSURL(string: "tel://1234567890")! as URL))
}
Thank You !
Proper Swift 3.0 Code
if let url = URL(string: "tel://\(phoneNumber)") {
UIApplication.shared().open(url, options: [:], completionHandler: nil)
}
In Swift 3.0 NSURL have changed to URL. And sharedApplciation changed to shared. Also OpenURL changed to open, they have added a bunch other parameters to the openmethod, you can pass empty dictionary in options and nil in the completionHandler.
Please try following code it's use to solve your problem.
if let url = NSURL(string: "tel://\(1234567890)") {
UIApplication.sharedApplication().openURL(url)
}
Try this answer.
#IBAction func callPhone(sender: AnyObject) {
if let url = NSURL(string: "tel://9069118117") {
UIApplication.sharedApplication().openURL(url)
}
}
please note that:
tel:// try to call direct the phone number;
telprompt:// shows you an alert to confirm call
as of iOS 10 openUrl is deprecated;
#available(iOS, introduced: 2.0, deprecated: 10.0, message: "Please use openURL:options:completionHandler: instead")
open func openURL(_ url: URL) -> Bool
so i advice to use this code block to support also iOS < 9:
if #available(iOS 10, *) {
UIApplication.shared.open(yourURL)
// if you need completionHandler:
//UIApplication.shared.open(yourURL, completionHandler: { (aBool) in })
// if you need options too:
//UIApplication.shared.open(yourURL, options: [:], completionHandler: { (aBool) in })
} else {
UIApplication.shared.openURL(number)
}
Latest Xcode , Latest Swift working codes.
use telprompt:// not tel
let myphone = "+134345345345"
if let phone = URL(string:"telprompt://\(myphone)"), UIApplication.shared.canOpenURL(url) {
UIApplication.shared.openURL(url)
}

How to open Facebook Messenger and direct to someone?

I have FBSDK already and can use FBSDKShareKit send something on Messenger.
I want just open a chat with someone in Facebook Messenger. like this:
Click a button in my app(sample: Facebook app):
http://i.imgur.com/j60P3Ng.png
Go to Facebook Messenger and open a chat with this person:
http://i.imgur.com/yU0EXKF.png
How Can I do it?
Swift 4
UI
In my app I show a user's Facebook ID as a button:
Code
#IBAction func messengerButton(_ sender: UIButton) {
if let id = sender.titleLabel?.text {
if let url = URL(string: "fb-messenger://user-thread/\(id)") {
// Attempt to open in Messenger App first
UIApplication.shared.open(url, options: [:], completionHandler: {
(success) in
if success == false {
// Messenger is not installed. Open in browser instead.
let url = URL(string: "https://m.me/\(id)")
if UIApplication.shared.canOpenURL(url!) {
UIApplication.shared.open(url!)
}
}
})
}
}
}
User's Facebook ID
The user can get another person's Facebook ID from looking them up on Facebook and then observing the URL:
I found a solution with URL Scheme:
let userID = 4
let urlStr = String(format: "fb-messenger://user-thread/%d", userID)
let theUrl = NSURL(string: urlStr)
[UIApplication.sharedApplication() .openURL(theUrl!)]
This code will open Message application and talk to Mark.
in swift 5.1, use
guard let messenger = URL(string: "fb-messenger://user-thread/your_id") else { return }
UIApplication.shared.open(messenger)

Open Gmail app from my app

I'm trying to send an email from my app. But what I want is if user is having Gmail app on his/her phone, then mail should be sent using it. If Gmail app is unavailable then the user should be redirected to Mailbox.
So how can I know if user contains Gmail app and how can I redirect user to it.
Setup for iOS9+
As explained here, if you're on iOS9+, don't forget to add googlegmail to LSApplicationQueriesSchemes on your info.plist
Code to open GMail
Then, you can do the same as the accepted answer (below is my swift 2.3 version):
let googleUrlString = "googlegmail:///co?subject=Hello&body=Hi"
if let googleUrl = NSURL(string: googleUrlString) {
// show alert to choose app
if UIApplication.sharedApplication().canOpenURL(googleUrl) {
if #available(iOS 10.0, *) {
UIApplication.sharedApplication().openURL(googleUrl, options: [:], completionHandler: nil)
} else {
UIApplication.sharedApplication().openURL(googleUrl)
}
}
}
You need to use custom URL Scheme. For gmail application its:
googlegmail://
If you want to compose a message there you can add more parameters to this URL:
co?subject=Example&body=ExampleBody
You can determinate if any kind of application is installed using this code (just replace customURL obviously for an other apps):
NSString *customURL = #"googlegmail://";
if ([[UIApplication sharedApplication]
canOpenURL:[NSURL URLWithString:customURL]])
{
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:customURL]];
}
else
{
//not installed, show popup for a user or an error
}
For Swift 3.0+
Notes:
This solution shows how to use spaces or newlines in the arguments to the URL (Gmail may not respect the newlines).
It is NOT necessary to register with LSApplicationQueriesSchemes as long as you don't call canOpenURL(url). Just try and use the completion handler to determine if it succeeded.
let googleUrlString = "googlegmail:///co?to=\(address.addingPercentEncoding(withAllowedCharacters: .alphanumerics) ?? "")&subject=\(subject.addingPercentEncoding(withAllowedCharacters: .alphanumerics) ?? "")&body=\(buildInfo.addingPercentEncoding(withAllowedCharacters: .alphanumerics) ?? "")"
if let googleUrl = URL(string: googleUrlString) {
UIApplication.shared.open(googleUrl, options: [:]) {
success in
if !success {
// Notify user or handle failure as appropriate
}
}
}
else {
print("Could not get URL from string")
}
I couldn't figure out why this wasn't working for me until I realised I was targetting a info_development.plist instead of the production-file info.plist
If you're like me and happen to have multiple Plists (one for development, one for prod etc) make sure you edit it everywhere. ;-)
Swift 5
These answers can open gmail but what if the user do not have gmail installed in the device? In that case I have handled opening apple mail/outlook/yahoo/spark. If none of them are present, I am showing an alert.
#IBAction func openmailAction() {
if let googleUrl = NSURL(string: "googlegmail://") {
openMail(googleUrl)
} else if let mailURL = NSURL(string: "message://") {
openMail(mailURL)
} else if let outlookURL = NSURL(string: "ms-outlook://") {
openMail(outlookURL)
} else if let yahooURL = NSURL(string: "ymail://") {
openMail(yahooURL)
} else if let sparkUrl = NSURL(string: "readdle-spark://") {
openMail(sparkUrl)
} else {
// showAlert
}
}
func openMail(_ url: NSURL) {
if UIApplication.shared.canOpenURL(url as URL) {
UIApplication.shared.open(url as URL, options: [:], completionHandler: nil)
}
}
You might also may have to add this in the plist
<key>LSApplicationQueriesSchemes</key>
<array>
<string>googlegmail</string>
<string>ms-outlook</string>
<string>readdle-spark</string>
<string>ymail</string>
</array>

Resources