- 当需要叠加
UITabBarController
和UINavigationController
时,应将后者放在前者之中。
- 当需要新的控制器不显示Tab Bar时,应该在它的控制器选中
Hide Botton Bar on Push
.
UITabBarController
和UINavigationController
时,应将后者放在前者之中。Hide Botton Bar on Push
.Currently WKWatchConnectivityRefreshBackgroundTask
is only called for sure on a watchOS Simulator when the watchOS extension's WCSession
is in notActivated
state and the extension is not running in foreground (in background or terminated).
In real devices, it won't be called in my tests. But Apple docs says it may. So you shouldn't rely on it won't be called until Apple changes its docs.
For WCSession
, when it is activated
, you can transfer userInfo, and when the counterpart is active, it can get the userInfo. The counterpart won't need to be in foreground to be activated, it can be in a high priority background.
Here are my testing results.
WCSession
notActivated
?WCSession.activate()
in your code on watchOS Extension side. As WCSession
is notActivated
by default.func updateApplicationContext([String : Any])
的传输这个方法的传输会对数据进行优化,连续发送相同的数据,后发的不会被传输。
正如这个函数的名称那样,这个函数用于发送程序状态的信息,如果有多个状态,那么连续发送相同的,只有第一个会被发送。
activated WCSession
in the sending app. That is the first condition to check before sending data.sendMessage(_:replyHandler:errorHandler:)
and sendMessageData(_:replyHandler:errorHandler:)
, it is needed to check isReachable
to be true as well.iOSDeviceNeedsUnlockAfterRebootForReachability
for if the iOS device needs to unlock after rebooting.isPaired
and isWatchAppInstalled
before sending any data.// iOS app
class AppDelegate: UIResponder, UIApplicationDelegate, WCSessionDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
if WCSession.isSupported() {
let session = WCSession.default()
session.delegate = self
session.activate()
}
return true
}
extension AppDelegate:WCSessionDelegate {
public func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
guard error == nil else { fatalError(error!.localizedDescription) }
}
}
// view controller
class ViewController: UIViewController {
@IBAction func sendButtonClicked(_ sender: Any) {
if WCSession.isSupported() {
let session = WCSession.default()
if session.activationState == .activated {
if session.isWatchAppInstalled && session.isPaired {
session.transferUserInfo(["send test":nil])
}
}
}
}
}
// watchOS app
class ExtensionDelegate: NSObject, WKExtensionDelegate {
func applicationDidFinishLaunching() {
// Perform any final initialization of your application.
let session = WCSession.default()
session.delegate = self
session.activate()
}
func applicationDidBecomeActive() {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
func applicationWillResignActive() {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, etc.
}
var total = 0
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.setTaskCompleted()
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.
total += 1
DispatchQueue.main.async {
if let viewController = WKExtension.shared().rootInterfaceController as? InterfaceController {
viewController.activeBurnedEnergyLabel.setText(String(self.total))
}
}
connectivityTask.setTaskCompleted()
case let urlSessionTask as WKURLSessionRefreshBackgroundTask:
// Be sure to complete the URL session task once you’re done.
urlSessionTask.setTaskCompleted()
default:
// make sure to complete unhandled task types
task.setTaskCompleted()
}
}
}
}
extension ExtensionDelegate: WCSessionDelegate {
public func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
guard error == nil else { fatalError(error!.localizedDescription) }
}
/** -------------------------- Background Transfers ------------------------- */
public func session(_ session: WCSession, didReceiveUserInfo userInfo: [String : Any] = [:]) {
total += 4
DispatchQueue.main.async {
if let viewController = WKExtension.shared().rootInterfaceController as? InterfaceController {
viewController.activeBurnedEnergyLabel.setText(String(self.total))
}
}
}
}