I’m working on an application which acts as a bridge between Xamarin and React Native. I’m following this GitHub project
https://github.com/voydz/xamarin-react-native
This is my NativePackage.cs code-
using Com.Facebook.React.Bridge;
using Com.Facebook.React.Uimanager;
using Com.Facebook.React;
using Java.Interop;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Android.Widget;
using Android.Content;
namespace ReactNative.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 };
Console.WriteLine("Hello CreateNativeModules");
return list;
}
public IList<ViewManager> CreateViewManagers(ReactApplicationContext context)
{
Console.WriteLine("Hello CreateViewManagers");
return new List<ViewManager> { };
}
}
public class NativeModule : ReactContextBaseJavaModule
{
public NativeModule(ReactApplicationContext reactContext) : base(reactContext)
{
Console.WriteLine("Hello NativeModule");
}
public override string Name => "XNativeModule";
[Export("Foo")]
[ReactMethod]
public void Foo()
{
Console.WriteLine("Hello Native World");
Toast.MakeText(ReactApplicationContext, "Hello Native World", ToastLength.Long).Show();
}
}
}
Following is my MainActivity code
using Android.App;
using Android.OS;
using Com.Facebook.React;
using Com.Facebook.React.Shell;
using Com.Facebook.React.Common;
using Android.Views;
using Com.Facebook.React.Modules.Core;
using Android.Support.V7.App;
using Android.Content;
using Android.Net;
using Android.Provider;
using ReactNative.Droid;
namespace SampleApp.Droid
{
[Activity(Label = "XamarinReactNative", MainLauncher = true, Icon = "@mipmap/icon", Theme = "@style/Theme.AppCompat.Light.NoActionBar")]
public class MainActivity : AppCompatActivity, IDefaultHardwareBackBtnHandler
{
ReactRootView mReactRootView;
ReactInstanceManager mReactInstanceManager;
private const int OVERLAY_PERMISSION_REQ_CODE = 1;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
if (Build.VERSION.SdkInt >= BuildVersionCodes.M)
{
if (!Settings.CanDrawOverlays(this))
{
Intent intent = new Intent(Settings.ActionManageOverlayPermission, Uri.Parse("package:" + PackageName));
StartActivityForResult(intent, OVERLAY_PERMISSION_REQ_CODE);
}
}
mReactRootView = new ReactRootView(this);
mReactInstanceManager = ReactInstanceManager.Builder()
.SetApplication(Application)
.SetBundleAssetName("index.android.bundle")
.SetJSMainModulePath("index")
.AddPackage(new MainReactPackage())
#if DEBUG
.SetUseDeveloperSupport(true)
#else
.SetUseDeveloperSupport(false)
#endif
.SetInitialLifecycleState(LifecycleState.Resumed)
.Build();
mReactRootView.StartReactApplication(mReactInstanceManager, "MyReactNativeApp", null);
SetContentView(mReactRootView);
}
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
if (requestCode == OVERLAY_PERMISSION_REQ_CODE)
{
if (Build.VERSION.SdkInt >= BuildVersionCodes.M)
{
if (!Settings.CanDrawOverlays(this))
{
// SYSTEM_ALERT_WINDOW permission not granted...
}
}
}
}
protected override void OnPause()
{
base.OnPause();
if (mReactInstanceManager != null)
{
mReactInstanceManager.OnHostPause(this);
}
}
protected override void OnResume()
{
base.OnResume();
if (mReactInstanceManager != null)
{
mReactInstanceManager.OnHostResume(this, this);
}
}
protected override void OnDestroy()
{
base.OnDestroy();
if (mReactInstanceManager != null)
{
mReactInstanceManager.OnHostDestroy(this);
}
}
public override void OnBackPressed()
{
if (mReactInstanceManager != null)
{
mReactInstanceManager.OnBackPressed();
}
else
{
base.OnBackPressed();
}
}
public void InvokeDefaultOnBackPressed()
{
base.OnBackPressed();
}
public override bool OnKeyUp(Keycode keyCode, KeyEvent e)
{
if (keyCode == Keycode.Menu && mReactInstanceManager != null)
{
mReactInstanceManager.ShowDevOptionsDialog();
return true;
}
return base.OnKeyUp(keyCode, e);
}
}
}
Following is my index.js code
import React, { Component } from 'react';
import {
AppRegistry,
Platform,
StyleSheet,
Text, Button,
View,NativeModules
} from 'react-native';
console.log(NativeModules);
const instructions = Platform.select({
ios: 'Press Cmd+R to reload,n' +
'Cmd+D or shake for dev menu',
android: 'Double tap R on your keyboard to reload this is part of React,n' +
'Shake or press menu button for dev menu',
});
const {XNativeModule}=NativeModules;
const RNHelloWorld=()=> {
return (
<View style={styles.container}>
<Text style={styles.welcome}>
Hey there Judson! This is React native project
</Text>
<Text style={styles.instructions}>
To get started, edit App.js
</Text>
<Text style={styles.instructions}>
{instructions}
</Text>
<Button onPress={() => XNativeModule.Foo()} title="Call Native Module" />
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5,
},
});
// Module name
AppRegistry.registerComponent('MyReactNativeApp', () => RNHelloWorld);
I’m getting following error when I click the button.
undefined is not an object (evaluating 'u.Foo')
Currently in my code when I call XNativeModule.Foo() from my JavaScript code, React Native bridges the call to the native module by sending a message to the native side using a message queue. On the native side, the Xamarin runtime receives the message and routes it to the appropriate native module. In this case, it will call the Foo() method defined in the XNativeModule class. In Xamarin.Android, the ReactContextBaseJavaModule class is used to create a native module that can be called from the React Native JavaScript code. But it is not working for me. I have no clue how to fix this. Any suggestions?
2
Answers
I fixed that by adding the NativePackage class in ReactInstanceManager. Native package class consists of Foo method since NativePackage class was not registered we where getting undefined error for Foo method. This is the my changes in MainActivity code
As you can see
AddPackage(new NativePackage())
in my MainActivity code. This fixed it and I was able to deploy the app without any exceptions.Since Foo isn’t a class method, can you remove
this
from button press