I'm building an iOS app with an iMessage extension. I am successfully using the insertAttchment call from within the iMessage app to attach a media file to a text message for the user to send, however, I would like to attach two or three attachments at one time, before the user taps send.
Does anyone know if this is possible, and how it would be accomplished?
Here is the code I successfully use to attach one media file:
func didClickItem(_ controller: ItemViewController, itemUrl: URL) {
if let conversation = self.activeConversation {
conversation.insertAttachment(itemUrl, withAlternateFilename: "", completionHandler: nil)
}
Related
Please help to solve the issue of sending invites to the app via SMS or iMessage.
The issue is that when all the receipents of the message have iMessage available (blue button), then upon invitation sending a group consisting of these people gets created, but I need to send the messages separately (not in group).
if MFMessageComposeViewController.canSendText() {
let messageViewController = MFMessageComposeViewController()
messageViewController.body = "Some invite text"
messageViewController.recipients = [phone_numbers_from_contacts]
messageViewController.messageComposeDelegate = self
self.present(messageViewController, animated: true, completion: nil)
} else {
// Some alert with text "SMS services are not available"
}
AFAIK you have no control over whether the message is sent as a group message or not.
If you want to send it as individual messages then I would suggest using multiple different instances of the MFMessageComposeViewController.
TBH though, you shouldn't really be using this for sending out spam texts anyway.
I am exploring SiriKit and I want to use it for sending data to web server. Basically, I want to send some data whenever user says "Hey Siri, send data using SomeApplication". Here 'SomeApplication' is the name of my app. I googled a bit, but I came to know that I can only use the intents given by SiriKit, I can't create my own. Please help me if there is some way to do this.
That’s true that you can’t create your own intents but there’s a trick that you can play. You can use the Messaging intent and instead of sending text message, you can make your service call from there.
In the IntentHandler.swift file, modify the code of resolveRecipients method to create a custom contact. This would result in showing a messaging UI but would skip the step of asking for recipient. Instead, Siri would directly ask for the message that you would receive in resolveContent method. Get it from there and call your web service. As simple as that.
Here's the code
func resolveRecipients(for intent: INSendMessageIntent, with completion: #escaping ([INPersonResolutionResult]) -> Void) {
let resolutionResults = [INPersonResolutionResult.success(with: INPerson.init(personHandle: INPersonHandle.init(value: "Raw", type: .unknown), nameComponents: PersonNameComponents.init(), displayName: "Raw", image: INImage.init(), contactIdentifier: "Raw", customIdentifier: "Raw"))]
completion(resolutionResults)
}
For detailed example, you can checkout this Git Repo for SiriKitDemo
I am developing an app that reads csv files and display its content in a tableViewController. When doing my testings using Xcode, I have a sample file within the projects directory and I am perfectly able to read that file using its location path. The problem that I have is I want to be able to take any csv file (sent to me via some method), click the 'Open in' button and have the file sent to my app.
My app is being displayed in the available applications to which I can send the file to. My question is what happens after? When I choose to send it to my app it then switches over to my app and from there, I don't know how to receive the file and read it to extract its content. Where does the file go and how do I interact with it?
This is handled in your AppDelegate, more precisely, you get passed an URL to the document and then you handle it from there in optional function, e.g.:
func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
do {
let data = try Data(contentsOf: url)
// Do something with the file
} catch {
print("Unable to load data: \(error)")
}
return true
}
More info: https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1623112-application
I'm trying to update my app to work correctly with the new features of GameCenter in iOS10.
I create a new GKGameSession on device1, get a share URL, and all that works fine. I send the share URL out via a share sheet to device 2.
Device2 clicks the link, the device briefly displays 'Retrieving...' and then launches my app. Great! But, now what? Is there context information available for this URL that I can somehow access? Otherwise I have no way how to respond when the app is launched.
Previously you'd get a callback to something adhering to the GKLocalPlayerListener protocol, to the method player:didAcceptInvite:, and you could join the match that way. But with these iCloud-based messages, the player might not be even logged into GameCenter, right? This part seems to have been glossed over in the WWDC presentation.
Also, as of today (12/28/2016) there is no Apple documentation on these new methods.
Since the GKGameSessionEventListener callback session:didAddPlayer: only fires if the game is already running, to be sure you can process this callback every time requires a work around. I've tested this and it works.
When you send out an iMessage or email invite to the game, don't include the Game Session Invite URL directly in the message. Instead use a registered URL that will open your app when opened on a device on which your app is installed. Check here to see how:
Complete Tutorial on iOS Custom URL Schemes
But add a percent escaped encoding of the game invite URL as a parameter to this URL thusly (I'm assuming the registration of a url e.g. newGameRequest but it will be best to make this quite unique, or even better - though it requires more setup, try Universal Link Support as this will allow you to direct users who don't have your app installed to a webpage with a download link)
let openOverWordForPlayerChallenge = "newGameRequest://?token="
gameState.gameSession?.getShareURL { (url, error) in
guard error == nil else { return }
// No opponent so we need to issue an invite
let encodedChallengeURL = url!.absoluteString.addingPercentEncoding(withAllowedCharacters:.urlHostAllowed)
let nestedURLString = openOverWordForPlayerChallenge + encodedChallengeURL!
let nestedURL = URL(string: nestedURLString)!
}
send the URL in a message or email or WhatsApp or whatever. Then in your app delegate, add the following:
func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
var success = false
if let queryString = url.query {
if let urlStringToken = queryString.removingPercentEncoding {
let token = "token="
let startIndex = urlStringToken.startIndex
let stringRange = startIndex..<urlStringToken.index(startIndex, offsetBy: token.characters.count)
let urlString = urlStringToken.replacingOccurrences(of: token, with: "", options: .literal, range: stringRange)
if let url = URL(string: urlString) {
if UIApplication.shared.canOpenURL(url) {
UIApplication.shared.open(url, options: [:], completionHandler: nil)
success = true
}
}
}
}
return success
}
Now you can be sure the session:didAddPlayer: will be called. What's the betting this workarround is good for about 2 weeks, and they fix this in the next release of iOS showcased at WWDC 2017 ! Update: this problem hasn't been fixed - so the workaround above remains good!
I agree, the lack of documentation is frustrating. From what I can see, we have to:
add <GKGameSessionEventListener> protocol in the class' header
Then session:didAddPlayer: fires on the joining player's device after accepting an invite link.
update:
Unfortunately, I'm not surprised to hear your results. I hadn't tried all of those scenarios, but GKTurnBasedMatch had similar shortcomings. The way I got around it there was: I added a list of player statuses to match data (invited, active, quit, etc). I gave the player a view of "pending invitations." When they opened that view, I would load all of their matches and display the entries where the player was in invited state. With GKGameSession, that should work too.
Or, it might be easier if you could maintain a local list of sessions that you are aware of. Whenever the game becomes active, pull the entire list of sessions from the server and look for a new entry. The new entry would have to be the match the player just accepted by clicking the share URL.
i build a register form for my app and i need to send the user a verifiation code by sms in order to complete the registration proccess.
i tried to use MFMessageComposeViewController but its open the dialog sms on the device so the user can see the code.
i also checked the web for 3party of sending sms but there is a problem with the country code. i know its posible becuse whatsapp do it to confirm the user.
what it the right way to do it?
this is the topic the i tried:
Sending SMS in iOS with Swift
The best way to achieve this is by creating some views for allowing the user to enter the phone number with the country code which can be used by a server to send a request for initiating the OTP verification. To achieve this you need to:
Create View Controllers.
Upload Phone Number and Country code to the server.
Validate the requests by verifying the OTP.
As mentioned by Dan, you can use Digits in Fabric for that purpose, and create custom views for a great UX.
On the other hand, you can also use a service called as SendOTP from MSG91 - you can use it for internal testing and development ideas as they provide you with 5,000 free OTP SMS. The service has a complete set of APIs which you can implement on the backend as well on the app front. Also, they provide a framework so that you don't need to create the views, but only presentViewController and call delegate methods for knowing what happened during the verification process - such as Cancelled or Verified or Failed.
Swift implementation of the same looks like this:
class OTPFrame: UIViewController, sendOTPAuthenticationViewControllerDelegate {
func loadOTPFramework() {
SendOTP.sharedManager().startWithApiId("yourAppID")
let frameworkPath: NSString = NSBundle.mainBundle().privateFrameworksPath!
let frameworkBundlePath: NSString = frameworkPath.stringByAppendingPathComponent("SendOTPFramework.framework")
let frameworkBundle : NSBundle
= NSBundle(path: frameworkBundlePath as String)!
let authenticationViewController: AuthenticationViewController = AuthenticationViewController(nibName: "AuthenticationViewController", bundle: frameworkBundle)
authenticationViewController.delegate = self self.presentViewController(authenticationViewController, animated: true, completion: nil)
}
func authenticationisSuccessfulForMobileNumber(mobNo: String!, withCountryCode countryCode: String!) {
print("Success")
}
func canceledAuthentication() {
print("Cancelled")
}
func authenticationisFailedForMobileNumber(mobNo: String!, withCountryCode countryCode: String!) {
print("Failed")
}
}
Disclaimer: I, in no way, endorse the services mentioned above - you are free to choose whatever you like.
Thank You!
I would give digits a try! It's part of the Twitter Fabric package and it's very simple to use. The user enters their phone number and Fabric takes care of validating the number.