Search code examples
javaandroidiosreact-nativeobjective-c++

How to do event handling for android and iOS in react native's new architecture for fabric components?


I am trying to create a Fabric component. I have got it working for the most part. The only issue I am facing is I am not able to get click listener to work for a fabric component.

I created a spec file

import type {HostComponent, ViewProps} from 'react-native';
import type {DirectEventHandler} from 'react-native/Libraries/Types/CodegenTypes';
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';

type Event = Readonly<{
  value: string;
}>;

interface NativeProps extends ViewProps {
  text: string;
   onClickHandler?: BubblingEventHandler<Event>; ////Event name should start with on
}

export default codegenNativeComponent<NativeProps>(
  'MyButtonView',
) as HostComponent<NativeProps>;

For android my fabric component looks like as follows

public class MyButtonView extends androidx.appcompat.widget.AppCompatButton {

    public MyButtonView(Context context) {
        super(context);
        configureViews();
    }

    private void configureViews(){
        setBackgroundColor(Color.YELLOW);
        setOnClickListener(view -> {
            onReceiveNativeEvent();
        });
    }

    public void onReceiveNativeEvent() {
        WritableMap event = Arguments.createMap();
        event.putString("message", "MyMessage");
        ReactContext reactContext = (ReactContext)getContext();
        reactContext.getJSModule(RCTModernEventEmitter.class)
                .receiveEvent(getId(),getId(),"onClickHandler",true,0,event,1);

    }
}

Not sure what to pass first param as int, canCoalesceEvent, customCoalesceKey and category in receiveEvent

In ViewManager I did add following code as well

@Nullable
@Override
public Map<String, Object> getExportedCustomDirectEventTypeConstants() {
    Log.i("here55","999999");
    return MapBuilder.of("onClickHandler",
            MapBuilder.of("registrationName", "onClickHandler")
    );
}

For android I am not getting the callback from native android to js side

I am following https://reactnative.dev/docs/native-components-android but it was for the old architecture and I think is not applicable for fabric components

Same for iOS https://reactnative.dev/docs/native-components-ios, the doc is not very helpful for the new architecture

For iOS, I created the header and objective-c++ file

Typically if we want to add property we do this

RCT_EXPORT_VIEW_PROPERTY(text, NSString)

Not sure how to do it for event handler


Solution

  • iOS

    Assuming native spec you posted is correct (I'm not really familiar with TypeScript + Codegen duo) when you run pod install command in your ios/ directory codegen should generate EventEmitters cpp file (+ header) in React-Codegen pod (you can see below how to find it in XCode)

    link to the screenshot with Pods structure

    You can then use these classes in your Objective-C++ code to emit the events:

    if (_eventEmitter != nullptr) {
        std::dynamic_pointer_cast<const facebook::react::$$NAME OF YOUR EVENT EMITTER TYPE$$>(_eventEmitter)
            ->onEvent(facebook::react::$$NAME OF YOUR EVENT EMITTER TYPE::OnEvent{.value = $$VALUE$$});
    }
    

    See links below to see how it is done in react-native-screens

    1. Native component spec in Flow
    2. Event emission in Obj-C++ code
    3. Event exposure in screen manager - I'm not quite sure if this line is necessary, haven't tested it out yet.

    Android

    1. To trigger codegen just run native build.
    2. Define native event class as done here
    3. Take a look here for how to dispatch event
    4. Export your event types