I have been tasked to see if it is possible to integrate React Native into a Xamarin.Forms project.
I think I came fairly close to achieving this, but I can't say for sure. I'm aware that this is a bit of a weird/ backwards solution, but I'd like to have a go at it anyway to see if I can beat it...
Intro
My employer is wanting to see if it is possible to use React Native for UI and use C# for the business logic. It is being explored as a solution so that the UI/UX team can produce work with RN and we (the dev team) can link in the logic to it.
What I've tried so far
I took the Xcode project that React Native outputted and started by removing the dependancy of a local Node service by cd'ing terminal into the project directory and ran react-native bundle --entry-file index.ios.js --platform ios --dev false --bundle-output ios/main.jsbundle --assets-dest ios
(taken from this blog post). I then made the change to the AppDelegate
line where it's looking for the main.jsbundle file.
I then added a static library as a target for the project. Comparing with the app's build phases, I then added all the same link libraries
After this, I created a Xamarin.Forms solution. As I had only created the iOS library, I created a iOS.Binding project. I added the Xcode .a lib as a native reference. Within the ApiDefinition.cs
file I created the interface with the following code
BaseType(typeof(NSObject))]
interface TheViewController
{
[Export("setMainViewController:")]
void SetTheMainViewController(UIViewController viewController);
}
To which, in the Xcode project, created a TheViewController
class. The setMainViewController:
was implemented in the following way:
-(void)setMainViewController:(UIViewController *)viewController{
AppDelegate * ad = (AppDelegate*)[UIApplication sharedApplication].delegate;
NSURL * jsCodeLocation = [NSURL fileURLWithPath:[[NSBundle mainBundle]pathForResource:@"main" ofType:@"jsbundle"]];
RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
moduleName:@"prototyper"
initialProperties:nil
launchOptions:ad.savedLaunchOptions];
rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];
ad.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
viewController.view = rootView;
ad.window.rootViewController = viewController;
[ad.window makeKeyAndVisible];
}
Where I am effectively trying to pass in a UIViewController
from Xamarin for the React Native stuff to add itself to.
I am calling this from Xamarin.iOS in the following way:
private Binding.TheViewController _theViewController;
public override void ViewDidLoad()
{
base.ViewDidLoad();
_theViewController = new TheViewController();
_theViewController.SetTheMainViewController(this);
}
This class is implementing PageRenderer
, overriding the Xamarin.Forms' ContentPage
using
[assembly:ExportRenderer(typeof(RNTest.MainViewController), typeof(RNTest.iOS.MainViewController))]
Well, after all of this, I went to go and deploy to device and, expectedly, hit by a number of errors. The AOT compiler is going into my lib and trying to do it's magic and throws a number of linker errors in the React Native projects, as shown below.
Pastebin dump of full Build Output
I was intending on setting up more methods in the binding to set callbacks etc to start building some functionality regarding passing information back and forth with the Objective-C, which I was going to pass into the React Native with some native code link.
Summary
I know it's pretty long breathed, but if we can get this off the ground, then we can basically do all of our (fairly comlex) business logic in C# and leave all the UI changes to the dedicated UI team, who have a strong preference for React Native (fair enough, with their prototype being in pretty good condition). Really, it's all just another POC that I've been putting together for the next major release of our app.
If anyone can think of a better way of doing this, I am all ears. I have, of course, glazed over some of the details, so if anything needs clarifying then please ask and I will ammend.
Many, many thanks.
Luke