Swift: How to use handoff in the simplest way possible? - swift

I am trying to use handoff to make an iphone app do something when the user does something in the watchkit app. In the watch app (in InterfaceController.swift), I have this code that gets run when the user taps a button:
self.updateUserActivity("com.test", userInfo: ["one":"two"], webpageURL: nil)
Then in the AppDelegate.swift file of the phone app, I have this code:
func application(application: UIApplication!,
continueUserActivity userActivity: NSUserActivity!,
restorationHandler: (([AnyObject]!) -> Void)!)
-> Bool {
let userInfo = userActivity.userInfo
println("testing: \(userInfo)")
return true
}
In theory this should print the userInfo (in this case ["one":"two"]) to the console, but I think I'm missing something here.

Related

How to implement CallKit in real app?

I am trying to implement Apple CallKit in my VoIP application. I am using Xcode 9.2, Swift 4.0.3, iOS 10.3. Problem is I do not know how exactly to do this. I have tried to search for tutorial in Web, but I failed to find tutorial based on real system. They all using fake systems, only simulate calls! I have a class which rules with someone third person library which is responsible for the calls. So, if I have incoming call happens, some event goes through observer. Like this:
NotificationCenter.default.addObserver(forName: Notification.Name(rawValue: Notifications.Name.transMessage.rawValue), object: nil, queue: nil) { notification in
self.handleLibtransEvents()
}
where self.handleLibtransEvents is private function calling calls.
Plus, I have installed working PUSH Notification system in AppDelegate.swift. Like this:
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
print("NOTIFICATION ERROR: \(error)")
}
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
let pushToken = deviceToken.reduce("", {$0 + String(format: "%02X", $1)}).lowercased()
print("pushToken: \(pushToken)")
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
if UIApplication.shared.applicationState != UIApplicationState.active {
// PUSH: Incoming call event!
}
}
So there are two places, I can catch incoming call but I have not any idea how to catch real call through Apple CallKit. I will be thankful for any help, advice, call example. Thanks!
P. S. I have installed all settings correctly.
CallKit is basically a framework to show up a Call UI when ever you receive a voip call or make a new call, So it will do nothing if you pass it a number n assume it will make call, Keep it in mind its only to show a UI for receive call & make call.
To make calls n receive calls you will need 3rd party services like Sinch and many other.

How to detect if an app was opened by a notification action in the ViewController

I am working on a notification app and was wondering if it is possible to detect if the app is opened from a notification action in ViewController.Swift instead of the AppDelegate.swift. How can I do this?
Krish, Whenever the app is launched the AppDelegate gets called(if the default Main class is not modified) and in the AppDelegate class you can check for the launch option in launch option delegate whether its opened through remote notification. This is the first action where you will catch the app opening event.
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
let remoteNotif = launchOptions?[UIApplicationLaunchOptionsKey.remoteNotification] as? NSDictionary
if remoteNotif != nil {
let notifName = remoteNotif?["aps"] as! String
print("Notification: \(notifName )")
}
else {
print("Not remote")
}
}
Here is a complete and easy answer to that
After you handle the event on AppDelegate you can use an observer to let your ViewController of that event.
Normally you should redirect the user to a specific view, depending on the notification payload.

Sirikit and parent app communication in ios 10 : Handoff

I am using Sirikit to integrate with my payment domain app where I need to interact with the app. I read Apple documentation, they asked to use common frameworks.
Is it possible to use handoff? if yes then how?
How can I call the other viewController which is in parent app from sirikit?
I will really appreciate for any help. Thanks
Every user activity object needs a type and we need to define those types in the
info.plist of the application
For Eg.
let userActivity = NSUserActivity(activityType: "uaType")
userActivity.title = "uaTitle"
userActivity.userInfo = ["uaKey": "uaValue"]
You can now access this activity object in AppDelegate as follows
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: #escaping ([Any]?) -> Void) -> Bool {
switch userActivity.activityType {
case "uaType":
//Write your logic to access uaKey & uaValue here
return true
default: return false
}
}
Check SiriKit Programming Guide,
To use handoff, You can create intent response object with NSUserActivity object. While creating NSUserActivity object assign userInfo property to appropriate object that you want,
let userActivity = NSUserActivity()
userActivity.userInfo = ["myKey": myAnyObject]
You will get this NSUserActivity object in parent application AppDelegate,
optional public func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: ([AnyObject]?) -> Swift.Void) -> Bool
Here you can get userInfo object which you can compare as per your requirement and call appropriate viewController.

Updating Glance data in watchOS2.2

I'm hoping you smart people can help me as most of the data online is out of date.
I have an iPhone app that displays financial information.
I would like to present this on a watch glance screen.
I can get the app to send the dictionary of the latest information and the glance does update live if both the Glance screen and phone app are open.
I would like to know how to use the Glance screen to ask the phone app for the latest information.
The phone app will probably be closed so it would need waking up and then asked for the current information.
I'm using swift 7 and WatchOS 2.2 and IOS 9.3
A lot of information here on Stackoverflow refers to watchOS 1 so no longer works.
I look forward to your solutions.
Look into WCSession as there are different methods for sending different types of data. This implementation is sending a dictionary.
Must setup a WCSession on both watch and phone devices. AppDelegate in didFinishLaunchingWithOptions: and I use the ExtensionDelegate in its init method. Be sure to import WatchConnectivity when using WCSession. Using the AppDelegate as a WCSessionDelegate below.
// AppDelegate.swift
class AppDelegate: UIResponder, UIApplicationDelegate, WCSessionDelegate {
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Setup session on phone
if WCSession.isSupported() {
let session = WCSession.defaultSession()
session.delegate = self
session.activateSession()
}
return true
}
// WCSessionDelegate method receiving message from watch and using callback
func session(session: WCSession, didReceiveMessage message: [String : AnyObject], replyHandler: ([String : AnyObject]) -> Void) {
// Reply with a dictionary of information based on the "message"
replyHandler(["Key": "Value"])
}
}
Setup WCSession on the watch:
// ExtensionDelegate.swift
override init() {
let session = WCSession.defaultSession()
session.activateSession()
}
Send message, consisting of a dictionary, to the phone in order to receive information in the callback:
// GlanceController.swift
WCSession.defaultSession().sendMessage(["Please give Glance data": "Value"], replyHandler:{ (response) in
// Extract data from response dictionary
}) { (error) in
// Handle error
}

watchOS2 app and iPhone app communication

In the watchOS1, we had a method “openParentApplication”. This method communicated with the phone application even when it wasn’t running in foreground or background and fetched a reply immediately. I need something similar for watchOS2. I want my watch application to communicate immediately with the phone app even if my iPhone application is not running. Methods like updateApplicationContext:error:, sendMessage:replyHandler:errorHandler: and transferUserInfo: are not helpful in this scenario.
Please can someone suggest me a better approach to achieve this?
Actually sendMessage:replyHandler:errorHandler: is doing exactly what you are asking for. As long as your watch is connected to your phone it immediately gets a response to the message. This is working when the app is in the foreground, in the background or not running at all.
Here is how you set it up:
In the WatchExtension:
Setup the session. Typically in your ExtensionDelegate:
func applicationDidFinishLaunching() {
if WCSession.isSupported() {
let session = WCSession.defaultSession()
session.delegate = self
session.activateSession()
}
}
And then send the message when you need something from the app:
if WCSession.defaultSession().reachable {
let messageDict = ["message": "hello iPhone!"]
WCSession.defaultSession().sendMessage(messageDict, replyHandler: { (replyDict) -> Void in
print(replyDict)
}, errorHandler: { (error) -> Void in
print(error)
}
}
In the iPhone App:
Same session setup, but this time also set the delegate:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
...
if WCSession.isSupported() {
let session = WCSession.defaultSession()
session.delegate = self
session.activateSession()
}
}
And then implement the delegate method to send the reply to the watch:
func session(session: WCSession, didReceiveMessage message: [String : AnyObject], replyHandler: ([String : AnyObject]) -> Void) {
replyHandler(["message": "Hello Watch!"])
}
This works whenever there is a connection between the Watch and the iPhone. If the app is not running, the system starts it in the background. So, basically it just works like openParentApplication(_:reply:)