Tree-based Progressive Migration:
from Native iOS to React-Native
Context
- Pragmatism-as-a-Service: deliver maximum value in minimal time
- Expertise: React Native, React, Angular, Node, Python and Symfony
Context
Me
- Joined Theodo ~1 year ago
-
Expertise: Angular, Node, React Native, Python.
-
No Objective-C experience
emoji unicode: 1f628
Context
I WANT TO REDESIGN SOME SCREENS IN MY APP,
CAN WE DO THAT IN REACT-NATIVE ?
CLIENT:
The Challenge
THE CHALLENGE: In Pub page
1 - FINDING THE ENTRY POINT
MPPubViewController *pubViewController = [[MPPubViewController alloc]
initWithInPub:dictionary
andWithBar:bar
withRewardId:nil];
[self.navigationController pushViewController:pubViewController animated:YES];
2 - REPLACE WITH REACT-native view
- Add to your Podfile
pod 'React', :path => '../node_modules/react-native', :subspecs => [
'Core',
'RCTText',
'RCTNetwork',
'RCTWebSocket', # needed for debugging
]
- Register a React-Native Component
import { AppRegistry } from 'react-native';
import InPubPage from './src/page/InPubPage';
AppRegistry.registerComponent('InPubPage', () => InPubPage);
2 - REPLACE WITH REACT-native view
Create a controller that contains the magic class: RCTRootView
#ifdef DEBUG
NSURL *jsCodeLocation =
[NSURL URLWithString:@"http://localhost:8081/index.ios.bundle?platform=ios"];
#else
NSURL *jsCodeLocation =
[[NSBundle mainBundle] URLForResource:@"index.ios" withExtension:@"bundle"];
#endif
self.rootView =
[[RCTRootView alloc] initWithBundleURL:jsCodeLocation
moduleName:@"InPubPage"
launchOptions:nil ];
self.view = self.rootView;
return self;
2 - REPLACE WITH REACT-native view
- (void) displayModal
-(void) hideModal
{
[self.view.layer setMasksToBounds:YES];
[self.view.layer setBackgroundColor:[UIColor colorWithWhite:1 alpha:0].CGColor];
backgroundView = [[UIView alloc] initWithFrame:CGRectMake(0, 0,
[[UIScreen mainScreen] bounds].size.width,
[[UIScreen mainScreen] bounds].size.height)];
[backgroundView addSubview:self.view];
CGRect targetFrame = CGRectMake(0, 0,
self.targetView.view.frame.size.width,
self.targetView.view.frame.size.height);
[self.view setFrame:targetFrame];
[self.targetView addChildViewController:self];
[self.targetView.view addSubview:backgroundView];
[self didMoveToParentViewController:self.targetView];
}
{
[self willMoveToParentViewController:nil];
[backgroundView removeFromSuperview];
[self removeFromParentViewController];
}
2 - REPLACE WITH REACT-native view
@implementation NavigationManager
+ (id) sharedInstance
{
...
}
// ...
- (void) goToInPubPage
{
self.inPubPageModal = [[RNInPubPageController alloc]
init:[UIApplication sharedApplication].keyWindow.rootViewController];
[self.inPubPageModal displayModal];
}
- (void) exitInPubPage
{
[self.inPubPageModal hideModal];
}
2 - REPLACE WITH REACT-native view
- Use the Navigation Singleton to create and display the modal
2 - REPLACE WITH REACT-native view
// MPPubViewController *pubViewController = [[MPPubViewController alloc]
// initWithInPub:dictionary
// andWithBar:bar
// withRewardId:nil];
// [self.navigationController pushViewController:pubViewController animated:YES];
// Enter React-Native sub-app
[[MPNavigationManager sharedInstance] goToInPubPage];
3 - PASS INFORMATIONS FROM NATIVE TO rEACT-NATIVE
self.rootView =
[[RCTRootView alloc] initWithBundleURL:jsCodeLocation
moduleName:@"InPubPage"
initialProperties:@{
@"bar" : self.bar
}
launchOptions:nil ];
This will be received as props in your component
4 - Back to previous screen
Native
#import "NativeNavigation.h"
#import "NavigationManager.h"
@implementation NativeNatigation
RCT_EXPORT_MODULE();
RCT_EXPORT_METHOD(exitInPubPage) {
dispatch_async(dispatch_get_main_queue(), ^{
[[MPNavigationManager sharedInstance] exitInPubPage];
});
}
import { NativeModules } from 'react-native';
export const NativeNavigation = NativeModules.NativeNavigation;
React-Native
import { NativeNavigation } from '../nativeNavigation';
// ...
<TouchableOpacity onPress={NativeNavigation.exitInPubPage}>
Back
</TouchableOpacity>
4 - Back to previous screen
5 - Go To any native screen
5 - Go To any native screen
KO :(
SOLUTION: Tree-based Approach
- Identify most connected leaf
- Find all entry points and replace with React-Native
- Repeat for all entry points
Conclusion
Useful Links:
PROS
- No need to know Objective-C
- Faster for designed views
- React-Native
CONS
- Need to start with leaves
- Making sure states are in sync can be tricky
QUESTIONS ?
Tree-based Progressive Migration - Final
By Jeremy Gotteland
Tree-based Progressive Migration - Final
- 328