WCSession发送消息给出错误"有效载荷无法传送"

时间:2016-11-12 04:11:49

标签: c# ios xamarin watchkit

我正在使用Xamarin开发Apple Watch应用程序。我正在尝试使用SendMessage功能将手表中的消息发送到iPhone。当我执行此操作时,我会在out错误中收到消息payload could not be delivered。我只能阅读部分信息("有效载荷可以......"),因为我在标签上写它(因为我的调试器不能在Xamarin中工作,我可以&#t; t看一下这条消息),但是在做了一些谷歌搜索之后,我假设它写的是什么。知道为什么吗?这是我的代码:

    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

1 个答案:

答案 0 :(得分:8)

我解决了。我不是实现IWCSessionDelegate,而是简单地实现WCSessionDelegate,并根据需要覆盖这些函数。