Search code examples
react-nativeswiftuiapple-watchwatchconnectivitywcsession

Send Message to Apple Watch - IOS React Native with react-native-watch-connectivity - WatchOS Swift with WCSession


I want to send a message from my IOS application in React Native to my WatchOS application in Swift.

Here is my code on the React Native side:

import React from 'react';
import {Button, View} from 'react-native';
import * as Watch from 'react-native-watch-connectivity';

const Component = () => {
    const sendMessageToWatch = () => {
        Watch.getIsWatchAppInstalled().then((isInstalled) => {
            if (!isInstalled) {
                console.log('getIsWatchAppInstalled -> No');
            } else {
                console.log('getIsWatchAppInstalled -> Yes');
            }
        });
        Watch.getIsPaired().then((isPaired) => {
            if (!isPaired) {
                console.log('isPaired -> No');
            } else {
                console.log('isPaired -> Yes');
            }
        });
        Watch.sendMessageData('valueMessage')
            .then((response) => {
                console.log('response -> ', response);
            })
            .catch((error) => {
                console.log('error -> ', error);
                console.log('error.code -> ', error.code);
                console.log('error.message -> ', error.message);
            });
    };
    return (
        <View>
            <Button
                title="Send Message"
                onPress={sendMessageToWatch}
            />

        </View>
    );
};

export default Component;

Here are the logs received when the button is pressed:

getIsWatchAppInstalled -> Yes
isPaired -> Yes
error.code -> EWCERRORDOMAIN7014
error.message -> Les données utiles n’ont pas pu être envoyées. //In English -> Payload data could not be sent.
error.code -> {"code": "EWCERRORDOMAIN7014", "domain": "WCErrorDomain", "message": "Les données utiles n’ont pas pu être envoyées.", "nativeStackIOS": ["0   SwimWorkout                         0x00000001030c11b0 RCTJSErrorFromCodeMessageAndNSError + 112", "1   SwimWorkout                         0x00000001030c1100 RCTJSErrorFromNSError + 236", "2   SwimWorkout                         0x00000001030627d8 __41-[RCTModuleMethod processMethodSignature]_block_invoke_4.56 + 132", "3   SwimWorkout                         0x0000000102fb11ac __56-[RNWatch sendMessageData:encoding:replyCallback:error:]_block_invoke.73 + 72", "4   WatchConnectivity                   0x000000022cdb2ff4 E79B7B28-4F4E-36F7-BB22-2E9D64BE49C3 + 94196", "5   Foundation                          0x00000001b0aa5c00 60F744F4-1345-325E-8970-D37BB5A1A31D + 302080", "6   Foundation                          0x00000001b0ad70ec 60F744F4-1345-325E-8970-D37BB5A1A31D + 504044", "7   Foundation                          0x00000001b0ad4974 60F744F4-1345-325E-8970-D37BB5A1A31D + 493940", "8   Foundation                          0x00000001b0ad3a64 60F744F4-1345-325E-8970-D37BB5A1A31D + 490084", "9   Foundation                          0x00000001b0ad657c 60F744F4-1345-325E-8970-D37BB5A1A31D + 501116", "10  Foundation                          0x00000001b0ad62e8 60F744F4-1345-325E-8970-D37BB5A1A31D + 500456", "11  libdispatch.dylib                   0x00000001b99ed6a8 149FF9CD-3E92-321D-B92F-EF58717C70B6 + 9896", "12  libdispatch.dylib                   0x00000001b99ef300 149FF9CD-3E92-321D-B92F-EF58717C70B6 + 17152", "13  libdispatch.dylib                   0x00000001b99f27b8 149FF9CD-3E92-321D-B92F-EF58717C70B6 + 30648", "14  libdispatch.dylib                   0x00000001b99f1dd4 149FF9CD-3E92-321D-B92F-EF58717C70B6 + 28116", "15  libdispatch.dylib                   0x00000001b9a00be4 149FF9CD-3E92-321D-B92F-EF58717C70B6 + 89060", "16  libdispatch.dylib                   0x00000001b9a013ec 149FF9CD-3E92-321D-B92F-EF58717C70B6 + 91116", "17  libsystem_pthread.dylib             0x000000021acaa928 _pthread_wqthread + 228", "18  libsystem_pthread.dylib             0x000000021acaaa04 start_wqthread + 8"], "userInfo": {"NSLocalizedDescription": "Les données utiles n’ont pas pu être envoyées."}}

On the side of my WatchOS application I implemented the following code which launches when the application is opened:

import WatchKit
import SwiftUI
import WatchConnectivity

class WatchSessionManager: NSObject, WCSessionDelegate {
    func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
        print("WCSession activation completed with state: \(activationState.rawValue)")
        if let error = error {
            print("WCSession activation failed with error: \(error.localizedDescription)")
        }
    }
    
    func session(_ session: WCSession, didReceiveMessage message: [String : Any]) {
        print("Received message from iPhone: \(message)")
    }
}

@main
struct SwimWorkoutWatch_Watch_AppApp: App {
    
    let watchSessionManager = WatchSessionManager()
    
    init() {
      if WCSession.isSupported() {
            let session = WCSession.default
            session.delegate = watchSessionManager
            session.activate()
            print("WCSession is supported and activated.")
        } else {
            print("WCSession is not supported on this device.")
        }
    }
    
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

When opening the WatchOS application I have the following logs:

WCSession is supported and activated.
WCSession activation completed with state: 2

I don't understand why the payload data cannot be sent (I send a string as expected) and especially why on the WatchOS side I receive nothing, not even an error.


Solution

  • I had the same error while I was sending message from react native app to my watch extension. Problem is that Watch.sendMessageData function is having a response block. There are two functions in WCSessionDelegate class:

    func session(_ session: WCSession, didReceiveMessage message: [String : Any]) this is the one you are using which doesn't have any reply handler. you should use this function instead. func session(_ session: WCSession, didReceiveMessage message: [String : Any], replyHandler: @escaping ([String : Any]) -> Void) . Hope that solves the issue!