SiriKit support for general services - ios

I have watched SiriKit in wwdc and read document.
https://developer.apple.com/library/prerelease/content/documentation/Intents/Conceptual/SiriIntegrationGuide/
Add SiriKit support only if your app implements one of the following
types of services:
Audio or video calling
Messaging Payments
Searching photos
Workouts
Ride booking
I am still wondering whether I can do for other services (since my app will be for enterprise app).
My service will be very simple searching only like "Find SQ212 in myapp".
Can it be done? I afraid that sirkit can't support intent for other servies.

No, you can't. That's why it says "only if your app implements one of the following types of services".
You won't get the 'find foo in bar' syntax; each respective service has its own syntax - like "start a workout in MyApp" or "Book a ride to place with MyApp". See https://developer.apple.com/sirikit/ for examples.
I would expect a workaround using the SiriKit API to result in your app being rejected if submitted to the general app store, and I would expect it to be extremely fragile if it passed App Review or didn't go through it in the first place.

I found this article on making Sirikit Extensions that aren't default ones provided by Apple on swifting.io.
Using INVocabulary
From the Apple documentation:
The INVocabulary object lets you augment your app’s fixed vocabulary with terms that are both unique to your app and to the current user of your app. Registering custom terms provides Siri with the hints it needs to apply those terms appropriately to the corresponding intent objects. You may register only specific types of custom terms, such as the name of a contact, the name of a user’s workout, a custom tag applied to a photo, or a user-specific payment type.
public enum INVocabularyStringType : Int {
case contactName
case contactGroupName
case photoTag
case photoAlbumName
case workoutActivityName
case carProfileName
}
INMessage
Here they use INSearchForMessagesIntent to setup an index search for finding support.
struct SupportMe{
static let systems = [
INPerson(personHandle: INPersonHandle(value: "MyNotes",
type: INPersonHandleType.unknown),
nameComponents: nil,
displayName: "MyNotes",
image: nil,
contactIdentifier: "MyNotes",
customIdentifier: "MyNotes")]
static let articles = [
INMessage(identifier: "MyNotesPassword",
content: "Retrieving password in MyNotes app. To retrieve
password use 'forgot password' button that is located below
sign in button. Then type email address that your account has
been assigned to and press reset password",
dateSent: Date(),
sender: SupportMe.systems[0],
recipients: [SupportMe.systems[0]])]
}
extension IntentHandler: INSearchForMessagesIntentHandling{
func handle(searchForMessages intent: INSearchForMessagesIntent,
completion: (INSearchForMessagesIntentResponse) -> Void){
let userActivity = NSUserActivity(activityType: String(INSearchForMessagesIntent.self))
let response = INSearchForMessagesIntentResponse(code: .success,
userActivity: userActivity)
response.messages = [SupportMe.articles[0]]
completion(response)
}
}

Related

When i terminate app MUC group chat members are getting removed

When i terminate app MUC group chat members are getting removed, i have to join them again while coming back to app from bookmarks? We do not want to rejoin again and again. Can someone please suggest way how to avoid rejoining.
In Android smack there is provision for auto-rejoin.
Even from Openfire back end we have managed code to do not remove.
So Android is working fine, iOS is removing users.
Please do suggest.
Instead of rejoining the room every time, do set the presence of the group when the user relaunches the app.
Set presence with below code function iterate through all your groups name and set presence:
for group in chatListModel ?? []{
if(group.opponent_type == "2"){
print("Group Name: \(group.opponent_uuid ?? "")")
XMPPGlobal.sharedIntanceXMPP.xmppController.updatePresence(roomJID: XMPPJID(string: "\(group.opponent_uuid ?? "")#\(groupServerName)"))
}
}
Define below function in your XMPPController class:
func updatePresence(roomJID : XMPPJID?) {
let presence = XMPPPresence(type: "presence")
presence.addAttribute(withName: "from", stringValue: self.xmppStream.myJID?.user ?? "")
presence.addAttribute(withName: "to", stringValue: "\(roomJID?.full ?? "")/\(self.xmppStream.myJID?.user ?? "")")
let element = DDXMLElement.init(name: "x", xmlns: XMPPMUCNamespace)
presence.addChild(element)
self.xmppStream.send(presence)
}
Hope it will works for you.
In spite of the fact that there is the answer.
I would like to elaborate a little bit :)
In case of MUC rooms: there is an affiliation, i.e. long-lasting role (admin, owner, etc) and "subscription" role (visitor, member etc).
What you are asking is per se described in XMPP MUC. 7.1 Order of Events
You send your presence to join the room, and receive presence from other other participants, you can also get some cached messages if your XMPP backend was configured properly.
For instance for ejabberd (process-one): mod_muc: history_size settings defines in-memory cache.
You might don't want to get set of room events, as described in 7.1 above.
There might be some server's extensions. In case of ejabberd there is MUCPubSub you send your subscription (not presence) and get the following messages, plus you can get list of members or track its changes, and etc:
<subscribe xmlns='urn:xmpp:mucsub:0'
nick='mynick'
password='roompassword'>
<event node='urn:xmpp:mucsub:nodes:messages' />

How to use SiriKit for sending data using Web Service?

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

iMessaged-based invitations for GameCenter for iOS 10

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.

Can we use SiriKit for anything else than the 6 types of services it is supposed to support? [duplicate]

I have watched SiriKit in wwdc and read document.
https://developer.apple.com/library/prerelease/content/documentation/Intents/Conceptual/SiriIntegrationGuide/
Add SiriKit support only if your app implements one of the following
types of services:
Audio or video calling
Messaging Payments
Searching photos
Workouts
Ride booking
I am still wondering whether I can do for other services (since my app will be for enterprise app).
My service will be very simple searching only like "Find SQ212 in myapp".
Can it be done? I afraid that sirkit can't support intent for other servies.
No, you can't. That's why it says "only if your app implements one of the following types of services".
You won't get the 'find foo in bar' syntax; each respective service has its own syntax - like "start a workout in MyApp" or "Book a ride to place with MyApp". See https://developer.apple.com/sirikit/ for examples.
I would expect a workaround using the SiriKit API to result in your app being rejected if submitted to the general app store, and I would expect it to be extremely fragile if it passed App Review or didn't go through it in the first place.
I found this article on making Sirikit Extensions that aren't default ones provided by Apple on swifting.io.
Using INVocabulary
From the Apple documentation:
The INVocabulary object lets you augment your app’s fixed vocabulary with terms that are both unique to your app and to the current user of your app. Registering custom terms provides Siri with the hints it needs to apply those terms appropriately to the corresponding intent objects. You may register only specific types of custom terms, such as the name of a contact, the name of a user’s workout, a custom tag applied to a photo, or a user-specific payment type.
public enum INVocabularyStringType : Int {
case contactName
case contactGroupName
case photoTag
case photoAlbumName
case workoutActivityName
case carProfileName
}
INMessage
Here they use INSearchForMessagesIntent to setup an index search for finding support.
struct SupportMe{
static let systems = [
INPerson(personHandle: INPersonHandle(value: "MyNotes",
type: INPersonHandleType.unknown),
nameComponents: nil,
displayName: "MyNotes",
image: nil,
contactIdentifier: "MyNotes",
customIdentifier: "MyNotes")]
static let articles = [
INMessage(identifier: "MyNotesPassword",
content: "Retrieving password in MyNotes app. To retrieve
password use 'forgot password' button that is located below
sign in button. Then type email address that your account has
been assigned to and press reset password",
dateSent: Date(),
sender: SupportMe.systems[0],
recipients: [SupportMe.systems[0]])]
}
extension IntentHandler: INSearchForMessagesIntentHandling{
func handle(searchForMessages intent: INSearchForMessagesIntent,
completion: (INSearchForMessagesIntentResponse) -> Void){
let userActivity = NSUserActivity(activityType: String(INSearchForMessagesIntent.self))
let response = INSearchForMessagesIntentResponse(code: .success,
userActivity: userActivity)
response.messages = [SupportMe.articles[0]]
completion(response)
}
}

how to send verification code by sms in swift 2

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.

Resources