如何在React Native应用程序中使socket.io在iOS后台运行?

22

我正在一个 iOS React Native(v0.20) app 中使用 socket.io。该应用程序跟踪我的位置,当我的位置发生变化时,它会向服务器发送消息。如果套接字连接丢失,则服务器会发送电子邮件进行通知。

我使用 react-native-location 在后台实现了位置跟踪,但我无法使 socket.io 正常工作。每当我更改应用程序或关闭屏幕时,应用程序仍然跟踪我的位置,但我会失去套接字连接。

是否有一种方法可以像位置跟踪一样在后台运行 socket.io?除此之外,是否有一些本地代码可以让我在后台维护 客户端/服务器连接

我知道有一个WebSocket替代方案,但我看不到任何使其在后台运行的方法。

更新: 我已经双重检查了我的 Info.plist,对于 react-native-location,它已经设置了必要的后台值。我不知道是否重要,但套接字工作和位置跟踪都是在同一个组件中完成的。

enter image description here

LocationComponent.js

window.navigator.userAgent = 'react-native';
const io = require('socket.io-client/socket.io');
const socket = io(url, {jsonp: false});

import React, { Text, View, DeviceEventEmitter } from 'react-native';
import { RNLocation } from 'NativeModules';

export default GeolocationExample = React.createClass({

  componentDidMount: function() {
    RNLocation.requestAlwaysAuthorization();
    RNLocation.startUpdatingLocation();
    RNLocation.setDistanceFilter(3.0);
    DeviceEventEmitter.addListener('locationUpdated', locationObject => {
      this.props.newPosition({ longitude: locationObject.coords.longitude, latitude: locationObject.coords.latitude });
    });
  },

  render: function() {
    const { lastPosition, distance } = this.props;
    socket.emit('newPos', { longitude: lastPosition.longitude, latitude: lastPosition.latitude, distance, time: Date() });
    return (
      <View>
        <Text> {distance} </Text>
      </View>
    );
  }
});

1
iOS和Android的行为是否相似,还是这只是iOS的问题? - Stavash
我还没有尝试过Android。这是我的第一个React Native应用程序,我想专注于为iOS构建,以便我可以在我的手机上使用它。 - EasilyBaffled
你找到解决方案了吗? - Chris Andersson
@ChrisAndersson 没有,我能找到的最好建议就是构建一个包,将我需要运行的JavaScript与可以运行它的本地代码桥接起来。但我实际上还不知道如何做到这一点。 - EasilyBaffled
@EasilyBaffled 我找到了这个,但还没有让它工作。https://gist.github.com/liamzebedee/67e1b2c53c6c5edcf8ec - Chris Andersson
这个有更新了吗? - Kasra
4个回答

6

没有办法以“正确的方式”来完成这个任务。

编辑

来自苹果官方文档

实现长时间运行的任务
对于需要更多执行时间来实现的任务,您必须请求特定权限以在后台运行它们而不被挂起。在iOS中,只有特定类型的应用程序允许在后台运行:
- 在后台播放可听内容的应用程序,例如音乐播放器应用程序 - 在后台录制音频内容的应用程序 - 始终保持用户位置的应用程序,例如导航应用程序 - 支持VoIP的应用程序 - 需要定期下载和处理新内容的应用程序 - 定期从外部附件接收更新的应用程序
实现这些服务的应用程序必须声明它们支持的服务,并使用系统框架来实现这些服务的相关方面。声明服务可以让系统知道您使用哪些服务,但在某些情况下,正是系统框架实际上防止了您的应用程序被挂起。
话虽如此,存在一种工作技术可以保持您的套接字打开:
播放无声音频并将后台模式设置为音频。有关此问题的更多信息,请参见this article(它有点旧,但仍然有效)。这将使您能够保持套接字打开并伪装成音频应用程序。您的info.plist应更新以允许音频在后台运行。UIBackgroundModes应设置为audio(有关更多信息,请参见docs)。

我已经在后台运行位置检查。正如我所展示的,我已经在info.plist中设置了它。那不应该已经解决了吗? - EasilyBaffled

3
我知道有一些方法可以实现这个功能(比如使用音频hack),但iOS不允许在后台运行长时间任务,这是有原因的-请重新考虑你的设计以实现更好的产品。
长时间运行的任务会耗尽电池。如果您需要数据更新,请使用苹果推送服务注册以获取推送通知(如果您直接使用,它是免费的,或者上次我处理类似问题时是免费的)。
特别是位置跟踪,是允许在后台系统服务中运行的,考虑使用本地API来实现。
至于将数据推送到服务器,您将无法(也可能不应该)与服务器保持长时间连接。
考虑收集数据并在一段时间后上传到服务器-最好在重新打开应用程序时进行,以避免浪费后台资源并使用户对电池寿命和数据消耗感到不满。

2
我目前不太关心电池寿命问题。我宁愿在有一个可行的应用程序示例之后再解决这个问题。该应用程序的重点是与赛车手分享实时更新,每个人都需要保持不断的沟通。如果我等太久才报告跑步者的位置,那么每个人都会失去机会。 - EasilyBaffled
你可能不太关心,但是苹果在设计API时是有考虑到这些限制的...也许赛车手们可以将应用程序保持在前台。 - Myst
虽然这在基本层面上可以工作,但远非理想。当我跑步时,我会打开音乐并关闭手机屏幕,所以让应用程序保持在前台对我来说不是一个选项。 - EasilyBaffled

2

iOS对应用程序在后台运行时允许的进程类型有相当严格的限制。 此处有相关说明。

关于socket.io客户端问题跟踪器上似乎有一些讨论。

如果将后台模式设置为audio,似乎可以使socket连接保持活动状态。但是效果因人而异。

请确保在Info.plist文件的UIBackgroundModes部分中设置了正确的值。 如何在XCode中进行此操作


我已经在Info.plist中为react-native-location设置了值,并且正如我在问题中提到的,位置跟踪是有效的。我已经在问题中添加了Info.plist值的图片。 - EasilyBaffled

0
在您的Info.plist图片中,它只允许以下三种后台模式
  1. 后台获取

  2. 位置更新

  3. 远程通知

    您应该允许“音频和AirPlay”模式,似乎是“应用程序使用Airplay播放音频或流视频”。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接