11

iOS と watchOS の間でユーザー資格情報を同期する際に問題が発生しました。

私の基本的なセットアップは、iOS アプリと watchOS アプリの両方がバックエンド サーバーと通信する必要があり、そのためにアクセス トークンが必要であるということです。ただし、ユーザーは iOS アプリでのみサインインできます (ユーザーとパスワードを入力する必要があるため)。

ここで、ユーザーが iOS にサインインする (またはその後アプリを開く) と、updateApplicationContext() を使用してユーザーの資格情報を watchOS に送信します。ユーザーがログアウトすると、次のように同様のことが行われます。

func logInOnWatch() {
    if WCSession.isSupported() {
        session.activate()

        var userInfo = [String : Any]()
        userInfo["type"] = "logInConfirm"
        userInfo[userKey.isLoggedIn] = true
        let deviceUserID = KeychainAccess.password(for: userKey.ID, service: userKey.keyChain)
        userInfo[userKey.ID] = deviceUserID
        let accessTokenSecret = KeychainAccess.password(for: userKey.accessTokenSecret, service: userKey.keyChain)
        userInfo[userKey.accessTokenSecret] = accessTokenSecret

        do {
            try session.updateApplicationContext(userInfo)
        }
        catch {
            print(error)
        }
    }
}

func logOutOnWatch() {
    if WCSession.isSupported() {
        session.activate()

        var dict = [String : Any]()
        dict["type"] = "logInConfirm"
        dict["logInStatus"] = "User Has Not Logged In"

        do {
            try session.updateApplicationContext(dict)
        }
        catch {
            print(error)
        }
    }
}

次に、データを受信し、時計側のインターフェイスを次のように更新します。

func session(_ session: WCSession, didReceiveApplicationContext applicationContext: [String : Any]) {
    if let contextType = applicationContext["type"] as? String {
        switch contextType {
        case "logInConfirm":
            saveUserDataToDisk(from: applicationContext)
            reloadRootControllersIfNeeded()

        ... // Handle other types of data

        default:
            return
        }
    }
}

func saveUserDataToDisk(from userInfo: [String : Any]) {
    if let _ = userInfo[userKey.isLoggedIn] {
        userDefaults.set(true, forKey: userKey.isLoggedIn)
        if let token = userInfo[userKey.accessTokenSecret] as? String {
            KeychainAccess.setPassword(token, for: userKey.accessTokenSecret, service: userKey.keyChain)
        }
        if let userID = userInfo[userKey.ID] as? String {
            KeychainAccess.setPassword(userID, for: userKey.ID, service: userKey.keyChain)
        }
    }
    else {
        removeAllData()
    }
}

func reloadRootControllersIfNeeded() {
    if (userDefaults.object(forKey: userKey.isLoggedIn) == nil) {
        /// Display the logged out controller if it isn't already the root controller.
        if (loggedIn == nil) || loggedIn! {
            WKInterfaceController.reloadRootControllers(withNames: ["LoggedOutController"], contexts: [self])
        }
        loggedIn = false
    }
    else {
        /// Display the home controller if the logged out controller is the root controller.
        if (loggedIn == nil) || !loggedIn! {
            WKInterfaceController.reloadRootControllers(withNames: ["HomeController"], contexts: [self])
        }
        loggedIn = true
    }
}

これは、ユーザーがログインするときとユーザーがログアウトするときにすべて正常に機能します。

ただし、ログイン後にアプリを使用すると、時々、時計がルートコントローラーをログアウトしたコントローラーに切り替えます(おそらく、ユーザーのデフォルトからログインフラグを削除することを伝えるメッセージを受信したため、ログアウトするように指示したためです) )。

Xcode を使用してこれが発生した場合にキャッチする良い方法はありませんが、散発的に発生します。さらに悪いことに、iOS でアプリ (タブ バー コントローラーの viewDidAppear から logInOnWatch() を呼び出す) を開くと、時計が更新されません。ウォッチを更新する唯一の方法は、iOS でログアウトして再度ログインすることです。その後、時計は認証情報とログイン フラグを受け取ります。

ユーザーがログインすると、iOS から watchOS にユーザー データを送信するアプリのライフ サイクル全体で他のインスタンスがあり、それらは問題なく動作します。Apple が時計でユーザーのデフォルトを処理する方法に問題があるのか​​ 、それとも WatchConnectivity に問題があるのか​​ 疑問に思っています。

このデータの同期をより一貫して維持するためのより良い方法はありますか?

4

0 に答える 0