From 36f5b0218dccbdce3913af73b8427eeddebb10a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Tue, 14 Feb 2017 14:59:49 +0100 Subject: [PATCH] [RN] Fix running timers in the background Turns out React Native's timers (setTimeout / setInterval) don't run while the app is in the background: https://github.com/facebook/react-native/issues/167 This patch replaces the global timer functions with those from the react-native-background-timer package, which work in the background. These timers won't magically make an application work in the background, but they will run if an application already happens to run in the background. That's our case while in a conference, so these timers will run, allowing XMPP pings to be sent and the conference to stay up as long as the user desires. --- android/app/build.gradle | 1 + .../java/org/jitsi/meet/MainApplication.java | 1 + android/settings.gradle | 2 ++ ios/jitsi-meet-react.xcodeproj/project.pbxproj | 14 ++++++++++++-- package.json | 1 + .../lib-jitsi-meet/native/polyfills-browser.js | 16 ++++++++++++++++ 6 files changed, 33 insertions(+), 2 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 1218faa67..ae1097595 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -139,6 +139,7 @@ if (project.hasProperty('JITSI_SIGNING') } dependencies { + compile project(':react-native-background-timer') compile project(':react-native-immersive') compile project(':react-native-keep-awake') compile project(':react-native-vector-icons') diff --git a/android/app/src/main/java/org/jitsi/meet/MainApplication.java b/android/app/src/main/java/org/jitsi/meet/MainApplication.java index c27d2adf7..0d3395fa2 100644 --- a/android/app/src/main/java/org/jitsi/meet/MainApplication.java +++ b/android/app/src/main/java/org/jitsi/meet/MainApplication.java @@ -29,6 +29,7 @@ public class MainApplication extends Application implements ReactApplication { new com.corbt.keepawake.KCKeepAwakePackage(), new com.facebook.react.shell.MainReactPackage(), new com.oblador.vectoricons.VectorIconsPackage(), + new com.ocetnik.timer.BackgroundTimerPackage(), new com.oney.WebRTCModule.WebRTCModulePackage(), new com.rnimmersive.RNImmersivePackage(), new org.jitsi.meet.audiomode.AudioModePackage() diff --git a/android/settings.gradle b/android/settings.gradle index ee5e51af4..00f50689d 100644 --- a/android/settings.gradle +++ b/android/settings.gradle @@ -1,6 +1,8 @@ rootProject.name = 'jitsi-meet-react' include ':app' +include ':react-native-background-timer' +project(':react-native-background-timer').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-background-timer/android') include ':react-native-immersive' project(':react-native-immersive').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-immersive/android') include ':react-native-keep-awake' diff --git a/ios/jitsi-meet-react.xcodeproj/project.pbxproj b/ios/jitsi-meet-react.xcodeproj/project.pbxproj index d7d6b3e98..866bbddea 100644 --- a/ios/jitsi-meet-react.xcodeproj/project.pbxproj +++ b/ios/jitsi-meet-react.xcodeproj/project.pbxproj @@ -5,7 +5,6 @@ }; objectVersion = 46; objects = { - /* Begin PBXBuildFile section */ 002AF788986B412780935607 /* FontAwesome.ttf in Resources */ = {isa = PBXBuildFile; fileRef = B96AF9B6FBC0453798399985 /* FontAwesome.ttf */; }; 00C302E51ABCBA2D00DB3ED1 /* libRCTActionSheet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302AC1ABCB8CE00DB3ED1 /* libRCTActionSheet.a */; }; @@ -41,6 +40,7 @@ BF9643921C34FBF100B0BBDF /* libsqlite3.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = BF9643911C34FBF100B0BBDF /* libsqlite3.tbd */; }; BF9643941C34FBF900B0BBDF /* libstdc++.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = BF9643931C34FBF900B0BBDF /* libstdc++.tbd */; }; BFC745141CB829B300673F38 /* libRCTWebRTC.a in Frameworks */ = {isa = PBXBuildFile; fileRef = BFC745131CB829A700673F38 /* libRCTWebRTC.a */; }; + 7FAD39BE09A84D6AB0ABACA8 /* libRNBackgroundTimer.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 27A0018BBB2C4FD5A4F9CE71 /* libRNBackgroundTimer.a */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -297,6 +297,8 @@ BF9643911C34FBF100B0BBDF /* libsqlite3.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libsqlite3.tbd; path = usr/lib/libsqlite3.tbd; sourceTree = SDKROOT; }; BF9643931C34FBF900B0BBDF /* libstdc++.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = "libstdc++.tbd"; path = "usr/lib/libstdc++.tbd"; sourceTree = SDKROOT; }; BFC7450D1CB829A700673F38 /* RCTWebRTC.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTWebRTC.xcodeproj; path = "../node_modules/react-native-webrtc/ios/RCTWebRTC.xcodeproj"; sourceTree = ""; }; + 0965153BB98645B4A8B6AA10 /* RNBackgroundTimer.xcodeproj */ = {isa = PBXFileReference; name = "RNBackgroundTimer.xcodeproj"; path = "../node_modules/react-native-background-timer/ios/RNBackgroundTimer.xcodeproj"; sourceTree = ""; fileEncoding = undefined; lastKnownFileType = wrapper.pb-project; explicitFileType = undefined; includeInIndex = 0; }; + 27A0018BBB2C4FD5A4F9CE71 /* libRNBackgroundTimer.a */ = {isa = PBXFileReference; name = "libRNBackgroundTimer.a"; path = "libRNBackgroundTimer.a"; sourceTree = ""; fileEncoding = undefined; lastKnownFileType = archive.ar; explicitFileType = undefined; includeInIndex = 0; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -329,6 +331,7 @@ 139FDEF61B0652A700C62182 /* libRCTWebSocket.a in Frameworks */, 3847F11906B4479A9162628F /* libRNVectorIcons.a in Frameworks */, 901FE90FA5744B5B94DCDC41 /* libKCKeepAwake.a in Frameworks */, + 7FAD39BE09A84D6AB0ABACA8 /* libRNBackgroundTimer.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -489,6 +492,7 @@ 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */, 146833FF1AC3E56700842450 /* React.xcodeproj */, 22418656B14845609F953A42 /* RNVectorIcons.xcodeproj */, + 0965153BB98645B4A8B6AA10 /* RNBackgroundTimer.xcodeproj */, ); name = Libraries; sourceTree = ""; @@ -576,7 +580,7 @@ 83CBB9F71A601CBA00E9B192 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0820; + LastUpgradeCheck = 820; ORGANIZATIONNAME = Facebook; TargetAttributes = { 13B07F861A680F5B00A75B9A = { @@ -954,6 +958,7 @@ "$(SRCROOT)/../node_modules/react-native/Libraries/LinkingIOS/**", "$(SRCROOT)/../node_modules/react-native-keep-awake/ios", "$(SRCROOT)/../node_modules/react-native-vector-icons/RNVectorIconsManager", + "$(SRCROOT)/../node_modules/react-native-background-timer/ios", ); INFOPLIST_FILE = app/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 9.0; @@ -961,6 +966,7 @@ LIBRARY_SEARCH_PATHS = ( "$(inherited)", "$(SRCROOT)/../node_modules/react-native-webrtc/**", + "\"$(SRCROOT)/jitsi-meet-react\"", ); OTHER_LDFLAGS = ( "$(inherited)", @@ -990,6 +996,7 @@ "$(SRCROOT)/../node_modules/react-native/Libraries/LinkingIOS/**", "$(SRCROOT)/../node_modules/react-native-keep-awake/ios", "$(SRCROOT)/../node_modules/react-native-vector-icons/RNVectorIconsManager", + "$(SRCROOT)/../node_modules/react-native-background-timer/ios", ); INFOPLIST_FILE = app/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 9.0; @@ -997,6 +1004,7 @@ LIBRARY_SEARCH_PATHS = ( "$(inherited)", "$(SRCROOT)/../node_modules/react-native-webrtc/**", + "\"$(SRCROOT)/jitsi-meet-react\"", ); OTHER_LDFLAGS = ( "$(inherited)", @@ -1052,6 +1060,7 @@ "$(SRCROOT)/../node_modules/react-native/React/**", "$(SRCROOT)/../node_modules/react-native-keep-awake/ios", "$(SRCROOT)/../node_modules/react-native-vector-icons/RNVectorIconsManager", + "$(SRCROOT)/../node_modules/react-native-background-timer/ios", ); IPHONEOS_DEPLOYMENT_TARGET = 8.0; MTL_ENABLE_DEBUG_INFO = YES; @@ -1097,6 +1106,7 @@ "$(SRCROOT)/../node_modules/react-native/React/**", "$(SRCROOT)/../node_modules/react-native-keep-awake/ios", "$(SRCROOT)/../node_modules/react-native-vector-icons/RNVectorIconsManager", + "$(SRCROOT)/../node_modules/react-native-background-timer/ios", ); IPHONEOS_DEPLOYMENT_TARGET = 8.0; MTL_ENABLE_DEBUG_INFO = NO; diff --git a/package.json b/package.json index 52467cc9e..7f0ef7947 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "react": "15.4.2", "react-dom": "15.4.2", "react-native": "0.41.2", + "react-native-background-timer": "^1.0.0", "react-native-immersive": "0.0.4", "react-native-keep-awake": "^2.0.2", "react-native-prompt": "^1.0.0", diff --git a/react/features/base/lib-jitsi-meet/native/polyfills-browser.js b/react/features/base/lib-jitsi-meet/native/polyfills-browser.js index 47b4b1e74..12ef0ade8 100644 --- a/react/features/base/lib-jitsi-meet/native/polyfills-browser.js +++ b/react/features/base/lib-jitsi-meet/native/polyfills-browser.js @@ -1,3 +1,5 @@ +import BackgroundTimer from 'react-native-background-timer'; + /** * Gets the first common prototype of two specified Objects (treating the * objects themselves as prototypes as well). @@ -313,4 +315,18 @@ function _visitNode(node, callback) { } } + // Timers + // + // React Native's timers won't run while the app is in the background, + // this is a known limitation. Replace them with a background-friendly + // alternative. + // + // Required by: + // - lib-jitsi-meet + // - Strophe + global.setTimeout = window.setTimeout = BackgroundTimer.setTimeout; + global.clearTimeout = window.clearTimeout = BackgroundTimer.clearTimeout; + global.setInterval = window.setInterval = BackgroundTimer.setInterval; + global.clearInterval = window.clearInterval = BackgroundTimer.clearInterval; + })(global || window || this); // eslint-disable-line no-invalid-this