I am developing an iOS application with a button to report an issue using SMS/iMessage. I am using MFMessageComposeViewController to present the message composition interface using the following code (Swift 3):
if(MFMessageComposeViewController.canSendText()){
let controller = MFMessageComposeViewController()
controller.messageComposeDelegate = self
controller.body = "Example Message"
controller.recipients = ["2345678901"]
self.present(controller, animated: true, completion: nil)
}
I have also implemented the MFMessageComposeViewControllerDelegate function to dismiss properly. A standard text message / iMessage sends successfully, but the user does not have the option to attach an image. The buttons for camera, iMessage Apps, etc. are there, but they are disabled and cannot be pressed. How can I enable these buttons (camera, specifically) to allow my users to attach images to messages composed with the app?
The Buttons in Question:
EDIT:
Thanks Abdelahad for the suggestion. I've modified his response to allow multiple recipients and to include a message body. I also updated it to remove the deprecated addingPercentEscapes(using: ) method.
Here is a solution using a url to open the Messages app. NOTE: This takes users out of the app.
let recipients = "2345678901,3456789012" //Phone Numbers
let messageBody = "This is a test"
let sms: String = "sms://open?addresses=\(recipients)&body=\(messageBody)"
let smsEncoded = sms.addingPercentEncoding(withAllowedCharacters: .urlFragmentAllowed)
let url = URL(string: smsEncoded!)
UIApplication.shared.openURL(url!)
But still I would like a solution that does not take the user out of the app. Is this possible? Why would the MFMessageComposeViewController show the buttons without enabling them?
Don't use MFMessageComposeViewController use UIApplication.shared.openURL(url!) but this will takes the user out of the app
var phoneToCall: String = "sms: +201016588557"
var phoneToCallEncoded = phoneToCall.addingPercentEscapes(using: String.Encoding.ascii)
var url = URL(string: phoneToCallEncoded)
UIApplication.shared.openURL(url!)
Related
I'm creating an app similar to THIS one
I'm working on adding siri shortcuts into my app to get quotes by categories just like this app.
So far I've succeeded in creating NSUserActivity and donating shortcuts. My shortcuts are showing up in spotlight and they work just as expected ( In the overlay window for a shortcut without opening the app)
However, when I show the INUIAddVoiceShortcutViewController and use that to add that shortcut to the shortcuts app, it stops working in the overlay and opens my app instead
The app I'm trying to copy the feature from also has an option to edit their shortcut action which I can't get in my app.
Here is an example of how the app I'm trying to copy shows the sheet, notice the arrow in the 'Do' section
It looks like this when opened
But my app doesn't work like that even though I've set up the intentDefinition file
My app looks like this. I can't for the love of god get it to be editable.
I've read the documentation, read through every tutorial on the web, gone through google's first page completely and still can't find a relevant updated code sample.
This is my IntentDefinition File
I'm donating all available shortcuts as soon as my app opens into the dashboard (I did that to test if I need to donate shortcuts before adding them to siri)
This is my code to generate a new user activity
public let kNewArticleActivityType = "\(bundleID).GetQuotes"
class Shortcuts {
public static func newUserActivity(category: Categories, thumbnail: UIImage? = UIImage(named: "icon")) -> NSUserActivity {
let categoryString = category.getStringValue().capitalized
let invocationPhrase = "\(categoryString) quote"
let attributes = CSSearchableItemAttributeSet(itemContentType: kUTTypeItem as String)
attributes.contentDescription = "Get quote from the \(categoryString) category"
attributes.thumbnailData = thumbnail?.jpegData(compressionQuality: 1.0)
attributes.keywords = ["quote", "motivation", "positive", "vibrations"]
let activity = NSUserActivity(activityType: kNewArticleActivityType)
activity.persistentIdentifier = NSUserActivityPersistentIdentifier(kNewArticleActivityType)
activity.isEligibleForSearch = true
activity.isEligibleForPrediction = true
activity.suggestedInvocationPhrase = invocationPhrase
activity.title = "Get a quote"
activity.userInfo = ["category": categoryString]
activity.contentAttributeSet = attributes
return activity
}
static func donateInteraction(with category: Categories) {
let categoryString = category.getStringValue().capitalized
let phrase = "\(categoryString) quote"
let intent = GetQuotesIntent()
intent.suggestedInvocationPhrase = phrase
intent.category = category
let interaction = INInteraction(intent: intent, response: nil)
interaction.donate { (error) in
if let error = error {
print("Interaction donation failed because \(error.localizedDescription)")
} else {
print("Successfully donated interaction")
}
}
}
}
As soon as a category name is clicked, I add it to siri using this code
func addToSiriClicked(category: String) {
let categoryEnum = Categories.getEnum(from: category)
let activity = Shortcuts.newUserActivity(category: categoryEnum)
self.userActivity = activity
let shortcut = INShortcut(userActivity: activity)
let viewController = INUIAddVoiceShortcutViewController(shortcut: shortcut)
viewController.modalPresentationStyle = .formSheet
viewController.delegate = self
self.present(viewController, animated: true, completion: nil)
}
If anyone can find any relevant tutorial for ios 14 or for siri shortcuts that isn't 2 years old, please send me a link. My donations work as expected from the spotlight, but they are generated as another interaction when I add them to siri and they stop working and open the app from that shortcut.
To get the edit function, you have to initialize the INUIAddVoiceShortcutViewController class with your custom intent
It has 2 initializers, 1 for the user activity and another one for a custom intent. Using the intent initializer solved this issue for me.
let shortcut = INShortcut(intent: Shortcuts.newIntent(category: categoryEnum))
if let shortcut = shortcut {
INVoiceShortcutCenter.shared.setShortcutSuggestions([shortcut])
let viewController = INUIAddVoiceShortcutViewController(shortcut: shortcut)
viewController.modalPresentationStyle = .formSheet
viewController.delegate = self
self.present(viewController, animated: true, completion: nil)
}
I am using share sheet for sharing files through mail,whatsapp etc.i want to set default email recipient(To Address).I was tried a lot I can able to set Subject for mail but I am not able to set recipient.its necessary for my app.(In stack over flow showing there is no option to set to sddress).if its not there in share sheet let me know when user clicks share sheet items how can I detect and do operation.please help me
I am excepting when user clicks share sheet item for example mail for that I have to set To Address(recipient).(WITH OUT USING MFMAILCOMPOSER)
Try this code,
let mailer = MFMailComposeViewController()
mailer.mailComposeDelegate = self
mailer.setSubject("")
let toRecipients = ["recipient mail ID"]
mailer.setToRecipients(toRecipients as? [String])
let emailBody = ""
mailer.setMessageBody(emailBody, isHTML: false)
mailer.navigationBar.barStyle = .blackOpaque
present(mailer, animated: true)
I am trying to use the FBSDK, specifically FBSDKShareKit to let users post a deep link to their wall from my app. I have my App set up with Facebook Developers (I know this isn't the issue because my app users sign in with Facebook with no problem) and have a scheme suffix associated with the app.
My application's info.plist has the same suffix set. I know this works because when opening a URL with this suffix from Safari, it navigates to my application.
When opening a URL, my app delegate checks if the URL host matches a certain string, if it does, I then check if the URL path matches a certain string. If both of these match, then I parse the parameters passed from the URL, create a custom object (in this case, an event), instantiate a view controller, and populate that view controller with the custom object's properties.
func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool {
if url.host != "www.mywebsite.app" {
return false
} else if url.path == "/sharedEvent" {
if let parameters = url.queryParameters {
//Get params from url
let name = parameters["name"]!
let description = parameters["description"]!
let lat = parameters["lat"]!.CGFloatValue()
let lng = parameters["lng"]!.CGFloatValue()
let startTime = Int(parameters["startTime"]!)!
let endTime = Int(parameters["endTime"]!)!
let categories = parameters["categories"]!
let priority = Int(parameters["priority"]!)!
let id = parameters["id"]!
let userId = parameters["userId"]!
let userName = parameters["userName"]!
let userEmail = parameters["userEmail"]!
let photoURLs = parameters["photoURLs"]!
let isVerified = Int(parameters["isVerified"]!)
//Create event from parameters
let sharedEvent = Event(name: name, description: description, lat: lat, long: lng, startTime: Date(timeIntervalSince1970: Double(startTime)), endTime: Date(timeIntervalSince1970: Double(endTime)), categories: [categories], priority: priority, id: id, userId: userId, userName: userName, userEmail: userEmail, photoURLs: [photoURLs], isVerified: isVerified!)
//Instantiate eventVC
let storyboard = UIStoryboard(name: "Main", bundle: .main)
let eventVC = storyboard.instantiateViewController(withIdentifier: "EventViewController") as! EventViewController
eventVC.event = sharedEvent
eventVC.userId = userId
eventVC.userEmail = userEmail
eventVC.userName = userName
DispatchQueue.main.async {
self.window!.rootViewController!.presentedViewController?.present(eventVC, animated: true, completion: nil)
}
}
return true
}
This code works as I've tested it by opening a URL from another app with some parameters, and the respective view controller is presented upon the app opening. A URL might look something like this:
fb1068346896678533://www.hootevents.app/sharedEvent?name=Some%20Name&description=Some%20description&lat=38.7016&lng=-90.447&startTime=1548466210&endTime=1551058140&categories=lhw9bs31nr2twlx&priority=1&id=15510581401548012896PfZLZCzDUh&userId=f5qLpyu4XNWa4eJI17sBi71bIw23&userName=David%20Chopin&userEmail=chopindavidg#gmail.com&photoURLs=https://upload.wikimedia.org/wikipedia/commons/thumb/2/2f/Google_2015_logo.svg/1200px-Google_2015_logo.svg.png&isVerified=1
My issue lies with actually presenting the deep link via Facebook. I've tried two approaches:
Using FBSDKShareKit's FBSDKShareButton by setting the button's shareContent to a FBSDKShareLinkContent with a content url equal to the one shown above. Doing this results in a greyed out, i.e. disabled, FBSDKShareButton. Changing the content's URL to something like "www.google.com" enables the button, meaning that Facebook doesn't like my URL for some reason.
let button = FBSDKShareButton()
let shareContent = FBSDKShareLinkContent()
content.contentURL = URL(string: "fb1068346896678533://www.hootevents.app/sharedEvent?name=Some%20Name&description=Some%20description&lat=38.7016&lng=-90.447&startTime=1548466210&endTime=1551058140&categories=lhw9bs31nr2twlx&priority=1&id=15510581401548012896PfZLZCzDUh&userId=f5qLpyu4XNWa4eJI17sBi71bIw23&userName=David%20Chopin&userEmail=chopindavidg#gmail.com&photoURLs=https://upload.wikimedia.org/wikipedia/commons/thumb/2/2f/Google_2015_logo.svg/1200px-Google_2015_logo.svg.png&isVerified=1")
button.shareContent = content
Using iOS's Social framework to instantiate an SLComposeViewController, setting said view controller's URL to the same one above, and presenting the view controller. Upon posting through Facebook, I'm prompted with the error message "There was a problem sharing your link." Again, when replacing the URL in question with "www.google.com," the post goes through successfully, indicating, again, that Facebook doesn't like the deep link I'm providing for some reason.
#IBAction func shareButtonPressed(_ sender: Any) {
let vc = SLComposeViewController(forServiceType: SLServiceTypeFacebook)
vc?.add(loadedImages.first?.image)
vc!.add(URL(string: shareURL))
for photo in self.loadedImages {
vc!.add(photo.image!)
}
present(vc!, animated: true, completion: nil)
}
So, in conclusion, I believe that the issue here lies with the fact that Facebook won't allow me to post:
fb1068346896678533://www.hootevents.app/sharedEvent?name=Some%20Name&description=Some%20description&lat=38.7016&lng=-90.447&startTime=1548466210&endTime=1551058140&categories=lhw9bs31nr2twlx&priority=1&id=15510581401548012896PfZLZCzDUh&userId=f5qLpyu4XNWa4eJI17sBi71bIw23&userName=David%20Chopin&userEmail=chopindavidg#gmail.com&photoURLs=https://upload.wikimedia.org/wikipedia/commons/thumb/2/2f/Google_2015_logo.svg/1200px-Google_2015_logo.svg.png&isVerified=1
on behalf of users. If this is the case, how am I supposed to format my deep link so that users can post it to their wall from my app, effectively sharing events with their Facebook friends and, ideally, driving more traffic to my app?
It seems all I had to do was wait a while (I guess it can take up to 48 hours for the link to start working?).
Note that the Facebook app does not allow users to navigate to another app via universal/deep linking. Their in-app browser is designed to not allow this to happen. There are some workaround, most notably Branch.io, which allows users to get use out of their universal links through Facebook.
I have an app and I wanna add messages extension feature.
I thought the feature is if the user selects a message, it switches my host app directly like google map.
I made a MSMessage and set URL and the message has template layout which had caption and sub-caption.
let message = MSMessage()
message.url = "http://blahblah?customScheme=myHostAppLaunchScheme"
let template = MSMessageTemplateLayout()
template.image = sampleImage
template.caption = "this is a caption"
template.subCaption = "this is a sub caption"
message.layout = template
guard let conversation = activeConversation else {
print("blahblah")
return
}
conversation.insert(message) { (error) in
print("finish. error = \(error == nil ? "nil" : error!.localizedDescription)")
}
and i wrote a code extensionContext.open(url, completionHandler) in
willBecomeActive(with conversation: MSConversation)
didReceive(_ message: MSMessage, conversation: MSConversation)
of course, i parsed selectedMessage's URL.
but it didn't work I expected.
the messages extension switches expand mode automatically.
it works if I used
conversation.insertText("myHostAppLaunchScheme", nil)
but I don't want it because it can't add template :(
is there any idea to switch iMessage to host app directly?
thanks for any ideas.
i think i found the answer.
there is no way with using
conversation.insert(message, completionHandler)
i think apple music and google maps are using
conversation.insertText("some url", completionHandler)
because i copied an URL after long press a message which is shared by apple music or google map
then i use the URL in my code
conversation.insertText("the URL", completionHandler)
it's working they did!!
I have tried many ways to achieve this but failed.
I have to share info on facebook with a URL and when clicked on the url, it will redirect to my app's specific page.
step# 1
let content: FBSDKShareLinkContent = FBSDKShareLinkContent()
content.contentURL = NSURL(string: linkUrl) as URL!
content.contentTitle = "Test"
content.quote = "game"
content.contentDescription = "This is a test game to test Fb share functionality"
content.imageURL = NSURL(string: imgUrl) as URL!
let dialog: FBSDKShareDialog = FBSDKShareDialog()
dialog.mode = FBSDKShareDialogMode.native
dialog.fromViewController = vc
dialog.shareContent = content
// if you don't set this before canShow call, canShow would always return YES
if !dialog.canShow() {
// fallback presentation when there is no FB app
dialog.mode = FBSDKShareDialogMode.feedBrowser
}
dialog.show()
It is working and successfully sharing the post. When I clicked on the link, it is redirecting to the app, not much info to redirect to a particular ViewController.
Step# 2
let properties = [
"fb:app_id": "Fb_id",
"og:type": "article",
"og:title": "Test",
"og:description": "This is a test game to test Fb share functionality",
"og:image" : urlImg,
"og:url" : linkUrl,
]
let object : FBSDKShareOpenGraphObject = FBSDKShareOpenGraphObject.init(properties: properties)
// Create an action
let action : FBSDKShareOpenGraphAction = FBSDKShareOpenGraphAction()
action.actionType = "news.publishes"
action.setObject(object, forKey: "article")
// Create the content
let content : FBSDKShareOpenGraphContent = FBSDKShareOpenGraphContent()
content.action = action
content.previewPropertyName = "article"
FBSDKShareDialog.show(from: vc, with: content, delegate: nil)
Here I am using Open Graph to post and successfully posted the Info. But con't redirecting to my app when clicked the link.
NB:
I don't have web Application.
My goal is to share a post with a app link. When clicked on that link it will open the app and redirect to a specific page if app is installed, otherwise redirect to the AppStore. So what should be the link format or how can I build the link to achieve this functionality?
Please help.
Thanks in advance
Use Universal Links. If you want to achieve something like this using universal link is a good idea. You can redirect to a specific page in your app if the app is installed otherwise it will navigate to appstore.
Here is how to implement universal links if you are not aware of:
Set up universal links - Raywenderlich
Universal links - Appsflyer
Note: Please ignore this, if this is not what you are looking for
I managed to achieve the same result using Branch.io. It's a very powerful app routing SDK and their console practically guides you down the routing scheme in a very visual and understandable manner.
The way it works is by dynamically creating a webpage with certain redirecting features according to what you set in the dashboard. You can then use that generated webpage to share it on Facebook or anywhere else.
Here's how you can integrate it:
Create an account here
Install and link the SDK (pod 'Branch')
Set up the routing mechanism using Branch's dashboard (it's guided and pretty straightforward, you just fill in the branches below). You can always change how the diagram looks like (if you want to always end up on a website or so, for instance)
Initialize the share data in your app
let branchUniversalObject: BranchUniversalObject = BranchUniversalObject(canonicalIdentifier: "any ID here") // just for tracking count and analytics
branchUniversalObject.title = "some title" // This will appear as the shared content's title
branchUniversalObject.contentDescription = "some description" // This will appear as the shared content's description
branchUniversalObject.imageUrl = "www.example.com/test.png"
branchUniversalObject.addMetadataKey("uid", value: self.userId)
branchUniversalObject.addMetadataKey("otherInfo", value: self.otherInfo)
Generate link and share the link on Facebook
let linkProperties = BranchLinkProperties()
linkProperties.channel = "Facebook"
linkProperties.feature = "Share"
// generate link
branchUniversalObject.getShortUrl(with: linkProperties, andCallback: { (shareURL, error) in
if error != nil {
// handle error
}
// init Facebook share data
let content = FBSDKShareLinkContent()
content.contentTitle = "Some title"
content.contentURL = URL(string: shareURL) // this URL handles the redirecting according to your dashboard's settings
content.contentDescription = "Some description"
content.imageURL = URL(string: "www.example.com/test.png")
// create Facebook share dialog
let dialog = FBSDKShareDialog()
dialog.fromViewController = self
dialog.delegate = self
dialog.shareContent = content
dialog.mode = .automatic
if dialog.canShow() {
dialog.show()
}
})
Yes, I achieved this functionality by setting up the metadata in the server end.
References: https://developers.facebook.com/docs/applinks
https://developers.facebook.com/docs/applinks/ios
Thanks...