iOS端React Native NFC会话自动关闭:如何保持会话持续活跃?
问题:iOS下react-native-nfc-manager会话自动关闭,需保持持续活跃
在iOS平台使用react-native-nfc-manager读取NFC标签时,每次发现标签均可正常读取,但约1分钟后NFC会话会自动关闭,应用停止读取标签,需手动重启会话才能恢复。需求是按需保持会话持续活跃。
现有代码
import { FlatList, Pressable, StyleSheet, Text, View } from "react-native"; import React, { useEffect, useState } from "react"; import NfcManager, { Ndef, NfcAdapter, NfcEvents, NfcTech, } from "react-native-nfc-manager"; import AppButton from "@/components/AppButton"; import Animated, { SlideInLeft } from "react-native-reanimated"; NfcManager.start({ onSessionClosedIOS: () => { console.log("ios session closed"); }, }) .then((result) => { console.log("start OK", result); }) .catch((error) => { console.warn("device does not support nfc!"); }); const Item = ({ title }) => { return ( <Animated.View entering={SlideInLeft.duration(300)} style={{ backgroundColor: "lightgreen", marginVertical: 4, padding: 12, borderRadius: 2, borderLeftWidth: 4, }} > <Animated.Text entering={SlideInLeft.duration(100)} style={{ fontSize: 16 }} > {title} </Animated.Text> </Animated.View> ); }; const Page = () => { const [tags, setTags] = useState([]); const [nfcState, setNfcState] = useState(null); const [nfcSupport, setNfcSupport] = useState(null); console.log(tags); const processNfcTag = (tag) => { if (tag.ndefMessage) { const ndefMessage = tag.ndefMessage[0]; // Assuming only one NDEF record const text = Ndef.text.decodePayload(ndefMessage.payload); // Use the decoded text console.log("Decoded Text:", text); setTags((pre) => { return [...pre, { id: pre.length, tag: text }]; }); } else { } }; useEffect(() => { NfcManager.setEventListener(NfcEvents.DiscoverTag, (tag) => { console.log("tag found", tag.ndefMessage); processNfcTag(tag); }); return () => { NfcManager.setEventListener(NfcEvents.DiscoverTag, null); }; }, []); useEffect(() => { const checkNfcState = async () => { const _nfcSupport = await NfcManager.isSupported(); setNfcSupport(_nfcSupport); const _nfcState = await NfcManager.isEnabled(); setNfcState(_nfcState); console.log(_nfcState, "nfcState"); console.log(_nfcSupport, "nfcSupport"); }; checkNfcState(); }, []); const readTag = async () => { try { const isActive = await NfcManager.isSessionAvailableIOS(); console.log(isActive, "is session available"); if (isActive) { return; } await NfcManager.registerTagEvent({ invalidateAfterFirstRead: false, isReaderModeEnabled: true, readerModeFlags: NfcAdapter.FLAG_READER_NFC_A | NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK, }); } catch (error) { console.log(error); } }; if (nfcSupport === null || nfcState === null) { return; } else if (!nfcSupport) { return ( <View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}> <Text> Your device does not support NFC</Text> </View> ); } else if (!nfcState) { return ( <View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}> <Text> NFC is off</Text> </View> ); } return ( <View style={{ padding: 16, gap: 12 }}> <AppButton style={{ backgroundColor: "orange", alignSelf: "center", width: 100, }} title="Start" textColor="#111" onPress={readTag} /> <FlatList data={tags} keyExtractor={(item) => item.id + "_key"} renderItem={({ item }) => <Item title={item?.tag} />} /> </View> ); }; export default Page; const styles = StyleSheet.create({});
解决方案
1. 利用iOS会话关闭事件自动重启会话
iOS系统默认NFC会话超时时间为60秒,超时后会触发onSessionClosedIOS回调。我们可以在这个回调里重新启动NFC会话,实现自动续期。
2. 优化会话注册参数
在registerTagEvent中设置sessionTimeoutIOS为0(表示无超时限制),同时保留invalidateAfterFirstRead: false确保读取多个标签后会话不关闭。
修改后的代码示例
import { FlatList, Pressable, StyleSheet, Text, View } from "react-native"; import React, { useEffect, useState } from "react"; import NfcManager, { Ndef, NfcAdapter, NfcEvents, NfcTech, } from "react-native-nfc-manager"; import AppButton from "@/components/AppButton"; import Animated, { SlideInLeft } from "react-native-reanimated"; // 定义启动NFC会话的通用函数 const startNfcSession = async () => { try { const isActive = await NfcManager.isSessionAvailableIOS(); if (isActive) return; await NfcManager.registerTagEvent({ invalidateAfterFirstRead: false, isReaderModeEnabled: true, readerModeFlags: NfcAdapter.FLAG_READER_NFC_A | NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK, sessionTimeoutIOS: 0, // 设置为0表示无超时限制 }); console.log("NFC会话已启动"); } catch (error) { console.error("启动NFC会话失败:", error); } }; NfcManager.start({ onSessionClosedIOS: async () => { console.log("iOS NFC会话已关闭,自动重启..."); await startNfcSession(); // 会话关闭后自动重启 }, }) .then((result) => { console.log("NFC初始化成功", result); }) .catch((error) => { console.warn("设备不支持NFC!"); }); const Item = ({ title }) => { return ( <Animated.View entering={SlideInLeft.duration(300)} style={{ backgroundColor: "lightgreen", marginVertical: 4, padding: 12, borderRadius: 2, borderLeftWidth: 4, }} > <Animated.Text entering={SlideInLeft.duration(100)} style={{ fontSize: 16 }} > {title} </Animated.Text> </Animated.View> ); }; const Page = () => { const [tags, setTags] = useState([]); const [nfcState, setNfcState] = useState(null); const [nfcSupport, setNfcSupport] = useState(null); const processNfcTag = (tag) => { if (tag.ndefMessage) { const ndefMessage = tag.ndefMessage[0]; const text = Ndef.text.decodePayload(ndefMessage.payload); console.log("解码文本:", text); setTags(prev => [...prev, { id: prev.length, tag: text }]); } }; useEffect(() => { const tagListener = NfcManager.setEventListener(NfcEvents.DiscoverTag, processNfcTag); return () => { tagListener.remove(); NfcManager.unregisterTagEvent(); // 组件卸载时清理会话 }; }, []); useEffect(() => { const checkNfcState = async () => { const _nfcSupport = await NfcManager.isSupported(); setNfcSupport(_nfcSupport); const _nfcState = await NfcManager.isEnabled(); setNfcState(_nfcState); }; checkNfcState(); }, []); const readTag = async () => { await startNfcSession(); }; if (nfcSupport === null || nfcState === null) { return null; } else if (!nfcSupport) { return ( <View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}> <Text>您的设备不支持NFC</Text> </View> ); } else if (!nfcState) { return ( <View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}> <Text>NFC已关闭</Text> </View> ); } return ( <View style={{ padding: 16, gap: 12 }}> <AppButton style={{ backgroundColor: "orange", alignSelf: "center", width: 100, }} title="启动" textColor="#111" onPress={readTag} /> <FlatList data={tags} keyExtractor={(item) => `${item.id}_key`} renderItem={({ item }) => <Item title={item?.tag} />} /> </View> ); }; export default Page; const styles = StyleSheet.create({});
关键修改点
- 提取通用的
startNfcSession函数,避免代码重复 - 在
onSessionClosedIOS回调中自动调用startNfcSession实现会话重启 - 设置
sessionTimeoutIOS: 0取消iOS默认的60秒超时限制 - 组件卸载时添加
NfcManager.unregisterTagEvent()清理资源,避免内存泄漏
内容的提问来源于stack exchange,提问作者Irfan Deva
相关产品推荐
相关产品推荐

