2016-11-12 44 views
7

我正在使用Xamarin開發Apple Watch應用程序。我正嘗試用我的SendMessage功能將手錶中的信息發送到iPhone。當我這樣做時,我收到out錯誤消息payload could not be delivered。我只能讀取部分消息(「payload could n ...」),因爲我將它寫在標籤上(因爲我的調試器在Xamarin中不起作用,我無法看看消息),但是在做一些谷歌搜索我假設這就是它寫的。任何想法爲什麼?這是我的代碼:WCSession發送消息給出錯誤「無法傳送有效負載」

public sealed class WCSessionManager : NSObject, IWCSessionDelegate 
{ 
    // Setup is converted from https://www.natashatherobot.com/watchconnectivity-say-hello-to-wcsession/ 
    // with some extra bits 
    private static readonly WCSessionManager sharedManager = new WCSessionManager(); 
    private static WCSession session = WCSession.IsSupported ? WCSession.DefaultSession : null; 

#if __IOS__ 
    public static string Device = "Phone"; 
#else 
    public static string Device = "Watch"; 
#endif 

    public event ApplicationContextUpdatedHandler ApplicationContextUpdated; 

    public delegate void ApplicationContextUpdatedHandler(WCSession session, Dictionary<string, object> applicationContext); 

    public event MessageReceivedHandler MessageReceived; 

    public delegate void MessageReceivedHandler(Dictionary<string, object> message, Action<Dictionary<string, object>> replyHandler); 

    private WCSession validSession 
    { 
     get 
     { 
#if __IOS__ 
      // Even though session.Paired and session.WatchAppInstalled are underlined, it will still build as they are available on the iOS version of WatchConnectivity.WCSession 
      Console.WriteLine($"Paired status:{(session.Paired ? '✓' : '✗')}\n"); 
      Console.WriteLine($"Watch App Installed status:{(session.WatchAppInstalled ? '✓' : '✗')}\n"); 
      return (session.Paired && session.WatchAppInstalled) ? session : null; 
      //return session; 
#else 
      return session; 
#endif 
     } 
    } 

    private WCSession validReachableSession 
    { 
     get 
     { 
      return session.Reachable ? validSession : null; 
     } 
    } 

    private WCSessionManager() : base() { } 

    public static WCSessionManager SharedManager 
    { 
     get 
     { 
      return sharedManager; 
     } 
    } 

    public void StartSession() 
    { 
     if (session != null) 
     { 
      session.Delegate = this; 
      session.ActivateSession(); 
      Console.WriteLine($"Started Watch Connectivity Session on {Device}"); 
     } 
    } 

    [Export("sessionReachabilityDidChange:")] 
    public void SessionReachabilityDidChange(WCSession session) 
    { 
     Console.WriteLine($"Watch connectivity Reachable:{(session.Reachable ? '✓' : '✗')} from {Device}"); 
     // handle session reachability change 
     if (session.Reachable) 
     { 
      // great! continue on with Interactive Messaging 
     } 
     else { 
      // prompt the user to unlock their iOS device 
     } 
    } 

    #region Application Context Methods 

    public void UpdateApplicationContext(Dictionary<string, object> applicationContext) 
    { 
     // Application context doesnt need the watch to be reachable, it will be received when opened 
     if (validSession != null) 
     { 
      try 
      { 
       var NSValues = applicationContext.Values.Select(x => new NSString(JsonConvert.SerializeObject(x))).ToArray(); 
       var NSKeys = applicationContext.Keys.Select(x => new NSString(x)).ToArray(); 
       var NSApplicationContext = NSDictionary<NSString, NSObject>.FromObjectsAndKeys(NSValues, NSKeys); 

       UpdateApplicationContextOnSession(NSApplicationContext); 
      } 
      catch (Exception ex) 
      { 
       Console.WriteLine($"Exception Updating Application Context: {ex.Message}"); 
      } 
     } 
    } 

    public void GetApplicationContext() 
    { 
     UpdateApplicationContext(new Dictionary<string, object>() { { "GET", null } }); 
    } 

    [Export("session:didReceiveApplicationContext:")] 
    public void DidReceiveApplicationContext(WCSession session, NSDictionary<NSString, NSObject> applicationContext) 
    { 
     Console.WriteLine($"Recieving Message on {Device}"); 
     if (ApplicationContextUpdated != null) 
     { 
      var keys = applicationContext.Keys.Select(k => k.ToString()).ToArray(); 

      IEnumerable<object> values; 

      try 
      { 
       values = applicationContext.Values.Select(v => JsonConvert.DeserializeObject(v.ToString(), typeof(DoorWatchDTO))); 
      } 
      catch (Exception) 
      { 
       values = applicationContext.Values.Select(v => JsonConvert.DeserializeObject(v.ToString())); 
      } 

      var dictionary = keys.Zip(values, (k, v) => new { Key = k, Value = v }) 
           .ToDictionary(x => x.Key, x => x.Value); 

      ApplicationContextUpdated(session, dictionary); 
     } 
    } 

    [Export("session:didReceiveMessage::")] 
    public void DidReceiveMessage(WCSession session, NSDictionary<NSString, NSObject> message, WCSessionReplyHandler replyHandler) 
    { 
     if (MessageReceived != null) 
     { 
      var keys = message.Keys.Select(k => k.ToString()).ToArray(); 

      IEnumerable<object> values; 

      values = message.Values.Select(v => JsonConvert.DeserializeObject(v.ToString())); 

      var dictionary = keys.Zip(values, (k, v) => new { Key = k, Value = v }) 
           .ToDictionary(x => x.Key, x => x.Value); 

      MessageReceived(dictionary, (dict) => 
      { 
       var NSValues = dict.Values.Select(x => new NSString(JsonConvert.SerializeObject(x))).ToArray(); 
       var NSKeys = dict.Keys.Select(x => new NSString(x)).ToArray(); 
       var NSDict = NSDictionary<NSString, NSObject>.FromObjectsAndKeys(NSValues, NSKeys); 

       replyHandler.Invoke(NSDict); 
      }); 
     } 
    } 

    public void SendMessage(Dictionary<string, object> message, Action<Dictionary<string, object>> replyHandler, WKInterfaceLabel label) 
    { 
     if (validSession != null) 
     { 
      try 
      { 
       var NSValues = message.Values.Select(x => new NSString(JsonConvert.SerializeObject(x))).ToArray(); 
       var NSKeys = message.Keys.Select(x => new NSString(x)).ToArray(); 
       var NSMessage = NSDictionary<NSString, NSObject>.FromObjectsAndKeys(NSValues, NSKeys); 

       var reply = new WCSessionReplyHandler((replyMessage) => 
       { 
        var values = replyMessage.Values.Select(x => JsonConvert.SerializeObject(x)).ToArray(); 
        var keys = replyMessage.Keys.Select(x => x.ToString()).ToArray(); 

        var dict = keys.Zip(values, (k, v) => new { Key = k, Value = v }) 
            .ToDictionary(x => x.Key, x => (object)x.Value); 

        replyHandler.Invoke(dict); 
       }); 

       validSession.SendMessage(NSMessage, reply, (error) => 
       { 
        label.SetText(error.ToString()); // I can see the error in here: "payload could n..." 
       }); 
      } 
      catch (Exception ex) 
      { 
       Console.WriteLine($"Exception sending message: {ex.Message}"); 
      } 
     } 
    } 

    private void UpdateApplicationContextOnSession(NSDictionary<NSString, NSObject> NSApplicationContext) 
    { 
     NSError error; 
     var sendSuccessfully = validSession.UpdateApplicationContext(NSApplicationContext, out error); 
     if (sendSuccessfully) 
     { 
      Console.WriteLine($"Sent App Context from {Device} \nPayLoad: {NSApplicationContext.ToString()} \n"); 

      #if __IOS__ 
      Logging.Log("Success, payload: " + NSApplicationContext.ToString()); 
      #endif 
     } 
     else 
     { 
      Console.WriteLine($"Error Updating Application Context: {error.LocalizedDescription}"); 

      #if __IOS__ 
      Logging.Log("error: " + error.LocalizedDescription); 
      #endif 
     } 
    } 

    #endregion 

回答

7

我解決了它。我不是實施IWCSessionDelegate,而是簡單地實施WCSessionDelegate,並根據需要覆蓋功能。

+1

很酷的說我更新了這個要點https://gist.github.com/b099l3/e5a361477168053f0d58ac3907ea16d6我將它添加到xamarin示例 –

+0

這就是它現在合併https://github.com/xamarin/ ios-samples/pull/131 –

+0

我正在執行'WCSessionDelegate',但我得到同樣的錯誤 –