我在 react-native v0.46.0 上,遇到了同样的问题。我在 react-native 代码库中将问题追溯到这个文件
https://github.com/facebook/react-native/blob/master/Libraries/Utilities/BackHandler.android.js#L25
运行时用chrome调试器关掉线
var subscriptions = Array.from(_backPressSubscriptions.values()).reverse()
总是为订阅返回一个空数组,这反过来会导致 invokeDefault 变量保持为真并调用 .exitApp() 函数。
经过更多调查,我认为该问题在以下PR #15182中被发现和讨论。
即使在旧版本的 RN 中复制/粘贴 PR 更改后,它也无法正常工作,很可能是由 PR 中描述的问题引起的。
经过一些非常细微的修改后,我通过更改为使其工作
RCTDeviceEventEmitter.addListener(DEVICE_BACK_EVENT, function() {
var invokeDefault = true;
var subscriptions = []
_backPressSubscriptions.forEach(sub => subscriptions.push(sub))
for (var i = 0; i < subscriptions.reverse().length; ++i) {
if (subscriptions[i]()) {
invokeDefault = false;
break;
}
}
if (invokeDefault) {
BackHandler.exitApp();
}
});
只需使用 .forEach 即可,它是 PR 上的原始实现,之后修改后的 Array.from 语法始终有效。
因此,您可以分叉 react-native 并使用修改后的版本,提交 PR 虽然我认为这需要一些时间才能在上游获得批准和合并,或者您可以做一些类似于我所做的事情,即覆盖用于hardwareBackPress 事件的RCTDeviceEventEmitter.addListener(...)。
// other imports
import { BackHandler, DeviceEventEmitter } from 'react-native'
class MyApp extends Component {
constructor(props) {
super(props)
this.backPressSubscriptions = new Set()
}
componentDidMount = () => {
DeviceEventEmitter.removeAllListeners('hardwareBackPress')
DeviceEventEmitter.addListener('hardwareBackPress', () => {
let invokeDefault = true
const subscriptions = []
this.backPressSubscriptions.forEach(sub => subscriptions.push(sub))
for (let i = 0; i < subscriptions.reverse().length; i += 1) {
if (subscriptions[i]()) {
invokeDefault = false
break
}
}
if (invokeDefault) {
BackHandler.exitApp()
}
})
this.backPressSubscriptions.add(this.handleHardwareBack)
}
componentWillUnmount = () => {
DeviceEventEmitter.removeAllListeners('hardwareBackPress')
this.backPressSubscriptions.clear()
}
handleHardwareBack = () => { /* do your thing */ }
render() { return <YourApp /> }
}