Xcodeの最新ベータ版をインストールして試してみましたSwift 2と、Apple時計開発セクションに加えられた改善点。
iOSとWatch OS2の間で情報を共有するこの基本的なNSUserDefaults
メソッドが機能しない理由を実際に理解するのに苦労しています。
thisstep-by-steptutorial に従って、電話アプリケーションとの両方で同じグループをオンにするなど、プロセスで何かを見逃していないかどうかを確認しました。拡張機能ですが、これが私が得たものです:[〜#〜] nothing [〜#〜]。
これが私がiPhoneアプリのViewControllerのために書いたものです:
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var lb_testo: UITextField!
let shared_defaults:NSUserDefaults = NSUserDefaults(suiteName: "group.saracanducci.test")!
var name_data:NSString? = ""
override func viewDidLoad() {
super.viewDidLoad()
name_data = shared_defaults.stringForKey("shared")
lb_testo.text = name_data as? String
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
@IBAction func upgrade_name(sender: AnyObject) {
name_data = lb_testo.text
shared_defaults.setObject(name_data, forKey: "shared")
lb_testo.resignFirstResponder()
shared_defaults.synchronize()
}
}
そして、これが私がWatchKitのInterfaceControllerに持っているものです:
import WatchKit
import Foundation
class InterfaceController: WKInterfaceController {
@IBOutlet var lb_nome: WKInterfaceLabel!
let shared_defaults:NSUserDefaults = NSUserDefaults(suiteName: "group.saracanducci.test")!
var name_data:NSString? = ""
override func awakeWithContext(context: AnyObject?) {
super.awakeWithContext(context)
}
override func willActivate() {
super.willActivate()
if (shared_defaults.stringForKey("shared") != ""){
name_data = shared_defaults.stringForKey("shared")
lb_nome.setText(name_data as? String)
}else{
lb_nome.setText("No Value")
}
}
override func didDeactivate() {
super.didDeactivate()
}
}
私はいくつかのテストを行いましたが、iOSアプリとWatch OSは異なるグループを利用しているようです...情報を共有していません、ローカルに保存しています。
誰かが同じ問題を抱えていますか?それを修正する方法はありますか?
ウォッチOS2では、共有グループコンテナを使用できなくなりました。 Apple Docs:
共有グループコンテナを使用してiOSアプリとデータを共有するWatchアプリは、データを異なる方法で処理するように再設計する必要があります。 watchOS 2では、各プロセスがローカルコンテナディレクトリ内の共有データの独自のコピーを管理する必要があります。両方のアプリで実際に共有および更新されるデータの場合、これには、WatchConnectivityフレームワークを使用してそのデータをアプリ間で移動する必要があります。
NSUserDefaults(アプリグループを使用している場合でも)は、watchOS 2のiPhoneとWatchの間で同期しません。iPhoneアプリまたはSettings-Watch.bundleから設定を同期する場合は、自分で同期を処理する必要があります。
この場合、WatchConnectivityのユーザー情報転送を使用すると非常にうまく機能することがわかりました。以下に、これを実装する方法の例を示します。このコードは、電話から時計への一方向の同期のみを処理しますが、他の方法も同じように機能します。
iPhoneアプリ:
1)同期が必要な設定の辞書を準備する
- (NSDictionary *)exportedSettingsForWatchApp
{
NSUserDefaults *userDefaults = [self userDefaults]; // the user defaults to sync
NSSet *keys = [self userDefaultKeysForWatchApp]; // set of keys that need to be synced
NSMutableDictionary *exportedSettings = [[NSMutableDictionary alloc] initWithCapacity:keys.count];
for (NSString *key in keys) {
id object = [userDefaults objectForKey:key];
if (object != nil) {
[exportedSettings setObject:object forKey:key];
}
}
return [exportedSettings copy];
}
2)設定をウォッチにプッシュする必要があるタイミングを決定します
(ここには表示されていません)
3)設定を時計にプッシュします
- (void)pushSettingsToWatchApp
{
// Cancel current transfer
[self.outstandingSettingsTransfer cancel];
self.outstandingSettingsTransfer = nil;
// Cancel outstanding transfers that might have been started before the app was launched
for (WCSessionUserInfoTransfer *userInfoTransfer in self.session.outstandingUserInfoTransfers) {
BOOL isSettingsTransfer = ([userInfoTransfer.userInfo objectForKey:@"settings"] != nil);
if (isSettingsTransfer) {
[userInfoTransfer cancel];
}
}
// Mark the Watch as requiring an update
self.watchAppHasSettings = NO;
// Only start a transfer when the watch app is installed
if (self.session.isWatchAppInstalled) {
NSDictionary *exportedSettings = [self exportedSettingsForWatchApp];
if (exportedSettings == nil) {
exportedSettings = @{ };
}
NSDictionary *userInfo = @{ @"settings": exportedSettings };
self.outstandingSettingsTransfer = [self.session transferUserInfo:userInfo];
}
}
時計拡張機能:
4)ユーザー情報の転送を受信します
- (void)session:(WCSession *)session didReceiveUserInfo:(NSDictionary<NSString *, id> *)userInfo
{
NSDictionary *settings = [userInfo objectForKey:@"settings"];
if (settings != nil) {
// Import the settings
[self importSettingsFromCompanionApp:settings];
}
}
5)受信した設定をウォッチのユーザーデフォルトに保存します
- (void)importSettingsFromCompanionApp:(NSDictionary *)settings
{
NSUserDefaults *userDefaults = [self userDefaults]; // the user defaults to sync
NSSet *keys = [self userDefaultKeysForWatchApp]; // set of keys that need to be synced
for (NSString *key in keys) {
id object = [settings objectForKey:key];
if (object != nil) {
[userDefaults setObject:object forKey:key];
} else {
[userDefaults removeObjectForKey:key];
}
}
[userDefaults synchronize];
}
古い機能を再現する簡単な方法があります。古いグループのユーザーデフォルトを辞書にエクスポートし、それをWatchConnectivityフレームワークに送信してから、反対側のユーザーデフォルトに再インポートします。
電話アプリと時計アプリの両方で:
#import <WatchConnectivity/WatchConnectivity.h>
_そしてWCSessionDelegate
として宣言しますアプリの起動後にセッションを開始するコードを追加します。
_if ([WCSession isSupported]) {
WCSession* session = [WCSession defaultSession];
session.delegate = self;
[session activateSession];
}
_
これを使用して、更新されたデフォルトを他のデバイスに送信します(現在の_[defaults synchronize]
_の後に呼び出します):
_[[WCSession defaultSession] updateApplicationContext:[[[NSUserDefaults alloc] initWithSuiteName:@"group.com.company.myapp"] dictionaryRepresentation] error:nil];
_
設定を受信してデフォルトに戻します-これをWCDelegateに追加します。
_-(void)session:(WCSession *)session didReceiveApplicationContext:(NSDictionary<NSString *,id> *)applicationContext {
NSLog(@"New Session Context: %@", applicationContext);
NSUserDefaults *defaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.com.company.myapp"];
for (NSString *key in applicationContext.allKeys) {
[defaults setObject:[applicationContext objectForKey:key] forKey:key];
}
[defaults synchronize];
}
_
WC以外のデバイスのサポートを維持するように注意してください-updateApplicationContext呼び出しをif ([WCSession isSupported])
でラップします
すでに述べたように、共有NSUserDefaultsはWatchOS2では機能しなくなりました。
これが@RichAbleの答えのSwiftバージョンで、さらにいくつかのメモがあります。
iPhoneアプリで、次の手順に従います。
データをApple Watch fromからプッシュし、フレームワークを上部に追加するビューコントローラーを選択します。
import WatchConnectivity
次に、時計とのWatchConnectivityセッションを確立し、データを送信します。
if WCSession.isSupported() { //makes sure it's not an iPad or iPod
let watchSession = WCSession.defaultSession()
watchSession.delegate = self
watchSession.activateSession()
if watchSession.paired && watchSession.watchAppInstalled {
do {
try watchSession.updateApplicationContext(["foo": "bar"])
} catch let error as NSError {
print(error.description)
}
}
}
デリゲートの設定をスキップすると、これは機能しないことに注意してください。したがって、デリゲートを使用したことがない場合でも、デリゲートを設定して、次の拡張機能を追加する必要があります。
extension MyViewController: WCSessionDelegate {
}
これで、時計アプリ(この正確なコードはGlanceやその他の時計キットアプリタイプでも機能します)にフレームワークを追加します。
import WatchConnectivity
次に、接続セッションを設定します。
override func awakeWithContext(context: AnyObject?) {
super.awakeWithContext(context)
let watchSession = WCSession.defaultSession()
watchSession.delegate = self
watchSession.activateSession()
}
iOSアプリからのメッセージを聞いて処理するだけです。
extension InterfaceController: WCSessionDelegate {
func session(session: WCSession, didReceiveApplicationContext applicationContext: [String : AnyObject]) {
print("\(applicationContext)")
dispatch_async(dispatch_get_main_queue(), {
//update UI here
})
}
}
これですべてです。
注意事項:
これを手に入れるのに何時間もかかりました。この非常に便利なビデオをご覧ください! WatchConnectivityを使用してiPhoneアプリとwacthの間でNSUserDefaultを共有する方法の基本的な考え方を説明します。