React Native结合Wear OS:如何实现杀死状态下的数据传输?
解决方案:React Native + Wear OS 离线/杀进程状态下通信保障
核心思路
利用Android原生WearableListenerService(系统级监听服务,不受应用进程状态影响)捕获Wear Data Layer的消息/数据变更,结合Headless JS任务或本地持久化实现离线数据处理,同时确保应用重启后能读取未处理的消息。
步骤1:创建Android原生监听服务
在Android项目src/main/java/[你的包名]/下新建WearDataListenerService.java,负责监听Wear Data Layer事件:
package com.yourapppackage; import android.content.Intent; import android.util.Log; import com.facebook.react.HeadlessJsTaskService; import com.facebook.react.bridge.Arguments; import com.facebook.react.jstasks.HeadlessJsTaskConfig; import com.google.android.gms.wearable.DataEvent; import com.google.android.gms.wearable.DataEventBuffer; import com.google.android.gms.wearable.MessageEvent; import com.google.android.gms.wearable.WearableListenerService; import org.json.JSONException; import org.json.JSONObject; public class WearDataListenerService extends WearableListenerService { private static final String TAG = "WearDataListener"; private static final String WEAR_TASK_NAME = "WearConnectivityTask"; // 监听实时消息 @Override public void onMessageReceived(MessageEvent messageEvent) { super.onMessageReceived(messageEvent); String messageContent = new String(messageEvent.getData()); Log.d(TAG, "Received offline message: " + messageContent); // 方案1:启动Headless JS处理消息 try { JSONObject messageJson = new JSONObject(messageContent); Intent intent = new Intent(this, HeadlessJsTaskService.class); intent.putExtra(HeadlessJsTaskService.EXTRA_TASK_CONFIG, new HeadlessJsTaskConfig( WEAR_TASK_NAME, Arguments.createMapFromJson(messageJson.toString()), 5000, // 任务超时时间(ms) false // 禁止前台执行(避免显示应用界面) )); startService(intent); } catch (JSONException e) { Log.e(TAG, "Parse message failed", e); } // 方案2:持久化到SharedPreferences(备选,用于App重启后读取) // SharedPreferences prefs = getSharedPreferences("WearOfflineData", MODE_PRIVATE); // prefs.edit().putString("lastMessage", messageContent).apply(); } // 监听数据项变更(适合需要同步的离线数据) @Override public void onDataChanged(DataEventBuffer dataEvents) { super.onDataChanged(dataEvents); for (DataEvent event : dataEvents) { if (event.getType() == DataEvent.TYPE_CHANGED) { String path = event.getDataItem().getUri().getPath(); String dataContent = new String(event.getDataItem().getData()); Log.d(TAG, "Data changed: " + path + " -> " + dataContent); // 同样可以触发Headless任务或持久化 } } dataEvents.close(); } }
步骤2:注册服务到AndroidManifest.xml
添加权限和服务声明,确保系统能唤醒监听服务:
<manifest ...> <!-- 必要权限 --> <uses-permission android:name="com.google.android.gms.permission.WEARABLE_MESSAGE" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" /> <!-- 应对API30+后台限制 --> <application ...> <!-- 注册Wear数据监听服务 --> <service android:name=".WearDataListenerService" android:exported="true"> <intent-filter> <action android:name="com.google.android.gms.wearable.MESSAGE_RECEIVED" /> <data android:host="*" android:pathPrefix="/" android:scheme="wear" /> </intent-filter> <intent-filter> <action android:name="com.google.android.gms.wearable.DATA_CHANGED" /> <data android:host="*" android:pathPrefix="/" android:scheme="wear" /> </intent-filter> </service> <!-- 注册Headless JS服务 --> <service android:name="com.facebook.react.HeadlessJsTaskService" android:enabled="true" android:exported="true" /> </application> </manifest>
步骤3:修复React Native Headless任务逻辑
修改index.js,让任务能接收并处理原生传递的消息:
import {AppRegistry, AsyncStorage} from 'react-native'; import App from './App'; import {name as appName} from './app.json'; const wearTaskHandler = async (taskData) => { console.log('[HeadlessJS] Process offline message:', taskData); // 持久化消息,供App重启后读取 try { await AsyncStorage.setItem('pendingWearMessages', JSON.stringify(taskData)); // 可选:用react-native-push-notification发送通知提醒用户 } catch (e) { console.error('[HeadlessJS] Save message failed:', e); } }; AppRegistry.registerHeadlessTask('WearConnectivityTask', () => wearTaskHandler); AppRegistry.registerComponent(appName, () => App);
步骤4:App重启后读取未处理消息
修改App.tsx,在组件挂载时读取持久化的离线消息并更新UI:
import React, {useEffect, useState} from 'react'; import {View, StyleSheet, Text, Button, AsyncStorage} from 'react-native'; import {sendMessage, watchEvents} from 'react-native-wear-connectivity'; import type {ReplyCallback, ErrorCallback} from 'react-native-wear-connectivity'; function CounterScreen() { const [disabled, setDisabled] = useState(false); const [count, setCount] = useState(0); useEffect(() => { // 读取应用杀进程期间收到的消息 const loadPendingMessages = async () => { try { const pendingMsg = await AsyncStorage.getItem('pendingWearMessages'); if (pendingMsg) { console.log('Load pending message:', pendingMsg); setCount(prev => prev + 1); // 处理完成后清除缓存 await AsyncStorage.removeItem('pendingWearMessages'); } } catch (e) { console.error('Load pending messages failed:', e); } }; loadPendingMessages(); // 监听前台状态下的实时消息 const unsubscribe = watchEvents.on('message', message => { console.log('Foreground message:', message); setCount(prev => prev + 1); }); return () => unsubscribe(); }, []); const onSuccess: ReplyCallback = result => { setDisabled(false); console.log('Send success:', result); }; const onError: ErrorCallback = error => console.log('Send error:', error); const sendMessageToWear = () => { setDisabled(true); sendMessage({text: 'hello from mobile'}, onSuccess, onError); }; return ( <View style={styles.container}> <Text style={styles.counter}>{count}</Text> <Button disabled={disabled} title="Increase Counter" onPress={sendMessageToWear} /> </View> ); } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', padding: 8, }, counter: { height: 100, width: 400, textAlign: 'center', fontSize: 50, fontWeight: 'bold', }, }); export default CounterScreen;
关键注意事项
- API30+后台限制:Android 11+对后台启动有严格限制,需引导用户关闭应用的电池优化,或申请
REQUEST_IGNORE_BATTERY_OPTIMIZATIONS权限。 - 数据同步选型:如果需要确保数据不丢失,优先使用Data Items而非Message API,Data Items会自动同步,设备重连后可获取最新数据。
- Headless JS限制:Headless任务不能执行UI操作,仅能处理数据、持久化或发送通知。
- 签名一致性:手机和手表端应用必须使用相同的签名(调试/发布签名需对应),否则无法建立Data Layer连接。
内容的提问来源于stack exchange,提问作者Nishit Chauhan
相关产品推荐
相关产品推荐

