23

Xcode の最新のベータ版をインストールして、Swift 2と、Apple Watch 開発セクションに加えられた改善を試してみました。

iOSWatch OS2NSUserDefaultsの間で情報を共有するこの基本的な方法が機能しない理由を理解するのに苦労しています。

このステップバイステップのチュートリアルに従って、電話アプリケーションと内線番号の両方で同じグループを有効にするなど、プロセスで何かを見逃していないかどうかを確認しましたが、得られたものは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 アプリは異なるグループを利用しているようです...それらは情報を共有しておらず、ローカルに保存しています。

誰かが同じ問題を抱えていますか?それを修正する方法はありますか?

4

5 に答える 5

43

watch OS2 では、共有グループ コンテナーを使用できなくなりました。 アップルのドキュメント:

共有グループ コンテナーを使用して iOS アプリとデータを共有した Watch アプリは、データを別の方法で処理するように再設計する必要があります。watchOS 2 では、各プロセスは、ローカル コンテナー ディレクトリ内の共有データの独自のコピーを管理する必要があります。両方のアプリで実際に共有および更新されるデータの場合、Watch Connectivity フレームワークを使用してそのデータをアプリ間で移動する必要があります。

于 2015-06-15T20:05:08.567 に答える
18

NSUserDefaults (アプリ グループを使用しても) は、iPhone と watchOS 2 の Watch の間で同期しません。iPhone アプリまたは Settings-Watch.bundle から設定を同期する場合は、自分で同期を処理する必要があります。

この場合、WatchConnectivity のユーザー情報転送を使用すると非常にうまく機能することがわかりました。以下に、これを実装する方法の例を示します。このコードは、電話から Watch への一方向の同期のみを処理しますが、他の方法も同じように機能します。

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) いつ設定を Watch にプッシュする必要があるかを決定します
(ここには示されていません)。

3) 設定を Watch にプッシュする

- (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];  
     }  
}  

Watch 拡張機能の場合:
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];  
}  
于 2015-08-12T08:01:24.310 に答える
12

古い機能を再現する簡単な方法があります。古いグループのユーザー デフォルトを辞書にエクスポートし、それを WatchConnectivity フレームワーク全体に送信してから、反対側のユーザー デフォルトに再インポートします。

電話アプリと時計アプリの両方で:

  1. WatchConnectivty フレームワークを追加する
  2. #import <WatchConnectivity/WatchConnectivity.h>そして次のように宣言します WCSessionDelegate
  3. アプリの起動後にセッションを開始するコードを追加します。

    if ([WCSession isSupported]) {
            WCSession* session = [WCSession defaultSession];
            session.delegate = self;
            [session activateSession];
        }
    
  4. これを使用して、更新されたデフォルトを他のデバイスに送信します (現在の の後に呼び出します[defaults synchronize])。

[[WCSession defaultSession] updateApplicationContext:[[[NSUserDefaults alloc] initWithSuiteName:@"group.com.company.myapp"] dictionaryRepresentation] error:nil];

  1. 設定を受け取り、保存してデフォルトに戻します - これを 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])

于 2015-09-17T10:28:01.707 に答える
7

既に述べたように、共有 NSUserDefaults は WatchOS2 では機能しなくなりました。

@RichAbleの回答の迅速なバージョンと、さらにいくつかのメモを次に示します。

iPhone アプリで、次の手順に従います。

Apple Watch にデータをプッシュするビュー コントローラーを選択し、上部にフレームワークを追加します。

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 {

}

ここで、ウォッチ アプリ(この正確なコードは Glances やその他のウォッチ キット アプリ タイプでも機能します) にフレームワークを追加します。

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
        })
    }

}

それだけです。

注意事項:

  1. 新しい applicationContext は何度でも送信できます。時計が近くにあり、接続されているかどうか、または時計アプリが実行されているかどうかは問題ではありません。これにより、インテリジェントな方法でバックグラウンドでデータが配信され、そのデータは時計アプリの起動時に待機しています。
  2. 時計アプリが実際にアクティブで実行されている場合、ほとんどの場合、すぐにメッセージを受け取るはずです。
  3. このコードを逆にして、同じ方法で時計から iPhone アプリにメッセージを送信できます。
  4. ウォッチ アプリが表示されたときに受け取る applicationContext は、最後に送信したメッセージのみになります。時計アプリが表示される前に 20 件のメッセージを送信した場合、最初の 19 件は無視され、20 件目は処理されます。
  5. 2 つのアプリ間の直接/ハード接続、またはバックグラウンド ファイル転送またはキュー メッセージについては、WWDC ビデオをご覧ください。
于 2016-01-26T19:47:53.287 に答える