I am trying to implement MFMailComposeViewController() in two cells (Subject "feedback"and "feedback2").
When I select each cell, "feedback" works well, but "feedback2" is not called.
It seems not difficult issue but I find it difficult to fix the problem.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
if indexPath.row == 0 {
let message = "hey download this app"
let shareView = UIActivityViewController(activityItems: [message], applicationActivities: nil)
self.present(shareView, animated: true, completion: nil)
} else if indexPath.row == 1 {
let mailCompose = MFMailComposeViewController()
mailCompose.mailComposeDelegate = self
mailCompose.setToRecipients(["gmail.com"])
mailCompose.setSubject("feedback")
mailCompose.setMessageBody("text", isHTML: false)
if MFMailComposeViewController.canSendMail()
{
self.present(mailCompose, animated: true, completion: nil)
} else if indexPath.row == 2 {
let mailCompose = MFMailComposeViewController()
mailCompose.mailComposeDelegate = self
mailCompose.setToRecipients(["ba#mail.com"])
mailCompose.setSubject("feedback2")
mailCompose.setMessageBody("text", isHTML: false)
if MFMailComposeViewController.canSendMail()
{
self.present(mailCompose, animated: true, completion: nil)
}
else{
print("error...!")
}
}
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
controller.dismiss(animated: true, completion: nil)
}
Your else if indexPath.row == 2 is indented one level too deeply – its else refers to !MFMailComposeViewController.canSendMail(), not the previous indexPath check. You'll need to shift that branch outwards one level to get the effect you want.
For the future, it might be easier to debug if you refactor out a single method for all your mail-composing:
private func sendMail(to recipient: String, subject: String) {
if !MFMailComposeViewController.canSendMail() {
return
}
let mailCompose = MFMailComposeViewController()
mailCompose.mailComposeDelegate = self
mailCompose.setToRecipients([recipient])
mailCompose.setSubject(subject)
mailCompose.setMessageBody("text", isHTML: false)
self.present(mailCompose, animated: true, completion: nil)
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
switch indexPath.row {
case 0: /* activity view controller stuff */ break;
case 1:
sendMail(to: "gmail.com", subject: "feedback")
break;
case 2:
sendMail(to: "ba#mail.com", subject: "feedback2")
break;
}
}
Related
I have small problem. I'm using MFMailComposeViewController to send email after work. So I have var allRuns, and I've printed that var in few places, and it always show value = 3. But in my MailViewController into MessageBody it's equal 0/nil (I've set 0). If it is important- I'm taking var from Firebase, but earlier in the app. Where should I seek problem? That's some code below.
MailViewController:
import UIKit
import MessageUI
class MailViewController: UIViewController, MFMailComposeViewControllerDelegate {
let av = ActualValues()
override func viewDidLoad() {
super.viewDidLoad()
}
//MARK: - Buttons
#IBAction func emailButtonTapped(_ sender: UIButton) {
showMailComposer()
}
#IBAction func backButtonTapped(_ sender: UIButton) {
self.dismiss(animated: true, completion: nil)
}
//MARK: -Func
func showMailComposer() {
if MFMailComposeViewController.canSendMail() {
let mailComposer = MFMailComposeViewController()
mailComposer.mailComposeDelegate = self
mailComposer.setToRecipients(["paereson#gmail.com"])
mailComposer.setSubject("Work of \(av.currentDate())")
mailComposer.setMessageBody("All runs: \(av.allRuns)", isHTML: false)
present(mailComposer, animated: true, completion: nil)
}
}
func mailComposeController(_ controller: MFMailComposeViewController,
didFinishWith result: MFMailComposeResult, error: Error?) {
if let _ = error {
//show alert
controller.dismiss(animated: true, completion: nil)
return
}
switch result {
case .cancelled:
print("Cancelled")
case .failed:
print("Failed")
case .saved:
print("saved")
case .sent:
print("Email sent")
#unknown default:
print("default")
}
controller.dismiss(animated: true, completion: nil)
}
}
Few lines in av = ActualValuse:
var allRuns: Int = 0
var runs: Array? = []
//All runs
func allRunsFunc() {
let ref1 = ref.child("\(currentYear())/\(currentMonth())/\(currentDay())")
ref1.observeSingleEvent(of: .value) { (snapshot) in
if let snapshots = snapshot.children.allObjects as? [DataSnapshot] {
self.allRuns = snapshots.count as Int
}
}
}
EDIT:
Should I use segue before MFMAilComposeViewController? If yes, how should I configure it?
import UIKit
import MessageUI
class MailViewController: UIViewController, MFMailComposeViewControllerDelegate {
let av = ActualValues()
override func viewDidLoad() {
super.viewDidLoad()
}
//MARK: - Buttons
#IBAction func emailButtonTapped(_ sender: UIButton) {
showMailComposer()
}
#IBAction func backButtonTapped(_ sender: UIButton) {
self.dismiss(animated: true, completion: nil)
}
//MARK: -Func
func showMailComposer() {
if MFMailComposeViewController.canSendMail() {
let mailComposer = MFMailComposeViewController()
mailComposer.mailComposeDelegate = self
mailComposer.setToRecipients(["paereson#gmail.com"])
mailComposer.setSubject("Work of \(av.currentDate())")
mailComposer.setMessageBody("\(av.exportText())", isHTML: true)
present(mailComposer, animated: true, completion: nil)
}
}
func mailComposeController(_ controller: MFMailComposeViewController,
didFinishWith result: MFMailComposeResult, error: Error?) {
if let _ = error {
//show alert
controller.dismiss(animated: true, completion: nil)
return
}
switch result {
case .cancelled:
print("Cancelled")
case .failed:
print("Failed")
case .saved:
print("saved")
case .sent:
print("Email sent")
#unknown default:
print("default")
}
controller.dismiss(animated: true, completion: nil)
}
func configureMail(model: ActualValues) {
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.destination is MFMailComposeViewController {
let vc = segue.destination as? MFMailComposeViewController
vc?.configureMail(model: av)
}
}
}
You seem to be missing the execution of allRunsFunc function. Maybe call it in the ActualValue init method.
I Implements SiriShortcut with Intent in my App.
I set up a button "Add to Siri" with the code that Apple give here : https://developer.apple.com/documentation/sirikit/inuiaddvoiceshortcutviewcontroller
func addSiriButton(to view: UIView) {
let button = INUIAddVoiceShortcutButton(style: .blackOutline)
button.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(button)
view.centerXAnchor.constraint(equalTo: button.centerXAnchor).isActive = true
view.centerYAnchor.constraint(equalTo: button.centerYAnchor).isActive = true
button.addTarget(self, action: #selector(addToSiri(_:)), for: .touchUpInside)
}
// Present the Add Shortcut view controller after the
// user taps the "Add to Siri" button.
#objc
func addToSiri(_ sender: Any) {
if let shortcut = INShortcut(intent: ProjectorOnIntent()) {
let viewController = INUIAddVoiceShortcutViewController(shortcut: shortcut)
viewController.modalPresentationStyle = .formSheet
viewController.delegate = self as? INUIAddVoiceShortcutViewControllerDelegate // Object conforming to `INUIAddVoiceShortcutViewControllerDelegate`.
present(viewController, animated: true, completion: nil)
}
}
But once I record a phrase when I click on the "Ok" button the view won't dismiss.
The error I got in the console :
2018-10-12 10:16:51.985156+0200 AppName[1029:172350] [default] No results found for query: {(
<_LSApplicationIsInstalledQuery: 0x28226e560>
)}
2018-10-12 10:16:51.989467+0200 AppName[1029:172263] [strings] ERROR: Add to Siri not found in
table Localizable of bundle CFBundle 0x111a01d00 </var/containers/Bundle/Application/DDADF244-FBCE-47C0-90F8-E8C8ADA6962E/AppName.app> (executable, loaded)
hope it help you,
class ViewController: UIViewController, INUIAddVoiceShortcutViewControllerDelegate, INUIEditVoiceShortcutViewControllerDelegate {
func editVoiceShortcutViewController(_ controller: INUIEditVoiceShortcutViewController, didUpdate voiceShortcut: INVoiceShortcut?, error: Error?) {
controller.dismiss(animated: true, completion: nil)
}
func editVoiceShortcutViewController(_ controller: INUIEditVoiceShortcutViewController, didDeleteVoiceShortcutWithIdentifier deletedVoiceShortcutIdentifier: UUID) {
controller.dismiss(animated: true, completion: nil)
}
func editVoiceShortcutViewControllerDidCancel(_ controller: INUIEditVoiceShortcutViewController) {
controller.dismiss(animated: true, completion: nil)
}
func addVoiceShortcutViewController(_ controller: INUIAddVoiceShortcutViewController, didFinishWith voiceShortcut: INVoiceShortcut?, error: Error?) {
controller.dismiss(animated: true, completion: nil)
}
func addVoiceShortcutViewControllerDidCancel(_ controller: INUIAddVoiceShortcutViewController) {
controller.dismiss(animated: true, completion: nil)
}
}
Use INUIAddVoiceShortcutViewControllerDelegate and INUIEditVoiceShortcutViewControllerDelegate
Thank you.
I'm trying to get the two different buttons I have shown with if indexPath.section == 1 && indexPath.row == 0 and if indexPath.section == 1 && indexPath.row == 1 to have different subjects when i pull up the email. Both buttons pull up the same subject (Suggestion: ). How would I allow the program to differentiate them?
import UIKit
import Foundation
import MessageUI
class AccountViewController: UITableViewController, MFMailComposeViewControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
self.navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
self.navigationController?.navigationBar.shadowImage = UIImage()
self.navigationController?.navigationBar.isTranslucent = false
self.navigationController?.view.backgroundColor = .clear
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.section == 1 && indexPath.row == 1{
print("pressed")
let mailComposeViewController2 = configureMailController()
if MFMailComposeViewController.canSendMail() {
self.present(mailComposeViewController2, animated: true, completion: nil)
} else {
showMailError()
}
}
if indexPath.section == 1 && indexPath.row == 0 {
print("pressed")
let mailComposeViewController = configureMailController()
if MFMailComposeViewController.canSendMail() {
self.present(mailComposeViewController, animated: true, completion: nil)
} else {
showMailError()
}
}
}
//if indexPath.section == 1 && indexPath.row == 1 {
//}
func configureMailController() -> MFMailComposeViewController {
let mailComposerVC = MFMailComposeViewController()
mailComposerVC.mailComposeDelegate = self
mailComposerVC.setToRecipients(["SolsticeOfficialLLC#gmail.com"])
mailComposerVC.setSubject("Suggestion: ")
return mailComposerVC
}
func configureMailController2() -> MFMailComposeViewController {
let mailComposerVC = MFMailComposeViewController()
mailComposerVC.mailComposeDelegate = self
mailComposerVC.setToRecipients(["SolsticeOfficialLLC#gmail.com"])
mailComposerVC.setSubject("Report: ")
return mailComposerVC
}
func showMailError() {
let sendMailErrorAlert = UIAlertController(title: "Could not send email", message: "Your device could not send email", preferredStyle: .alert)
let dismiss = UIAlertAction(title: "OK", style: .default, handler: nil)
sendMailErrorAlert.addAction(dismiss)
self.present(sendMailErrorAlert, animated: true, completion: nil)
}
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith: MFMailComposeResult, error: Error?){
controller.dismiss(animated: true, completion: nil)
}
}
You need to add a parameter to help you:
func configureMailController(subject = "Unspecified Subject") -> MFMailComposeViewController {
let mailComposerVC = MFMailComposeViewController()
mailComposerVC.mailComposeDelegate = self
mailComposerVC.setToRecipients(["SolsticeOfficialLLC#gmail.com"])
mailComposerVC.setSubject(subject)
return mailComposerVC
}
Then, do as you please when configuring:
let mailComposeViewController1 = configureMailController("Specific Subject 1")
....
let mailComposeViewController2 = configureMailController("Specific Subject 2")
I'm using Google maps and places API and i'm trying to load nearby places in a tableView but everytime i come in this class
import UIKit
import MapKit
import CoreLocation
import GoogleMaps
import GooglePlaces
import Social
import AVFoundation
private let resueIdentifier = "MyTableViewCell"
extension UIViewController {
func present(viewController : UIViewController, completion : (() -> ())? = nil ){
if let presented = self.presentedViewController {
presented.dismiss(animated: true, completion: {
self.present(viewController, animated: true, completion: completion)
})
} else {
self.present(viewController, animated: true, completion: completion)
}
}
}
class CourseClass2: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
struct User {
var name: String
var images: UIImage
var type: String
}
var previuosViewTappedButtonsArray = [String]()
var locationManager:CLLocationManager?
let minimumSpacing : CGFloat = 15 //CGFloat(MAXFLOAT)
let cellWidth: CGFloat = 250
let radius = 5000 // 5km
var category : QCategoryy?
var currentLocation : CLLocationCoordinate2D?
var places: [QPlace] = []
var isLoading = false
var response : QNearbyPlacesResponse?
var rows = 0
var users = [User]()
override func viewDidLoad() {
super.viewDidLoad()
self.title = category?.name
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
determineMyCurrentLocation()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillAppear(animated)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
rows = 0
insertRowsMode3()
tableView.reloadData()
category?.markView()
}
#IBAction func refreshTapped(_ sender: Any) {
rows = 0
insertRowsMode3()
tableView.reloadData()
}
func canLoadMore() -> Bool {
if isLoading {
return false
}
if let response = self.response {
if (!response.canLoadMore()) {
return false
}
}
return true
}
func loadPlaces(_ force:Bool) {
if !force {
if !canLoadMore() {
return
}
}
print("load more")
isLoading = true
NearbyPlaces.getNearbyPlaces(by: category?.name ?? "food", coordinates: currentLocation!, radius: radius, token: self.response?.nextPageToken, completion: didReceiveResponse)
}
func didReceiveResponse(response:QNearbyPlacesResponse?, error : Error?) -> Void {
if let error = error {
let alertController = UIAlertController(title: "Error", message: error.localizedDescription, preferredStyle: .alert)
let actionDismiss = UIAlertAction(title: "Dismiss", style: .cancel, handler: nil)
let actionRetry = UIAlertAction(title: "Retry", style: .default, handler: { (action) in
DispatchQueue.main.async {
self.loadPlaces(true)
}
})
alertController.addAction(actionRetry)
alertController.addAction(actionDismiss)
DispatchQueue.main.async {
self.present(viewController: alertController)
}
}
if let response = response {
self.response = response
if response.status == "OK" {
if let placesDownloaded = response.places {
places.append(contentsOf: placesDownloaded)
}
self.tableView?.reloadData()
} else {
let alert = UIAlertController.init(title: "Error", message: response.status, preferredStyle: .alert)
alert.addAction(UIAlertAction.init(title: "Cancel", style: .cancel, handler: nil))
alert.addAction(UIAlertAction.init(title: "Retry", style: .default, handler: { (action) in
DispatchQueue.main.async {
self.loadPlaces(true)
}
}))
self.present(viewController: alert)
}
isLoading = false
}
else {
print("response is nil")
}
}
func insertRowsMode2() {
tableView.beginUpdates()
for i in 0..<places.count {
insertRowMode2(ind: i, usr: places[i])
}
tableView.endUpdates()
}
func insertRowMode2(ind:Int,usr:QPlace) {
tableView.beginUpdates()
let indPath = IndexPath(row: ind, section: 0)
rows = ind + 1
tableView.insertRows(at: [indPath], with: .right)
tableView.endUpdates()
}
func insertRowsMode3() {
tableView.beginUpdates()
rows = 0
insertRowMode3(ind: 0)
tableView.endUpdates()
}
func insertRowMode3(ind:Int) {
tableView.beginUpdates()
let indPath = IndexPath(row: ind, section: 0)
rows = ind + 1
tableView.insertRows(at: [indPath], with: .right)
guard ind < places.count-1 else { return }
DispatchQueue.main.asyncAfter(deadline: .now()+0.20) {
self.insertRowMode3(ind: ind+1)
}
tableView.endUpdates()
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return places.count /* rows */
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! MyTableViewCell
let place = places[indexPath.row]
cell.update(place: place)
if indexPath.row == places.count - 1 {
loadPlaces(false)
}
/* let user = users[indexPath.row]
cell.selectionStyle = .none
cell.myImage.image = user.images
cell.myLabel.text = user.name
cell.myTypeLabel.text = user.type */
return (cell)
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
UIView.animate(withDuration: 0.2, animations: {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! MyTableViewCell
})
performSegue(withIdentifier: "goToLast" , sender: users[indexPath.row])
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 100
}
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == UITableViewCellEditingStyle.delete {
places.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .fade)
}
}
func didReceiveUserLocation(_ userLocation:CLLocation) {
currentLocation = userLocation.coordinate
loadPlaces(true)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "goToLast" && sender is IndexPath {
let dvc = segue.destination as! FinalClass
dvc.index = (sender as! IndexPath).row
dvc.places = places
dvc.userLocation = currentLocation
/* guard let vc = segue.destination as? FinalClass else { return }
let guest = segue.destination as! FinalClass
if let user = sender as? User {
*/
}
}
#IBAction func IndTapped(_ sender: Any) {
dismiss(animated: true, completion: nil)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func socialShare(_ sender: Any) {
//Alert
let alert = UIAlertController(title: "Share", message: "First share!", preferredStyle: .actionSheet)
//First action
let actionOne = UIAlertAction(title: "Share on Facebook", style: .default) { (action) in
//Checking if user is connected to Facebook
if SLComposeViewController.isAvailable(forServiceType: SLServiceTypeFacebook)
{
let post = SLComposeViewController(forServiceType: SLServiceTypeFacebook)!
post.setInitialText("First")
post.add(UIImage(named: "uround logo.png"))
self.present(post, animated: true, completion: nil)
} else {self.showAlert(service: "Facebook")}
}
let actionThree = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
//Add action to action sheet
alert.addAction(actionOne)
alert.addAction(actionThree)
//Present alert
self.present(alert, animated: true, completion: nil)
}
func showAlert(service:String)
{
let alert = UIAlertController(title: "Error", message: "You are not connected to \(service)", preferredStyle: .alert)
let action = UIAlertAction(title: "Dismiss", style: .cancel, handler: nil)
alert.addAction(action)
present(alert, animated: true, completion: nil)
}
}
extension CourseClass2: CLLocationManagerDelegate {
func determineMyCurrentLocation() {
locationManager = CLLocationManager()
locationManager?.delegate = self
locationManager?.desiredAccuracy = kCLLocationAccuracyBest
locationManager?.requestWhenInUseAuthorization()
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let userLocation:CLLocation = locations[0] as CLLocation
manager.stopUpdatingLocation()
print("user latitude = \(userLocation.coordinate.latitude)")
print("user longitude = \(userLocation.coordinate.longitude)")
didReceiveUserLocation(userLocation)
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print("Error \(error)")
errorGettingCurrentLocation(error.localizedDescription)
}
public func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
if status == .authorizedWhenInUse || status == .authorizedAlways {
locationManager?.startUpdatingLocation()
//locationManager.startUpdatingHeading()
} else if status == .denied || status == .restricted {
errorGettingCurrentLocation("Location access denied")
}
}
func errorGettingCurrentLocation(_ errorMessage:String) {
let alert = UIAlertController.init(title: "Error", message: errorMessage, preferredStyle: .alert)
alert.addAction(UIAlertAction.init(title: "Cancel", style: .cancel, handler: nil))
present(alert, animated: true, completion: nil)
}
}
i get the message "error - response status" from this function
func didReceiveResponse(response:QNearbyPlacesResponse?, error : Error?) -> Void {
if let error = error {
let alertController = UIAlertController(title: "Error", message: error.localizedDescription, preferredStyle: .alert)
let actionDismiss = UIAlertAction(title: "Dismiss", style: .cancel, handler: nil)
let actionRetry = UIAlertAction(title: "Retry", style: .default, handler: { (action) in
DispatchQueue.main.async {
self.loadPlaces(true)
}
})
alertController.addAction(actionRetry)
alertController.addAction(actionDismiss)
DispatchQueue.main.async {
self.present(viewController: alertController)
}
}
if let response = response {
self.response = response
if response.status == "OK" {
if let placesDownloaded = response.places {
places.append(contentsOf: placesDownloaded)
}
self.tableView?.reloadData()
} else {
let alert = UIAlertController.init(title: "Error", message: response.status, preferredStyle: .alert)
alert.addAction(UIAlertAction.init(title: "Cancel", style: .cancel, handler: nil))
alert.addAction(UIAlertAction.init(title: "Retry", style: .default, handler: { (action) in
DispatchQueue.main.async {
self.loadPlaces(true)
}
}))
self.present(viewController: alert)
}
isLoading = false
}
else {
print("response is nil")
}
}
so looking in the console i saw this error "((null)) was false: provideAPIKey: should be called at most once" which is perhaps the cause of the problem (even if I'm not sure), i followed the google documentation guide to get the API key for the project, here is my appDelegate where there are my keys (i changed for now the numbers of the key with "My Api key")
import UIKit
import Firebase
import CoreLocation
import GoogleMaps
import GooglePlaces
import FBSDKCoreKit
import GoogleSignIn
import FBSDKShareKit
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, GIDSignInDelegate {
static let googleMapsApiKey = "MY API Key"
static let googlePlacesAPIKey = "MY API Key"
var window: UIWindow?
var locationManager: CLLocationManager?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
FirebaseApp.configure()
locationManager = CLLocationManager()
locationManager?.requestWhenInUseAuthorization()
GMSServices.provideAPIKey(AppDelegate.googleMapsApiKey)
GMSPlacesClient.provideAPIKey(AppDelegate.googlePlacesAPIKey)
FBSDKApplicationDelegate.sharedInstance().application(application, didFinishLaunchingWithOptions: launchOptions)
IQKeyboardManager.sharedManager().enable = true
IQKeyboardManager.sharedManager().enableAutoToolbar = false
GIDSignIn.sharedInstance().clientID = FirebaseApp.app()?.options.clientID
GIDSignIn.sharedInstance().delegate = self
if GMSServices.provideAPIKey("MY API Key") {
print("good provided keys correctly")
}
else {
print("key didn't provided")
}
return true
}
someone can tell if the problem is a wrong use of the api key or if the keys are wrong or maybe the problem is another ?
Look at what you are doing here:
// once
GMSServices.provideAPIKey(AppDelegate.googleMapsApiKey)
GMSPlacesClient.provideAPIKey(AppDelegate.googlePlacesAPIKey)
FBSDKApplicationDelegate.sharedInstance().application(application, didFinishLaunchingWithOptions: launchOptions)
IQKeyboardManager.sharedManager().enable = true
IQKeyboardManager.sharedManager().enableAutoToolbar = false
GIDSignIn.sharedInstance().clientID = FirebaseApp.app()?.options.clientID
GIDSignIn.sharedInstance().delegate = self
// twice!
if GMSServices.provideAPIKey("MY API Key") {
You are calling provideAPIKey twice!
I know you want to check whether the API key is provided correctly, but the correct way to do this is not to call the method twice. Instead, you should store the return value and check the return value:
// put the return value in "success"
let success = GMSServices.provideAPIKey(AppDelegate.googleMapsApiKey)
GMSPlacesClient.provideAPIKey(AppDelegate.googlePlacesAPIKey)
FBSDKApplicationDelegate.sharedInstance().application(application, didFinishLaunchingWithOptions: launchOptions)
IQKeyboardManager.sharedManager().enable = true
IQKeyboardManager.sharedManager().enableAutoToolbar = false
GIDSignIn.sharedInstance().clientID = FirebaseApp.app()?.options.clientID
GIDSignIn.sharedInstance().delegate = self
// check "success"
if success {
I have created the setting page in TableView. When I tap row 0 UIActivityViewController is called. When I tap row2 MailComposeController is called.
MailComposeController is called, but when I tap cancel or send button on mail screen it does not work.
Here is the code。
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.row == 0 {
let message = "Hey download my app [LINK]"
let shareView = UIActivityViewController(activityItems: [message], applicationActivities: nil)
self.present(shareView, animated: true, completion: nil)
} else if indexPath.row == 1 {
let mailCompose = MFMailComposeViewController()
mailCompose.mailComposeDelegate = self
mailCompose.setToRecipients(["address#gmail.com"])
mailCompose.setSubject("feedback")
mailCompose.setMessageBody("text", isHTML: false)
if MFMailComposeViewController.canSendMail()
{
self.present(mailCompose, animated: true, completion: nil)
}
else{
print("error...!")
}
}
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
controller.dismiss(animated: true, completion: nil)
}
You have to put the delegate method in the ViewController but not in the tableView:didSelectRowAt method:
extension ViewController: MFMailComposeViewControllerDelegate {
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
controller.dismiss(animated: true, completion: nil)
}
}
Implement the delegate methods of Mail composer on click of send and cancel button:
Here are the Delegates methods which you need to implement :
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
controller.dismiss(animated: true, completion: {
switch (result)
{
case .cancelled:
break
case .saved:
break;
case .sent:
AppUtility.showAlert(message: kEmailSentSuccessMessage, isSuccess: true)
break;
case .failed:
AppUtility.showAlert(message: kEmailSentFailureMessage, isSuccess: true)
break;
}
})
}
Use breakpoint to see what exactly going on the click of send or cancel. and make sure that you have created the MailComposer object locally . since this object is going to send and cancel the mail each time .