Skip to content

Commit

Permalink
Apple Watch support
Browse files Browse the repository at this point in the history
  • Loading branch information
jbornemann committed Jan 17, 2018
1 parent 0c13c6f commit 673b745
Show file tree
Hide file tree
Showing 19 changed files with 835 additions and 42 deletions.
307 changes: 303 additions & 4 deletions FreeOTP.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

5 changes: 4 additions & 1 deletion FreeOTP/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,11 @@ import UIKit

@UIApplicationMain
class AppDelegate : UIResponder, UIApplicationDelegate {

var window: UIWindow?


let watchSessionDelegate = WatchSessionDelegate()

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
return true
}
Expand Down
1 change: 1 addition & 0 deletions FreeOTP/Assets.xcassets/AppIcon.appiconset/Contents.json
Original file line number Diff line number Diff line change
Expand Up @@ -104,3 +104,4 @@
"author" : "xcode"
}
}

74 changes: 37 additions & 37 deletions FreeOTP/Base.lproj/Main.storyboard

Large diffs are not rendered by default.

43 changes: 43 additions & 0 deletions FreeOTP/WatchSessionDelegate.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
//
// WatchSessionDelegate.swift
// FreeOTP
//
// Created by Jeff Bornemann on 1/16/18.
// Copyright © 2018 Fedora Project. All rights reserved.
//

import Foundation
import WatchConnectivity

class WatchSessionDelegate : NSObject, WCSessionDelegate {

override init() {
super.init()
if WCSession.isSupported() {
let session = WCSession.default
session.delegate = self
session.activate()
}
}

func session(_ session: WCSession,
didReceiveMessage message: [String : Any],
replyHandler: @escaping ([String : Any]) -> Void) {
let store: Int = message["store"] as! Int
let nextToken: Token? = TokenStore().load(store)
if nextToken != nil {
replyHandler(["token": nextToken?.codes[0].value as Any,
"account": nextToken?.account as Any,
"to": nextToken?.codes[0].to as Any])
}
else {
replyHandler(["token": "",
"account": "",
"to": Date(timeIntervalSinceNow: 5)])
}
}

func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {}
func sessionDidBecomeInactive(_ session: WCSession) {}
func sessionDidDeactivate(_ session: WCSession) {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"images" : [
{
"idiom" : "watch",
"screenWidth" : "{130,145}",
"scale" : "2x"
},
{
"idiom" : "watch",
"screenWidth" : "{146,165}",
"scale" : "2x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"assets" : [
{
"idiom" : "watch",
"filename" : "Circular.imageset",
"role" : "circular"
},
{
"idiom" : "watch",
"filename" : "Extra Large.imageset",
"role" : "extra-large"
},
{
"idiom" : "watch",
"filename" : "Modular.imageset",
"role" : "modular"
},
{
"idiom" : "watch",
"filename" : "Utilitarian.imageset",
"role" : "utilitarian"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"images" : [
{
"idiom" : "watch",
"screenWidth" : "{130,145}",
"scale" : "2x"
},
{
"idiom" : "watch",
"screenWidth" : "{146,165}",
"scale" : "2x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"images" : [
{
"idiom" : "watch",
"screenWidth" : "{130,145}",
"scale" : "2x"
},
{
"idiom" : "watch",
"screenWidth" : "{146,165}",
"scale" : "2x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"images" : [
{
"idiom" : "watch",
"screenWidth" : "{130,145}",
"scale" : "2x"
},
{
"idiom" : "watch",
"screenWidth" : "{146,165}",
"scale" : "2x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

71 changes: 71 additions & 0 deletions freeotpwatch Extension/ExtensionDelegate.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
//
// ExtensionDelegate.swift
// FreeOTPWatch Extension
//
// Created by Jeff Bornemann on 1/15/18.
// Copyright © 2018 Fedora Project. All rights reserved.
//

import WatchKit
import WatchConnectivity

class ExtensionDelegate: NSObject, WKExtensionDelegate, WCSessionDelegate {

var currentToken: String = ""
var account: String = ""

var to: Date = Date(timeIntervalSinceNow: 5)

func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {}

func applicationDidFinishLaunching() {
if WCSession.isSupported() {
let session = WCSession.default
session.delegate = self
session.activate()
}
}

func updateToken() {
if WCSession.isSupported() {
let session = WCSession.default
if session.isReachable {
session.sendMessage(["store": 0], replyHandler: { (replyMessage) -> Void in
self.currentToken = replyMessage["token"] as! String
self.account = replyMessage["account"] as! String
self.to = replyMessage["to"] as! Date
})
}
else {
self.currentToken = ""
self.account = ""
self.to = Date(timeIntervalSinceNow: 5)
}
}
}

func handle(_ backgroundTasks: Set<WKRefreshBackgroundTask>) {
// Sent when the system needs to launch the application in the background to process tasks. Tasks arrive in a set, so loop through and process each one.
for task in backgroundTasks {
// Use a switch statement to check the task type
switch task {
case let backgroundTask as WKApplicationRefreshBackgroundTask:
// Be sure to complete the background task once you’re done.
backgroundTask.setTaskCompletedWithSnapshot(false)
case let snapshotTask as WKSnapshotRefreshBackgroundTask:
// Snapshot tasks have a unique completion call, make sure to set your expiration date
snapshotTask.setTaskCompleted(restoredDefaultState: true, estimatedSnapshotExpiration: Date.distantFuture, userInfo: nil)
case let connectivityTask as WKWatchConnectivityRefreshBackgroundTask:
// Be sure to complete the connectivity task once you’re done.
connectivityTask.setTaskCompletedWithSnapshot(false)
case let urlSessionTask as WKURLSessionRefreshBackgroundTask:
// Be sure to complete the URL session task once you’re done.
urlSessionTask.setTaskCompletedWithSnapshot(false)
default:
// make sure to complete unhandled task types
task.setTaskCompletedWithSnapshot(false)
}
}
}

}
48 changes: 48 additions & 0 deletions freeotpwatch Extension/Info.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>FreeOTPWatch Extension</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>XPC!</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>CLKComplicationPrincipalClass</key>
<string>$(PRODUCT_MODULE_NAME).ComplicationController</string>
<key>CLKComplicationSupportedFamilies</key>
<array>
<string>CLKComplicationFamilyModularSmall</string>
<string>CLKComplicationFamilyModularLarge</string>
<string>CLKComplicationFamilyUtilitarianSmall</string>
<string>CLKComplicationFamilyUtilitarianSmallFlat</string>
<string>CLKComplicationFamilyUtilitarianLarge</string>
<string>CLKComplicationFamilyCircularSmall</string>
<string>CLKComplicationFamilyExtraLarge</string>
</array>
<key>NSExtension</key>
<dict>
<key>NSExtensionAttributes</key>
<dict>
<key>WKAppBundleIdentifier</key>
<string>org.fedorahosted.freeotp.watchkitapp</string>
</dict>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.watchkit</string>
</dict>
<key>WKExtensionDelegateClassName</key>
<string>$(PRODUCT_MODULE_NAME).ExtensionDelegate</string>
</dict>
</plist>
68 changes: 68 additions & 0 deletions freeotpwatch Extension/InterfaceController.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
//
// InterfaceController.swift
// FreeOTPWatch Extension
//
// Created by Jeff Bornemann on 1/15/18.
// Copyright © 2018 Fedora Project. All rights reserved.
//

import WatchKit
import WatchConnectivity
import Foundation


class InterfaceController: WKInterfaceController {

@IBOutlet var token: WKInterfaceLabel!
@IBOutlet var account: WKInterfaceLabel!

var timer: Timer?

let delegate: ExtensionDelegate = WKExtension.shared().delegate as! ExtensionDelegate

@IBAction func update() {
delegate.updateToken()
updateText()
setTimer()
}

func updateText() {
if !delegate.currentToken.isEmpty {
account.setText(delegate.account)
token.setText(delegate.currentToken)
}
else {
account.setText("")
token.setText("Connecting..")
}
}

func setTimer() {
unsetTimer()
let timeToRun = delegate.to.timeIntervalSinceNow > 10 ? delegate.to.timeIntervalSinceNow : TimeInterval(10)
timer = Timer.scheduledTimer(timeInterval: timeToRun, target: self, selector: #selector(update), userInfo: nil, repeats: false)
}

func unsetTimer() {
timer?.invalidate()
timer = nil
}

override func willActivate() {
super.willActivate()
// This method is called when watch view controller is about to be visible to user
update()
}

override func awake(withContext context: Any?) {
super.awake(withContext: context)
}

override func didDeactivate() {
// This method is called when watch view controller is no longer visible
super.didDeactivate()
unsetTimer()
}

}

Loading

0 comments on commit 673b745

Please sign in to comment.