This project is inspired and based on https://github.com/cluxton/xamarin-react-native. Credits to him, for his good work! 👍
This example includes a working proof-of-concept for both Xamarin.Android and Xamarin.iOS. Also there are renderers for Xamarin.Forms.
This is mainly a proof-of-concept and a challange to make transitioning projects from Xamarin to react-native a lot easier.
To get startet just install the NuGet packages you need for your project. It depends on which project type you are dealing with. The version of the NuGet package indicates in which version of react-native is targeted. For example the version 1.0.**50**
targets react-native ^0.50.0
.
- Xamarin.Droid - https://www.nuget.org/packages/ReactNative.Droid/
- Xamarin.iOS - https://www.nuget.org/packages/ReactNative.iOS/
- Xamarin.iOS for Debugging (see notes in 1. Getting your hands dirty) https://www.nuget.org/packages/ReactNative.iOS.Debug/
- Xamarin.Forms.Droid - https://www.nuget.org/packages/ReactNative.Forms.Droid/
- Xamarin.Forms.iOS - https://www.nuget.org/packages/ReactNative.Forms.iOS/
(you can and should use the ReactNative.iOS.Debug
package in exchange for ReactNative.iOS
for debugging purposes)
There are a lot of react-native components which need native linking. This binding already contains a precompiled and linked version of react-native. In theroy every component which need native linking should work if bound to C# seperatly. Make sure it is referencing this base react-native binding.
You can also write your own native modules for iOS or Android that can be called from javascript. See below for examples:
using System;
using Foundation;
using System.Runtime.InteropServices;
using ReactNative.iOS;
using UIKit;
namespace Example.iOS
{
public class NativeModule : RCTBridgeModule
{
[Export("moduleName")]
public static string ModuleName() => "SomeName";
[Export("requiresMainQueueSetup")]
public static bool RequiresMainQueueSetup() => false;
[Export("Foo")]
public void Foo()
{
Console.Write("Hello Native World!")
}
[Export("__rct_export__Foo")]
public static IntPtr FooExport()
{
var temp = new RCTMethodInfo()
{
jsName = string.Empty,
objcName = "Foo",
isSync = false
};
var ptr = Marshal.AllocHGlobal(Marshal.SizeOf(temp));
Marshal.StructureToPtr(temp, ptr, false);
return ptr;
}
}
}
using System.Collections.Generic;
using Android.Content;
using Com.Facebook.React;
using Com.Facebook.React.Bridge;
using Com.Facebook.React.Uimanager;
using Java.Interop;
namespace Example.Droid
{
public class NativePackage : Java.Lang.Object, IReactPackage
{
public IList<INativeModule> CreateNativeModules(ReactApplicationContext context)
{
var module = new NativeModule(context);
var list = new List<INativeModule> { module };
return list;
}
public IList<ViewManager> CreateViewManagers(ReactApplicationContext context)
{
return new List<ViewManager> { };
}
}
public class NativeModule : ReactContextBaseJavaModule
{
public NativeModule(ReactApplicationContext reactContext) : base(reactContext) { }
public override string Name => "SomeName";
[Export]
[ReactMethod]
public void Foo()
{
Console.Write("Hello Native World")
}
}
}
To build the application you will first need to download React Native & build the static library for Xamarin to use.
DO THIS STUFF TO MAKE IT WORK facebook/react-native#21168 (comment) https://github.com/facebook/react-native/pull/19579/commits/293915091ca6c9de2c54681e78eecf3229bc05d5?utf8=✓&diff=split&w=1
It is crucial to understand, that since the library is compiled and linked statically you have to ship seperate *.dlls
for release and debug. For example a release build of libReactNative.a
won't contain the DevSupport tools. See the commands below on how you can change the build configuration.
After checking out the project run the following commands:
# inside of ./binding/ReactNative.iOS
# install all node dependencies
yarn install
# build static react native library and the binding
make build CONFIGURATION=Debug # or Release respectively (case sensitive), default: Debug
This will only work for debug builds. Run the following command and check that your javascript bundle is available on http://localhost:8081/index.bundle
If you deploy to a physical device make sure you update the url inside SampleApp.iOS/AppDelegate.cs
with your local ip address, so that the device can reach the packager in your local network.
# inside of ./binding
# run react native packager
yarn start
This is recommended for release builds. You will need to update the javascript source inside samples/SampleApp.iOS/AppDelegate.cs
or samples/SampleApp.Forms/Mainpage.xaml
to the bundled asset.
# inside of ./binding
# bundle javascript to embeddable main.jsbundle
yarn bundle-ios
After you have done this, you can open the project samples/SampleApp.sln
and deploy it to a device or simulator.
After checking out the project run the following commands:
# inside of ./binding/ReactNative.Droid
# install all node dependencies
yarn install
# build the android binding
make build
This is recommended for release builds.
# inside of ./binding/
# bundle javascript to embeddable index.android
yarn bundle-android
Using the react packager is only possible once the app already started and loaded it's bundle from Assets/
. See Known Issues.
This will only work for debug builds. Run the following command and check that your javascript bundle is available on http://localhost:8081/index.bundle
# inside of ./binding
# run react native packager
yarn start
Open the react dev support menu and Refresh
the view or Enable hot reloading
to check if everything works.
After you have done this, you can open the project samples/SampleApp.sln
and deploy it to a device or simulator.
- The precompiled
ReactNative.Droid
assembly references theSquare.Okio
package. This will cause build errors in the DEXer build step if you are usingmodernhttpclient
. This is becausemodernhttpclient
ships with its own prebundled version ofokhttp
.- Workaround: You have to compile
ReactNative.Droid
by yourself and remove the duplicated native references. Alternatively you can use a fork ofmodernhttpclient
which does not embed its own version ofokhttp
.
- Workaround: You have to compile
- The Android sample application does not initially load from the react packager. Or is this the intended behavior?
- Workaround: Instead you have to
yarn bundle
and include theindex.android.bundle
in the androidAssets/
directory.
- Workaround: Instead you have to