watchOS 2 Reachability in Swift - ios

I have looked around at some of the similar answers but none of these seem to be helping me.
I seem to be having a problem with my application. I have created the single view application and also added in the WCSessionDelegate into my extension.
import WatchKit
class ExtensionDelegate: NSObject, WKExtensionDelegate, WCSessionDelegate { }
I have also checked the session if the session is not there and told it to print out if it cant find it
guard WCSession.isSupported() else {
print("Session is not supported")
return
}
let session = WCSession.defaultSession()
session.delegate = self
session.activateSession()
However I am still getting a No WatchConnectivity error. I'm confused as If the session is working then I think I have it coded right?

Answer
Whilst waiting for your code, I think I can see the issue. Where you have declared the session delegate as a delegate here:
import WatchKit
class ExtensionDelegate: NSObject, WKExtensionDelegate, WCSessionDelegate { }
You need to also import WatchConnectivity
like so:
import WatchKit
import WatchConnectivity
class ExtensionDelegate: NSObject, WKExtensionDelegate, WCSessionDelegate { }
Let me know if his helps!
Tutorial
There is a tutorial which explains exactly this issue: http://ios-blog.co.uk/tutorials/swift/watchos-2-checking-reachability/
Plugin
Also in the same search is a nift plugin you can use: https://github.com/ashleymills/Reachability.swift - This would be my option if you're not confident enough
Tip
(Google is your friend)

Related

Checkk if Apple Watch is connected (Swift 5)

I have made an application for iOS device to get the heart rate data continuously from the watch. It is working as intended and I wanted to add a test case checking if the watch is connected (paired) with the device. My code for testing it is:
if WCSession.isSupported() {
let wcsession = WCSession.default
wcsession.delegate = self as? WCSessionDelegate
wcsession.activate()
if(wcsession.isPaired){
print("paired")
}else{
print("not paired")
}
}
However, I get an error:
2020-02-29 15:25:55.044843+0900 HeartRateApp[68975:11196372] [WC] denying activation due to missing delegate
2020-02-29 15:25:55.044969+0900 HeartRateApp[68975:11196372] [WC] WCSession has not been activated
even though everything is working and I receive the data from the watch successfully...
I have looked at other questions here but they all have similar solutions:
Solution 1
Solution 2
Problably self as? WCSessionDelegate returns nil because the class doesn't implement the WCSessionDelegate protocol. The cast as? WCSessionDelegate should not be necessary. You need to make your class conform to the protocol (as seen in Solution 2):
class SomeClass: WCSessionDelegate {
// ...
}

Nearby Bluetooth devices using Swift 3.0

I'm looking for a way to programmatically list any nearby Bluetooth devices (discoverable) that my device finds. I have not been able to find any information or tutorials regarding performing this call in Swift 3.0. This Q-A post discusses finding these devices using Swift 1.0 and building in Xcode 6, rather than the latest version 8.
I did my best to try to make my code into the 3.0 Syntax from the 1.0, but while running the following code, nothing is returned in the Playground:
import Cocoa
import IOBluetooth
import PlaygroundSupport
class BlueDelegate : IOBluetoothDeviceInquiryDelegate {
func deviceInquiryComplete(_ sender: IOBluetoothDeviceInquiry, error: IOReturn, aborted: Bool) {
aborted
print("called")
let devices = sender.foundDevices()
for device : Any? in devices! {
if let thingy = device as? IOBluetoothDevice {
thingy.getAddress()
}
}
}
}
var delegate = BlueDelegate()
var inquiry = IOBluetoothDeviceInquiry(delegate: delegate)
inquiry?.start()
PlaygroundPage.current.needsIndefiniteExecution = true
Using IOBluetooth the Correct Way
The following code works flawlessly in Xcode Version 8.2.1 (8C1002), Swift 3.0. There are a few lines that aren't required, such as the entire method of deviceInquiryStarted.
Update: These usages still work as of Xcode 9.2 (9B55) and Swift 4.
Playground
import Cocoa
import IOBluetooth
import PlaygroundSupport
class BlueDelegate : IOBluetoothDeviceInquiryDelegate {
func deviceInquiryStarted(_ sender: IOBluetoothDeviceInquiry) {
print("Inquiry Started...")
//optional, but can notify you when the inquiry has started.
}
func deviceInquiryDeviceFound(_ sender: IOBluetoothDeviceInquiry, device: IOBluetoothDevice) {
print("\(device.addressString!)")
}
func deviceInquiryComplete(_ sender: IOBluetoothDeviceInquiry!, error: IOReturn, aborted: Bool) {
//optional, but can notify you once the inquiry is completed.
}
}
var delegate = BlueDelegate()
var ibdi = IOBluetoothDeviceInquiry(delegate: delegate)
ibdi?.updateNewDeviceNames = true
ibdi?.start()
PlaygroundPage.current.needsIndefiniteExecution = true
Project-Application Usage
import Cocoa
import IOBluetooth
import ...
class BlueDelegate : IOBluetoothDeviceInquiryDelegate {
func deviceInquiryStarted(_ sender: IOBluetoothDeviceInquiry) {
print("Inquiry Started...")
}
func deviceInquiryDeviceFound(_ sender: IOBluetoothDeviceInquiry, device: IOBluetoothDevice) {
print("\(device.addressString!)")
}
}
//other classes here:
//reference the following outside of any class:
var delegate = BlueDelegate()
var ibdi = IOBluetoothDeviceInquiry(delegate: delegate)
//refer to these specifically inside of any class:
ibdi?.updateNewDeviceNames = true
ibdi?.start() //recommended under after an action-button press.
Explanation
The issue I was originally faced with was trying to access the information as the inquiry was still in process.
When I accessed it, under many different occasions my playground would hang and I would be forced to force quit both Xcode.app, and com.apple.CoreSimulator.CoreSimulatorService from the Activity Monitor. I lead myself to believe that this was just a Playground bug, only to learn that my application would crash once the inquiry finished.
As Apple's API Reference states:
Important Note: DO NOT perform remote name requests on devices from delegate methods or while this object is in use. If you wish to do your own remote name requests on devices, do them after you have stopped this object. If you do not heed this warning, you could potentially deadlock your process.
Which entirely explained my issue. Rather than directly asking for the IOBluetoothDevice information from the sender.foundDevices() method (which I believe may not have been updating..?) I simply used the parameters built into the function to mention that it was indeed an IOBluetoothDevice object, and simply to ask for that information to be printed.
Final Note
I hope that this Q/A I've created helps others in need when using IOBluetooth in Swift. The lack of any tutorials and the high amounts of outdated, Objective-C code made finding this information very challenging. I'd like to thank #RobNapier for the support on trying to find the answer to this riddle in the beginning. I'd also like to thank NotMyName for the reply on my post on the Apple Developer Forums.
I will be exploring the usage of this in an iOS device more sooner than later!

Cannot call value of non-function type UIApplication when trying to open google maps URL

I'm new to swift programming and I stumbled upon a problem which can't seem to find a solution after searching the web.
What i'm trying to do is when a button is tapped in my application I want the Google maps app to launch but after implementing the code I get the error: Cannot call value of non-function type UIApplication
Am I missing something?
import UIKit
import GoogleMaps
class MapDisplayViewController: UIViewController, GMSMapViewDelegate, CLLocationManagerDelegate, UIApplicationDelegate {
#IBOutlet weak var openDirections: UIButton!
#IBAction func openMapsDirection(_ sender: UIButton!) {
if (UIApplication.sharedApplication().canOpenURL(NSURL(string:"comgooglemaps://")!)) {
UIApplication.sharedApplication().openURL(NSURL(string:
"comgooglemaps://?center=40.765819,-73.975866&zoom=14&views=traffic")!)
} else {
print("Can't use comgooglemaps://");
}
}
}
In Swift 3 sharedApplication() has been replaced with a property called shared.
Try updating your code:
if (UIApplication.shared.canOpenURL(NSURL(string:"comgooglemaps://")!)) {
UIApplication.shared.openURL(NSURL(string:
"comgooglemaps://?center=40.765819,-73.975866&zoom=14&views=traffic")!)
} else {
print("Can't use comgooglemaps://");
}
"comgooglemaps:// and comgooglemaps-x-callback:// - These schemes allow you to launch the Google Maps app for iOS and perform one of several actions"
Please make sure that your device already installed Google Maps app.
https://developers.google.com/maps/documentation/ios-sdk/urlscheme
Hope this will help you.

Why is session.paired unavailable?

In an iOS app, I've created a swift file named DataCoordinator with the following code:
import UIKit
import WatchConnectivity
class DataCoordinator: NSObject {
func test(session:WCSession!) {
if session.paired == true {
//...
}
}
}
When I try to build, I get this error:
'paired' is unavailable
'paired' has been explicitly marked unavailable here
This is in the iOS app and not the in the WatchOS app. It works fine if I use the above code in a ViewController class.

Check if iPhone is paired with apple watch?

In my app,
I need to find if my phone is paired with a apple watch and get some information about the paired watch like its name. I tried reading the documentation but I couldn't seem to find any thing specific to my use case.
Any help is appreciated.
So since WatchOS 2 that is possible !
You have to do on iPhone side :
First :
import WatchConnectivity
Then :
if WCSession.isSupported() { // check if the device support to handle an Apple Watch
let session = WCSession.default()
session.delegate = self
session.activate() // activate the session
if session.isPaired { // Check if the iPhone is paired with the Apple Watch
// Do stuff
}
}
I hope It would help you :)
The best you can do is write to a shared NSUserDefaults value the first time the user opens your WK app, then check for that value in your iOS app. Beyond that there's no info you can get.
The idea is taken from #BilalReffas answer, but in WatchOS versions greater than 2.1 activate() method is asynchronous, so the offered solution won't work (it always returns false, even if watch is connected)
Firstly import SDK
import WatchConnectivity
Then implement session activation request
if WCSession.isSupported() { // check if the device support to handle an Apple Watch
let session = WCSession.default
session.delegate = self
session.activate() // activate the session
}
Then implement methods from WCSessionDelegate
func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
if activationState == .activated && session.isPaired { // Check if the iPhone is paired with the Apple Watch
// Do stuff
}
}

Resources