Skip to content

Commit 1cf3697

Browse files
author
Riccardo Cipolleschi
committed
feat: add native code for android
1 parent 4ad7cf1 commit 1cf3697

File tree

2 files changed

+219
-2
lines changed

2 files changed

+219
-2
lines changed

docs/the-new-architecture/pillars-fabric-components.md

Lines changed: 218 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@ The code generated by the **CodeGen** in this step should not be committed to th
307307

308308
#### iOS
309309

310-
##### Generate the code
310+
##### Generate the code - iOS
311311

312312
To run Codegen for the iOS platform, we need to open a terminal and run the following command:
313313

@@ -519,6 +519,223 @@ Differently from Native Components, Fabric requires us to manually implement the
519519
520520
#### Android
521521
522+
Android follows some similar steps to iOS. We have to generate the code for Android, and then we have to write some native code to make it works.
523+
524+
##### Generate the Code - Android
525+
526+
To generate the code for Android, we need to manually invoke the CodeGen. This is done similarly to what we did for iOS: first, we need to add the package to the app and then we need to invoke a script.
527+
528+
```sh title="Running CodeGen for Android"
529+
cd MyApp
530+
yarn add ../RTNCenteredText
531+
cd android
532+
./gradlew generateCodegenArtifactsFromSchema --rerun-tasks
533+
```
534+
535+
This script first adds the package to the app, in the same way iOS does. Then, after moving to the `android` folder, it invokes a Gradle task to generate the codegen.
536+
537+
The generated code is stored in the `MyApp/node_modules/rnt-centered-text/android/build/generated/source/codegen` folder and it has this structure:
538+
539+
```title="Android generated code"
540+
codegen
541+
├── java
542+
│ └── com
543+
│ └── facebook
544+
│ └── react
545+
│ └── viewmanagers
546+
│ ├── RTNCenteredTextManagerDelegate.java
547+
│ └── RTNCenteredTextManagerInterface.java
548+
├── jni
549+
│ ├── Android.mk
550+
│ ├── CMakeLists.txt
551+
│ ├── RTNCenteredText-generated.cpp
552+
│ ├── RTNCenteredText.h
553+
│ └── react
554+
│ └── renderer
555+
│ └── components
556+
│ └── RTNCenteredText
557+
│ ├── ComponentDescriptors.h
558+
│ ├── EventEmitters.cpp
559+
│ ├── EventEmitters.h
560+
│ ├── Props.cpp
561+
│ ├── Props.h
562+
│ ├── ShadowNodes.cpp
563+
│ └── ShadowNodes.h
564+
└── schema.json
565+
```
566+
567+
You can see that the content of the `codegen/jni/react/renderer/components/RTNCenteredTextSpecs` looks similar to the files created by the iOS counterpart. Other interesting pieces are the `Android.mk` and `CMakeList.txt` files, which we need to configure the Fabric Component in the app, and the `RTNCenteredTextManagerDelegate.java` and `RTNCenteredTextManagerInterface.java` that we need to use in our manager.
568+
569+
See the [CodeGen](./pillars-codegen) section for further details on the generated files.
570+
571+
##### Write the Native Android Code
572+
573+
The native code for the Android side of a Fabric Components requires four pieces:
574+
575+
1. An `AndroidManifest.xml` file.
576+
2. A `RTNCenteredText.java` that represents the actual view.
577+
3. A `RTNCenteredTextManager.java` to instantiate the view.
578+
4. A `RTNCenteredTextPackage.java` that React Native uses to configure the library.
579+
580+
The final structure within the Android library should be like this.
581+
582+
```title="Android Folder Structure"
583+
android
584+
├── build.gradle
585+
└── src
586+
└── main
587+
├── AndroidManifest.xml
588+
└── java
589+
└── com
590+
└── rtncenteredtext
591+
├── RTNCenteredText.java
592+
├── RTNCenteredTextManager.java
593+
└── RTNCenteredTextPackage.java
594+
```
595+
596+
###### AndroidManifest.xml
597+
598+
```xml title="AndroidManifest.xml"
599+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
600+
package="com.rtncenteredtext">
601+
</manifest>
602+
```
603+
604+
This is a small manifest file that defines the package for our module.
605+
606+
###### RTNCenteredText.java
607+
608+
```java title="RTNCenteredText"
609+
package com.rtncenteredtext;
610+
611+
import androidx.annotation.Nullable;
612+
import android.content.Context;
613+
import android.util.AttributeSet;
614+
import android.graphics.Color;
615+
616+
import android.widget.TextView;
617+
import android.view.Gravity;
618+
619+
public class RTNCenteredText extends TextView {
620+
621+
public RTNCenteredText(Context context) {
622+
super(context);
623+
this.configureComponent();
624+
}
625+
626+
public RTNCenteredText(Context context, @Nullable AttributeSet attrs) {
627+
super(context, attrs);
628+
this.configureComponent();
629+
}
630+
631+
public RTNCenteredText(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
632+
super(context, attrs, defStyleAttr);
633+
this.configureComponent();
634+
}
635+
636+
private void configureComponent() {
637+
this.setBackgroundColor(Color.RED);
638+
this.setGravity(Gravity.CENTER_HORIZONTAL);
639+
}
640+
}
641+
```
642+
643+
This class represents the actual view Android is going to represent on screen. It inherit from `TextView` and we configure the basic aspects of it using a private `configureComponent()` function
644+
645+
###### RTNCenteredTextManager.java
646+
647+
```java title="RTNCenteredTextManager.java"
648+
package com.rtncenteredtext;
649+
650+
import androidx.annotation.NonNull;
651+
import androidx.annotation.Nullable;
652+
653+
import com.facebook.react.bridge.ReadableArray;
654+
import com.facebook.react.bridge.ReactApplicationContext;
655+
import com.facebook.react.module.annotations.ReactModule;
656+
import com.facebook.react.uimanager.SimpleViewManager;
657+
import com.facebook.react.uimanager.ThemedReactContext;
658+
import com.facebook.react.uimanager.ViewManagerDelegate;
659+
import com.facebook.react.uimanager.annotations.ReactProp;
660+
import com.facebook.react.viewmanagers.RTNCenteredTextManagerInterface;
661+
import com.facebook.react.viewmanagers.RTNCenteredTextManagerDelegate;
662+
663+
664+
@ReactModule(name = RTNCenteredTextManager.NAME)
665+
public class RTNCenteredTextManager extends SimpleViewManager<RTNCenteredText>
666+
implements RTNCenteredTextManagerInterface<RTNCenteredText> {
667+
668+
private final ViewManagerDelegate<RTNCenteredText> mDelegate;
669+
670+
static final String NAME = "RTNCenteredText";
671+
672+
public RTNCenteredTextManager(ReactApplicationContext context) {
673+
mDelegate = new RTNCenteredTextManagerDelegate<>(this);
674+
}
675+
676+
@Nullable
677+
@Override
678+
protected ViewManagerDelegate<RTNCenteredText> getDelegate() {
679+
return mDelegate;
680+
}
681+
682+
@NonNull
683+
@Override
684+
public String getName() {
685+
return RTNCenteredTextManager.NAME;
686+
}
687+
688+
@NonNull
689+
@Override
690+
protected RTNCenteredText createViewInstance(@NonNull ThemedReactContext context) {
691+
return new RTNCenteredText(context);
692+
}
693+
694+
@Override
695+
@ReactProp(name = "text")
696+
public void setText(RTNCenteredText view, @Nullable String text) {
697+
view.setText(text);
698+
}
699+
}
700+
```
701+
702+
The `RTNCenteredTextManager` is a class used by React Native to instantiate the native component. It is the class that leverage the **CodeGen** in order to implement all the proper interfaces (See the `RTNCenteredTextManagerInterface` interface in the `implements` clause) and it uses the `RTNCenteredTextManagerDelegate`.
703+
704+
It is also responsible to export all the constructs required by ReactNative: the class itself is annotated with `@ReactModule` and the `setText` method is annothated with `@ReactProp`.
705+
706+
###### RTNCenteredTextPackage.java
707+
708+
```java title="RTNCenteredTextPackage"
709+
package com.rtncenteredtext;
710+
711+
import com.facebook.react.ReactPackage;
712+
import com.facebook.react.bridge.NativeModule;
713+
import com.facebook.react.bridge.ReactApplicationContext;
714+
import com.facebook.react.uimanager.ViewManager;
715+
716+
import java.util.ArrayList;
717+
import java.util.Collections;
718+
import java.util.List;
719+
720+
public class RTNCenteredTextPackage implements ReactPackage {
721+
722+
@Override
723+
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
724+
List<ViewManager> viewManagers = new ArrayList<>();
725+
viewManagers.add(new RTNCenteredTextManager(reactContext));
726+
return viewManagers;
727+
}
728+
729+
@Override
730+
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
731+
return Collections.emptyList();
732+
}
733+
734+
}
735+
```
736+
737+
This is the last piece of Native Code for Android. It defines the Package object that will be used by the app to load the manager.
738+
522739
### Adding the Fabric Component To Your App
523740

524741
This is the last step to finally see our Fabric Component running on our app.

docs/the-new-architecture/pillars.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,5 @@ Finally, we dive a little deeper into the [CodeGen](pillars-codegen) process tha
2525
To integrate a TurboModule or a Fabric Component in an app, the app has to run with the New Architecture enabled.
2626

2727
To create a new app adopting the New Architecture, refer to the [Using the App Template](use-app-template) section.
28-
To migrate an existing app to the New Architecture, refer to the [Migration](/docs/new-architecture-intro) guide.
28+
To migrate an existing app to the New Architecture, refer to the [Migration](../new-architecture-intro) guide.
2929
:::

0 commit comments

Comments
 (0)