Skip to content

Commit 8acfe41

Browse files
authored
Support headlessJs (wix#1444)
Currently startApp is called from global context which results in the app being launched when headlessJs tasks run in the background. In order to support this use case, while not breaking existing users, this commit adds two mechanisms which should help users detrmine if the native Activity is running and startApp can be called safely. 1. RNN.appLaunched event is emitted is SplashActivity starts and react context has already been created. This is the use case of openeing the app while headless js task was started or has just finished and react context is in a "pasued" state. 2. Navigation.isAppLaunched() convenience method has been added. It returns a promise which when resolved, indicates if the app is launched and we should show the ui or not. Usage import {Navigation, NativeEventsReceiver} from 'react-native-navigation'; Promise.resolve(Navigation.isAppLaunched()) .then(appLaunched => { if (appLaunched) { startApp(); } else { new NativeEventsReceiver().appLaunched(startApp); } }); function startApp() { Navigation.startTabBasedApp({ ... }); }
1 parent 932c3c6 commit 8acfe41

File tree

10 files changed

+65
-6
lines changed

10 files changed

+65
-6
lines changed

android/app/src/main/java/com/reactnativenavigation/bridge/EventEmitter.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,4 +52,11 @@ public void sendEvent(String eventId) {
5252
}
5353
reactGateway.getReactEventEmitter().sendEvent(eventId, Arguments.createMap());
5454
}
55+
56+
public void sendAppLaunchedEvent() {
57+
if (!NavigationApplication.instance.isReactContextInitialized()) {
58+
return;
59+
}
60+
reactGateway.getReactEventEmitter().sendEvent("RNN.appLaunched", Arguments.createMap());
61+
}
5562
}

android/app/src/main/java/com/reactnativenavigation/bridge/NavigationReactModule.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,4 +258,9 @@ public void dismissContextualMenu(String screenInstanceId) {
258258
public void getOrientation(Promise promise) {
259259
NavigationCommandsHandler.getOrientation(promise);
260260
}
261+
262+
@ReactMethod
263+
public void isAppLaunched(Promise promise) {
264+
NavigationCommandsHandler.isAppLaunched(promise);
265+
}
261266
}

android/app/src/main/java/com/reactnativenavigation/controllers/NavigationCommandsHandler.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -535,4 +535,9 @@ public static void getOrientation(Promise promise) {
535535
}
536536
promise.resolve(OrientationHelper.getOrientation(currentActivity));
537537
}
538+
539+
public static void isAppLaunched(Promise promise) {
540+
final boolean isAppLaunched = SplashActivity.isResumed || NavigationActivity.currentActivity != null;
541+
promise.resolve(isAppLaunched);
542+
}
538543
}

android/app/src/main/java/com/reactnativenavigation/controllers/SplashActivity.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import com.reactnativenavigation.react.ReactDevPermission;
1212

1313
public abstract class SplashActivity extends AppCompatActivity {
14+
public static boolean isResumed = false;
1415

1516
@Override
1617
protected void onCreate(@Nullable Bundle savedInstanceState) {
@@ -22,8 +23,11 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
2223
@Override
2324
protected void onResume() {
2425
super.onResume();
26+
isResumed = true;
2527

2628
if (NavigationApplication.instance.getReactGateway().hasStartedCreatingContext()) {
29+
NavigationApplication.instance.getEventEmitter().sendAppLaunchedEvent();
30+
overridePendingTransition(0, 0);
2731
finish();
2832
return;
2933
}
@@ -42,6 +46,12 @@ protected void onResume() {
4246
NavigationApplication.instance.startReactContextOnceInBackgroundAndExecuteJS();
4347
}
4448

49+
@Override
50+
protected void onPause() {
51+
super.onPause();
52+
isResumed = false;
53+
}
54+
4555
private void setSplashLayout() {
4656
final int splashLayout = getSplashLayout();
4757
if (splashLayout > 0) {

src/NativeEventsReceiver.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import {
2+
NativeAppEventEmitter,
3+
DeviceEventEmitter,
4+
Platform
5+
} from 'react-native';
6+
export default class NativeEventsReceiver {
7+
constructor() {
8+
this.emitter = Platform.OS === 'android' ? DeviceEventEmitter : NativeAppEventEmitter;
9+
}
10+
11+
appLaunched(callback) {
12+
this.emitter.addListener('RNN.appLaunched', callback);
13+
}
14+
}

src/Navigation.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,10 @@ function handleDeepLink(params = {}) {
162162
}
163163
}
164164

165+
async function isAppLaunched() {
166+
return await platformSpecific.isAppLaunched();
167+
}
168+
165169
export default {
166170
getRegisteredScreen,
167171
registerComponent,
@@ -177,5 +181,6 @@ export default {
177181
startSingleScreenApp: startSingleScreenApp,
178182
setEventHandler: setEventHandler,
179183
clearEventHandler: clearEventHandler,
180-
handleDeepLink: handleDeepLink
184+
handleDeepLink: handleDeepLink,
185+
isAppLaunched: isAppLaunched
181186
};

src/deprecated/indexDeprecated.android.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import Navigation from './../Navigation';
22
import SharedElementTransition from './../views/sharedElementTransition';
3+
import NativeEventsReceiver from './../NativeEventsReceiver';
34

45
module.exports = {
56
Navigation,
6-
SharedElementTransition
7+
SharedElementTransition,
8+
NativeEventsReceiver
79
};
8-
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import Navigation from './../Navigation';
22
import {NavigationToolBarIOS} from './controllers';
33
import SharedElementTransition from '../views/sharedElementTransition';
4+
import NativeEventsReceiver from './../NativeEventsReceiver';
45

56
module.exports = {
67
Navigation,
78
NavigationToolBarIOS,
8-
SharedElementTransition
9+
SharedElementTransition,
10+
NativeEventsReceiver
911
};

src/deprecated/platformSpecificDeprecated.android.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -675,6 +675,10 @@ function dismissContextualMenu() {
675675
newPlatformSpecific.dismissContextualMenu();
676676
}
677677

678+
async function isAppLaunched() {
679+
return await newPlatformSpecific.isAppLaunched();
680+
}
681+
678682
export default {
679683
startTabBasedApp,
680684
startSingleScreenApp,
@@ -704,5 +708,6 @@ export default {
704708
showSnackbar,
705709
dismissSnackbar,
706710
showContextualMenu,
707-
dismissContextualMenu
711+
dismissContextualMenu,
712+
isAppLaunched
708713
};

src/platformSpecific.android.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,10 @@ function setScreenStyle(screenInstanceId, style) {
177177
NativeReactModule.setScreenStyle(screenInstanceId, style);
178178
}
179179

180+
async function isAppLaunched() {
181+
return await NativeReactModule.isAppLaunched();
182+
}
183+
180184
module.exports = {
181185
startApp,
182186
push,
@@ -210,5 +214,6 @@ module.exports = {
210214
dismissSnackbar,
211215
showContextualMenu,
212216
dismissContextualMenu,
213-
setScreenStyle
217+
setScreenStyle,
218+
isAppLaunched
214219
};

0 commit comments

Comments
 (0)