I am trying to call an Android native method showJ
from Javascript in React Native but I keep getting the error :
2019-12-10 20:22:31.959 24712-24861/com.example.myapplication E/ReactNativeJS: TypeError: Cannot read property 'showJ' of null
2019-12-10 20:22:31.976 24712-24712/com.example.myapplication E/unknown:ReactNative: Unable to launch redbox because react activity is not available, here is the error that redbox would've displayed: TypeError: Cannot read property 'showJ' of null, js engine: hermes
Any help resolving this will be greatly appreciated. Thank you all in advance.
This is how I go about it :
public class MainActivity extends AppCompatActivity {
Button myButton;
public static int OVERLAY_PERMISSION_REQ_CODE = 2;
LinearLayout rootContainer_LL;
LinearLayout scrollViewWrapperItems_LL;
MyReactView myReactView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
rootContainer_LL = new LinearLayout(this);
myButton = new Button(this);
myButton.setText("REV _Button");
myButton.setOnClickListener(v -> viewOnClick());
rootContainer_LL.addView(myButton);
setContentView(rootContainer_LL);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (!Settings.canDrawOverlays(this)) {
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, OVERLAY_PERMISSION_REQ_CODE);
}
}
myReactView = new MyReactView(this);
}
void viewOnClick() {
rootContainer_LL.addView(myReactView.reactJsView());
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == OVERLAY_PERMISSION_REQ_CODE) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (!Settings.canDrawOverlays(this)) {
// SYSTEM_ALERT_WINDOW permission not granted...
}
}
}
}
}
Get the React view :
public class MyReactView {
private Context context;
private ReactRootView mReactRootView;
private ReactInstanceManager mReactInstanceManager;
public MyReactView(Context context) {
this.context = context;
mReactInstanceManager = ReactInstanceManager.builder()
.setApplication(((Activity) context).getApplication())
.setBundleAssetName("index.android.bundle")
.setJSMainModulePath("index")
.addPackage(new MainReactPackage())
.setUseDeveloperSupport(BuildConfig.DEBUG)
.setInitialLifecycleState(LifecycleState.BEFORE_CREATE)
.build();
}
public View reactJsView() {
Bundle initialProperties = new Bundle();
initialProperties.putString("var_1", "Im the first var");
mReactRootView = new ReactRootView(context);
mReactRootView.startReactApplication(mReactInstanceManager, "HelloWorld", initialProperties);
return mReactRootView;
}
}
Then MainApplication
public class MainApplication extends Application implements ReactApplication {
private final ReactNativeHost mReactNativeHost =
new ReactNativeHost(this) {
@Override
public boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}
@Override
protected List<ReactPackage> getPackages() {
@SuppressWarnings("UnnecessaryLocalVariable")
List<ReactPackage> packages = new PackageList(this).getPackages();
// Packages that cannot be autolinked yet can be added manually here, for example:
// packages.add(new MyReactNativePackage());
// return packages;
packages.add(new CustomToastPackage());
Log.v("MyApp", "APP CALL FUNCS");
return packages;
}
@Override
protected String getJSMainModuleName() {
return "index";
}
};
@Override
public ReactNativeHost getReactNativeHost() {
return mReactNativeHost;
}
@Override
public void onCreate() {
super.onCreate();
SoLoader.init(this, /* native exopackage */ false);
}
}
Then I try adopting the implementation as directed in The Toast Module
ToastModule
public class ToastModule extends ReactContextBaseJavaModule {
private static ReactApplicationContext reactContext;
private static final String DURATION_SHORT_KEY = "SHORT";
private static final String DURATION_LONG_KEY = "LONG";
ToastModule(ReactApplicationContext context) {
super(context);
reactContext = context;
}
@Override
public String getName() {
return "ToastExample";
}
@Override
public Map<String, Object> getConstants() {
final Map<String, Object> constants = new HashMap<>();
constants.put(DURATION_SHORT_KEY, Toast.LENGTH_SHORT);
constants.put(DURATION_LONG_KEY, Toast.LENGTH_LONG);
return constants;
}
@ReactMethod
public void showJ(String message, int duration) {
Toast.makeText(getReactApplicationContext(), message, duration).show();
}
}
CustomToastPackage
public class CustomToastPackage implements ReactPackage {
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
List<NativeModule> modules = new ArrayList<>();
modules.add(new ToastModule(reactContext));
return modules;
}
}
The Javascript call
import {NativeModules} from 'react-native';
module.exports = NativeModules.ToastExample;
then . . .
import ToastExample from './ToastExample';
ToastExample.showJ('Awesome', ToastExample.SHORT);
UPDATE
The full javascript implementation :
import React, {Component} from 'react';
import {AppRegistry, StyleSheet, Text, View, TouchableOpacity} from 'react-native';
import {name as appName} from './app.json';
import ToastExample from './ToastExample';
class HelloWorld extends Component {
async sayHiFromJava() {
ToastExample.showJ('Awesome', ToastExample.SHORT);
}
render() {
return (
<View style={
styles.container
}>
<TouchableOpacity style={
styles.btnStyleH
}
onPress={
this.sayHiFromJava
}>
<View>
<Text style={
styles.btnStyle
}>...PUSH</Text>
</View>
</TouchableOpacity>
</View>
);
}
}
var styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'flex-start',
flexDirection: 'row'
},
btnStyle: {
fontSize: 10,
justifyContent: 'flex-start'
}
});
AppRegistry.registerComponent(appName, () => HelloWorld);
then : ToastExample.js
import {NativeModules} from 'react-native';
module.exports = NativeModules.ToastExample;
are you add a file named "ToastExample.js" and add these lines into.
import {NativeModules} from 'react-native'; module.exports = NativeModules.ToastExample;
and then call the "ToastExample.js" file from your main js file by means of these lines:
import ToastExample from './ToastExample'; ToastExample.showJ('Awesome', ToastExample.SHORT);
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.