Skip to content

Commit 2555e8f

Browse files
authored
Merge pull request Expensify#65442 from software-mansion-labs/war-in/send-hybridAppSettings-in-native-method
Send `hybridAppSettings` via native method
2 parents f35ae15 + 08cc113 commit 2555e8f

8 files changed

Lines changed: 44 additions & 15 deletions

File tree

modules/hybrid-app/android/src/main/java/com/expensify/reactnativehybridapp/ReactNativeHybridApp.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package com.expensify.reactnativehybridapp
33
import com.facebook.react.bridge.ReactApplicationContext
44
import com.facebook.react.module.annotations.ReactModule
55
import android.util.Log
6+
import com.facebook.react.bridge.Promise
67

78
@ReactModule(name = NativeReactNativeHybridAppSpec.NAME)
89
class ReactNativeHybridApp(reactContext: ReactApplicationContext) :
@@ -36,4 +37,9 @@ class ReactNativeHybridApp(reactContext: ReactApplicationContext) :
3637
override fun sendAuthToken(authToken: String?) {
3738
Log.d(NAME, "`sendAuthToken` should never be called in standalone `New Expensify` app")
3839
}
40+
41+
override fun getHybridAppSettings(promise: Promise) {
42+
Log.d(NAME, "`getHybridAppSettings` should never be called in standalone `New Expensify` app")
43+
promise.reject("NOT_IMPLEMENTED", "getHybridAppSettings is not implemented in standalone New Expensify app")
44+
}
3945
}

modules/hybrid-app/ios/ReactNativeHybridApp.mm

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,12 @@ - (void)sendAuthToken:(NSString *)authToken {
2727
NSLog(@"[ReactNativeHybridApp] `sendAuthToken` should never be called in standalone `New Expensify` app");
2828
}
2929

30+
- (void)getHybridAppSettings:(RCTPromiseResolveBlock)resolve
31+
reject:(RCTPromiseRejectBlock)reject {
32+
NSLog(@"[ReactNativeHybridApp] `getHybridAppSettings` should never be called in standalone `New Expensify` app");
33+
reject(@"NOT_IMPLEMENTED", @"This method is not available in standalone New Expensify app", nil);
34+
}
35+
3036
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
3137
(const facebook::react::ObjCTurboModule::InitParams &)params
3238
{

modules/hybrid-app/src/NativeReactNativeHybridApp.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ export interface Spec extends TurboModule {
99
completeOnboarding: (status: boolean) => void;
1010
switchAccount: (newDotCurrentAccountEmail: string, authToken: string, policyID: string, accountID: string) => void;
1111
sendAuthToken: (authToken: string) => void;
12+
getHybridAppSettings: () => Promise<string | null>;
1213
}
1314

1415
export default TurboModuleRegistry.getEnforcing<Spec>('ReactNativeHybridApp');

modules/hybrid-app/src/index.native.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ const HybridAppModule: HybridAppModuleType = {
2020
sendAuthToken({authToken}) {
2121
ReactNativeHybridApp.sendAuthToken(authToken);
2222
},
23+
getHybridAppSettings() {
24+
return ReactNativeHybridApp.getHybridAppSettings();
25+
},
2326
};
2427

2528
export default HybridAppModule;

modules/hybrid-app/src/index.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ const HybridAppModule: HybridAppModuleType = {
2424
// eslint-disable-next-line no-console
2525
console.warn('HybridAppModule: `sendAuthToken` should never be called on web');
2626
},
27+
getHybridAppSettings() {
28+
// eslint-disable-next-line no-console
29+
console.warn('HybridAppModule: `getHybridAppSettings` should never be called on web');
30+
return Promise.resolve(null);
31+
},
2732
};
2833

2934
export default HybridAppModule;

modules/hybrid-app/src/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ type HybridAppModuleType = {
55
completeOnboarding: (args: {status: boolean}) => void;
66
switchAccount: (args: {newDotCurrentAccountEmail: string; authToken: string; policyID: string; accountID: string}) => void;
77
sendAuthToken: (args: {authToken: string}) => void;
8+
getHybridAppSettings: () => Promise<string | null>;
89
};
910

1011
export default HybridAppModuleType;

src/App.tsx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,6 @@ import {SplashScreenStateContextProvider} from './SplashScreenStateContext';
5454
type AppProps = {
5555
/** The URL specifying the initial navigation destination when the app opens */
5656
url?: Route;
57-
/** Serialized configuration data required to initialize the React Native app (e.g. authentication details) */
58-
hybridAppSettings?: string;
5957
};
6058

6159
LogBox.ignoreLogs([
@@ -71,15 +69,15 @@ const fill = {flex: 1};
7169

7270
const StrictModeWrapper = CONFIG.USE_REACT_STRICT_MODE_IN_DEV ? React.StrictMode : ({children}: {children: React.ReactElement}) => children;
7371

74-
function App({url, hybridAppSettings}: AppProps) {
72+
function App({url}: AppProps) {
7573
useDefaultDragAndDrop();
7674
OnyxUpdateManager();
7775

7876
return (
7977
<StrictModeWrapper>
8078
<SplashScreenStateContextProvider>
8179
<InitialURLContextProvider url={url}>
82-
<HybridAppHandler hybridAppSettings={hybridAppSettings} />
80+
<HybridAppHandler />
8381
<GestureHandlerRootView style={fill}>
8482
<ComposeProviders
8583
components={[

src/HybridAppHandler.tsx

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,31 @@
1-
import {useContext, useState} from 'react';
2-
import type {AppProps} from './App';
1+
import HybridAppModule from '@expensify/react-native-hybrid-app';
2+
import {useContext, useEffect} from 'react';
33
import CONFIG from './CONFIG';
44
import CONST from './CONST';
55
import {signInAfterTransitionFromOldDot} from './libs/actions/Session';
6+
import Log from './libs/Log';
67
import SplashScreenStateContext from './SplashScreenStateContext';
78

8-
function HybridAppHandler({hybridAppSettings}: AppProps) {
9-
const [signInHandled, setSignInHandled] = useState(false);
9+
function HybridAppHandler() {
1010
const {setSplashScreenState} = useContext(SplashScreenStateContext);
1111

12-
if (!CONFIG.IS_HYBRID_APP || !hybridAppSettings || signInHandled) {
13-
return null;
14-
}
12+
useEffect(() => {
13+
if (!CONFIG.IS_HYBRID_APP) {
14+
return;
15+
}
1516

16-
signInAfterTransitionFromOldDot(hybridAppSettings).then(() => {
17-
setSplashScreenState(CONST.BOOT_SPLASH_STATE.READY_TO_BE_HIDDEN);
18-
setSignInHandled(true);
19-
});
17+
HybridAppModule.getHybridAppSettings().then((hybridAppSettings: string | null) => {
18+
if (!hybridAppSettings) {
19+
// Native method can send non-null value only once per NewDot lifecycle. It prevents issues with multiple initializations during reloads on debug builds.
20+
Log.info('[HybridApp] `getHybridAppSettings` called more than once during single NewDot lifecycle. Skipping initialization.');
21+
return;
22+
}
23+
24+
signInAfterTransitionFromOldDot(hybridAppSettings).then(() => {
25+
setSplashScreenState(CONST.BOOT_SPLASH_STATE.READY_TO_BE_HIDDEN);
26+
});
27+
});
28+
}, [setSplashScreenState]);
2029

2130
return null;
2231
}

0 commit comments

Comments
 (0)