Native Modules What you can do ・ Function creation ・ Event notification ·Callback
Native UI Components What you can do ・ Create View -View event notification
Native Modules Take Module, which displays a dialog, as an example.
[function] 1, Display the Android dialog. (Creation of function) 2, When the "OK" button in the dialog is clicked, "true" is displayed on the console. (Event notification) 3, When the "DATE" button is clicked, the current time is displayed. (Callback)
DialogModule.java
public class DialogModule extends ReactContextBaseJavaModule {
//Constructor
public DialogModule(@NonNull ReactApplicationContext reactContext) {
super(reactContext);
}
//Something like a tag to call this module
@Override
public String getName() {
return "DialogModule";
}
//You can define class constants that can be used in RN
public Map<String, Object> getConstants() {
final Map<String, Object> constants = new HashMap<>();
constants.put("SINGLE_BUTTON", "SINGLE");
constants.put("DOUBLE_BUTTON", "DOUBLE");
return constants;
}
//Function to display a dialog
@ReactMethod
public void showDialog(String message, String type) {
if (type.equals("SINGLE")) {
new AlertDialog.Builder(getCurrentActivity())
.setTitle("DialogModule")
.setMessage(message)
.setPositiveButton("CLOSE", (dialog, which) -> {
dialog.dismiss();
})
.show();
} else {
new AlertDialog.Builder(getCurrentActivity())
.setTitle("DialogModule")
.setMessage(message)
.setPositiveButton("OK", (dialog, which) -> {
sendEvent();
})
.setNegativeButton("CLOSE", (dialog, which) -> {
dialog.dismiss();
})
.show();
}
}
//A function that displays the current time and calls back
@ReactMethod
private void getCurrentTime(Callback callback) {
Calendar calendar = Calendar.getInstance();
callback.invoke(calendar.getTime().toString());
}
//An event that notifies you that a button has been clicked
private void sendEvent() {
WritableMap params = Arguments.createMap();
params.putBoolean("click", true);
getReactApplicationContext()
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit("onClick", params);
}
}
getName
It is necessary to describe the character string when calling from RN like "DialogModule".
@Override
public String getName() {
return "DialogModule";
}
getConstants
You can set Molue class constants that can be used from the RN.
constants.put (constant name, value);
public Map<String, Object> getConstants() {
final Map<String, Object> constants = new HashMap<>();
constants.put("SINGLE_BUTTON", "SINGLE");
constants.put("DOUBLE_BUTTON", "DOUBLE");
return constants;
}
@ReactMethod
You can set the methods available from the RN.
If you want to execute a callback, execute it with .invoke ()
.
@ReactMethod
private void getCurrentTime(Callback callback) {
Calendar calendar = Calendar.getInstance();
callback.invoke(calendar.getTime().toString());
}
Event (listener)
You can set the events that can be registered in RN.
//Set the callback value
WritableMap params = Arguments.createMap();
params.putBoolean("click", true);
//Set event name and callback value
getReactApplicationContext()
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit("onClick", params);
Native UI Components Take a View that displays a video player as an example.
[function] 1, Display the video player. (Create View) 2, Receive the url from the RN side with props and play the video. 3, Display the log at the end of playback. (View event notification)
VideoViewManager.java
public class VideoViewManager extends SimpleViewManager<VideoView> {
private Context context;
//Something like a tag to call this module
@Override
public String getName() {
return "VideoView";
}
//Something like a constructor that returns an instant of the View to use
@Override
protected VideoView createViewInstance(ThemedReactContext reactContext) {
this.context = reactContext;
return new VideoView(reactContext);
}
//Function that processes with the value received by Props
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1)
@ReactProp(name="url")
public void setVideoPath(VideoView videoView, String urlPath) {
Uri uri = Uri.parse(urlPath);
videoView.setMediaController(new MediaController(context));
videoView.setVideoURI(uri);
//Play as soon as it is ready to play
videoView.setOnPreparedListener(mp -> {
videoView.start();
});
//Call back to "onFinish" of props at the end of playback.(notification)
videoView.setOnCompletionListener(mp -> {
ReactContext reactContext = (ReactContext)context;
WritableMap event = Arguments.createMap();
event.putString("message", "onDirectEvent");
reactContext.getJSModule(RCTEventEmitter.class).receiveEvent(videoView.getId(),"onDirectEvent",event);
WritableMap event2 = Arguments.createMap();
event2.putString("message", "onBubblingEvent");
reactContext.getJSModule(RCTEventEmitter.class).receiveEvent(videoView.getId(),"onBubblingEvent",event2);
});
videoView.getDuration();
}
@Override
public Map<String, Object> getExportedCustomDirectEventTypeConstants() {
return MapBuilder.<String, Object>builder()
.put("onDirectEvent", MapBuilder.of("registrationName", "onDirectEvent"))
.build();
}
@Override
public Map<String, Object> getExportedCustomBubblingEventTypeConstants() {
return MapBuilder.<String, Object>builder()
.put("onBubblingEvent", MapBuilder.of("phasedRegistrationNames",
MapBuilder.of(
"bubbled", "onBubble",
"captured", "onCapture")))
.build();
}
}
getName
The character string when calling from RN must be described as "VideoView".
@Override
public String getName() {
return "VideoView";
}
@ReactProp
Setter method that receives Props of View
The method name itself can be anything
@ReactProp (name =" props name ")
public void setProp (View type view, value of type Props)
@ReactProp(name="url")
public void setVideoPath(VideoView videoView, String urlPath) {
// ...
}
createViewInstance
A function that returns an instance of View
@Override
protected VideoView createViewInstance(ThemedReactContext reactContext) {
return new VideoView(reactContext);
}
Event notification
You can set Props callbacks.
There are two methods for registering events. ・ GetExportedCustomDirectEventTypeConstants ・ GetExportedCustomBubblingEventTypeConstants
getExportedCustomDirectEventTypeConstants
Notify one props with one event.
How to register
MapBuilder.builder (). Put ("event name", MapBuilder.of ("registrationName", "props name")). build ();
getExportedCustomBubblingEventTypeConstants
Two props can be notified in one event.
How to register
MapBuilder.builder (). Put ("event name", MapBuilder.of ("phasedRegistrationNames", MapBuilder.of ("bubbled", "props name 1", "captured", "props name 2"))). build ();
//Function to register an event 1
@Override
public Map<String, Object> getExportedCustomDirectEventTypeConstants() {
return MapBuilder.<String, Object>builder()
.put("onDirectEvent", MapBuilder.of("registrationName", "onDirectEvent"))
.build();
}
//Function 2 to register an event
@Override
public Map<String, Object> getExportedCustomBubblingEventTypeConstants() {
return MapBuilder.<String, Object>builder()
.put("onBubblingEvent", MapBuilder.of("phasedRegistrationNames",
MapBuilder.of(
"bubbled", "onBubble",
"captured", "onCapture")))
.build();
}
Call receiveEvent
where you want to be notified
receiveEvent ("view ID", "event name", callback value)
// ...
ReactContext reactContext = (ReactContext)context;
//Process to notify event 1"onDirectEvent"Event
WritableMap event = Arguments.createMap();
event.putString("message", "onDirectEvent");
reactContext.getJSModule(RCTEventEmitter.class).receiveEvent(videoView.getId(),"onDirectEvent",event);
//Process to notify event 2"onBubblingEvent"Event
WritableMap event2 = Arguments.createMap();
event2.putString("message", "onBubblingEvent");
reactContext.getJSModule(RCTEventEmitter.class).receiveEvent(videoView.getId(),"onBubblingEvent",event2);
// ...
On the RN side, the event is notified as follows
<VideoView
onDirectEvent={({ nativeEvent }) => console.log(nativeEvent.message)} // onDirectEvent
onCapture={({ nativeEvent }) => console.log(nativeEvent.message)} // onBubblingEvent
onBubble={({ nativeEvent }) => console.log(nativeEvent.message)} // onBubblingEvent
/>
Register the created Module and UI Component as follows
ExamplePackage.java
public class ExamplePackage implements ReactPackage {
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.<ViewManager>singletonList(
//Add as UI Components increase
new VideoViewManager()
);
}
@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext
return Collections.<ViewManager>singletonList(
//Add as more Modules
new DialogModule(reactContext)
);
}
}
Register the created package in getPackages
in MainApplication.java
MainApplication.java
@Override
protected List<ReactPackage> getPackages() {
List<ReactPackage> packages = new PackageList(this).getPackages();
//Add as the number of packages increases
packages.add(new ExamplePackage());
return packages;
}
RN side Native Modules
Dialog.jsx
import React from 'react';
import { NativeModules } from 'react-native';
//Return value of getName function("DialogModule")Specify
DialogModule = NativeModules.DialogModule;
const Dialog = () => {
const [date, setDate] = React.useState("");
React.useEffect(() => {
const eventEmitter = new NativeEventEmitter(DialogModule);
eventEmitter.addListener('onClick', (event) => {
console.log(event.change) // "true"
});
}, [])
return (
<>
<TouchableOpacity onPress={() => DialogModule.showDialog('SINGLE BUTTON', DialogModule.SINGLE_BUTTON)}>
<Text>SINGLE BUTTON Dialog</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => DialogModule.showDialog('DOUBLE BUTTON', DialogModule.DOUBLE_BUTTON)}>
<Text>DOUBLE BUTTON Dialog</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => DialogModule.getCurrentTime(time => setDate(time))}>
<Text>DATE</Text>
</TouchableOpacity>
<Text>CURRENT DATE:</Text>
<Text>[ {date} ]</Text>
</>
)
}
export default Dialog
VideoView.jsx
import React from 'react';
import { requireNativeComponent } from 'react-native';
VideoView = requireNativeComponent('VideoView');
const VideoView = () => {
return (
<>
<VideoView
style={{ width: '100%', height: '100%' }}
url="https://www.radiantmediaplayer.com/media/bbb-360p.mp4"
onDirectEvent={({ nativeEvent }) => console.log(nativeEvent.message)}
onCapture={({ nativeEvent }) => console.log(nativeEvent.message)}
onBubble={({ nativeEvent }) => console.log(nativeEvent.message)} />
</>
)
}
export default VideoView
When you want to call the function implemented in UI Component from Module
ExamplePackage.java
public class ExamplePackage implements ReactPackage {
private ExampleViewManager instance;
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.<ViewManager>singletonList(
instance
);
}
@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext
instance = new ExampleViewManager();
return Collections.<ViewManager>singletonList(
//Pass an instance of ViewManager to the module
//After that, you can call the method of the instance from the function defined in the module.
new ExampleModule(reactContext, instance)
);
}
}
Regarding the bridge part of Android, I had a lot of trouble with only English articles and many sample code that did not work. Since I didn't have much time to write an article, there may be some omissions or mistakes, so please use the content of the article as a reference.
Next, the article on the 20th day of React Native Advent Calendar is @ duka's "A story about AB test": tada:
Recommended Posts