├── .gitignore
├── README.md
├── _img
└── android_metrics.png
├── android
├── build.gradle
└── src
│ ├── main
│ ├── AndroidManifest.xml
│ └── java
│ │ └── nl
│ │ └── skillnation
│ │ └── rlottie
│ │ ├── RLottiePackage.java
│ │ ├── RLottieView.java
│ │ └── RLottieViewManagerImpl.java
│ ├── newarch
│ └── java
│ │ └── nl
│ │ └── skillnation
│ │ └── rlottie
│ │ └── RLottieViewManager.java
│ └── oldarch
│ └── java
│ └── nl
│ └── skillnation
│ └── rlottie
│ └── RLottieViewManager.java
├── babel.config.js
├── example
├── .buckconfig
├── .bundle
│ └── config
├── .eslintrc.js
├── .gitignore
├── .prettierrc.js
├── .ruby-version
├── App.tsx
├── Gemfile
├── __tests__
│ └── App-test.tsx
├── android
│ ├── app
│ │ ├── _BUCK
│ │ ├── build.gradle
│ │ ├── build_defs.bzl
│ │ ├── debug.keystore
│ │ ├── proguard-rules.pro
│ │ └── src
│ │ │ ├── debug
│ │ │ ├── AndroidManifest.xml
│ │ │ └── java
│ │ │ │ └── com
│ │ │ │ └── newarchitecture
│ │ │ │ └── ReactNativeFlipper.java
│ │ │ └── main
│ │ │ ├── AndroidManifest.xml
│ │ │ ├── java
│ │ │ └── com
│ │ │ │ └── newarchitecture
│ │ │ │ ├── MainActivity.java
│ │ │ │ ├── MainApplication.java
│ │ │ │ └── newarchitecture
│ │ │ │ ├── MainApplicationReactNativeHost.java
│ │ │ │ ├── components
│ │ │ │ └── MainComponentsRegistry.java
│ │ │ │ └── modules
│ │ │ │ └── MainApplicationTurboModuleManagerDelegate.java
│ │ │ ├── jni
│ │ │ ├── Android.mk
│ │ │ ├── MainApplicationModuleProvider.cpp
│ │ │ ├── MainApplicationModuleProvider.h
│ │ │ ├── MainApplicationTurboModuleManagerDelegate.cpp
│ │ │ ├── MainApplicationTurboModuleManagerDelegate.h
│ │ │ ├── MainComponentsRegistry.cpp
│ │ │ ├── MainComponentsRegistry.h
│ │ │ └── OnLoad.cpp
│ │ │ └── res
│ │ │ ├── drawable
│ │ │ └── rn_edit_text_material.xml
│ │ │ ├── mipmap-hdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-mdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ │ └── values
│ │ │ ├── strings.xml
│ │ │ └── styles.xml
│ ├── build.gradle
│ ├── gradle.properties
│ ├── gradle
│ │ └── wrapper
│ │ │ ├── gradle-wrapper.jar
│ │ │ └── gradle-wrapper.properties
│ ├── gradlew
│ ├── gradlew.bat
│ └── settings.gradle
├── app.json
├── assets
│ └── icon_trophy.json
├── babel.config.js
├── index.js
├── ios
│ ├── NewArchitecture.xcodeproj
│ │ └── project.pbxproj
│ ├── NewArchitecture.xcworkspace
│ │ └── contents.xcworkspacedata
│ ├── NewArchitecture
│ │ ├── AppDelegate.h
│ │ ├── AppDelegate.mm
│ │ ├── Images.xcassets
│ │ │ ├── AppIcon.appiconset
│ │ │ │ └── Contents.json
│ │ │ └── Contents.json
│ │ ├── Info.plist
│ │ ├── LaunchScreen.storyboard
│ │ └── main.m
│ ├── NewArchitectureTests
│ │ ├── Info.plist
│ │ └── NewArchitectureTests.m
│ ├── Podfile
│ └── Podfile.lock
├── metro.config.js
├── package.json
├── src
│ ├── components
│ │ ├── Item.tsx
│ │ └── PerformanceScreen.tsx
│ └── screens
│ │ ├── HomeScreen.tsx
│ │ ├── ManualControlScreen.tsx
│ │ ├── PerformanceLottieScreen.tsx
│ │ ├── PerformanceRLottieScreen.tsx
│ │ └── SimpleViewScreen.tsx
└── yarn.lock
├── ios
├── RNLottieView.xcodeproj
│ ├── project.pbxproj
│ └── project.xcworkspace
│ │ └── contents.xcworkspacedata
└── RNLottieView
│ ├── LottieTypes.h
│ ├── RLottieView.h
│ ├── RLottieView.mm
│ └── RNLottieViewManager.mm
├── package.json
├── react-native-rlottie.podspec
├── src
├── RLottieViewNativeComponent.js
└── index.tsx
├── tsconfig.build.json
├── tsconfig.json
└── yarn.lock
/.gitignore:
--------------------------------------------------------------------------------
1 | **/xcshareddata/*
2 | **/xcuserdata/*
3 | .DS_Store
4 | **/.DS_Store
5 | **/constents.xcworkspacedata
6 | node_modules/
7 | build/
8 | .gradle/
9 | .vscode
10 | # generated by bob
11 | lib/
12 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 🌈 react-native-rlottie
2 |
3 | ## Features
4 |
5 | - ▶️ Uses [rlottie](https://github.com/Samsung/rlottie) to run lottie animations
6 | - 🌠 rlottie creates rasterized bitmaps for each frame of the animation (instead of using the platform's animation API to continuisly run the animation).
7 | - This also gives us the possibility to pre-render the animation into cache, so even complex animation can start and run in 60 FPS
8 | - ✅ Compatible with the new architecture (Fabric)
9 | - 🤖 Especially on android, using rlottie can be more performant than [lottie-android](https://github.com/airbnb/lottie-android) (which is used by [lottie-react-native](https://github.com/lottie-react-native/lottie-react-native)):
10 | - 📉 Using less CPU and RAM
11 | - 🏃♂️ Puts less pressure on the UI/main Thread, ensuring 60 FPS even on low end devices
12 | - Read more in [Performance Comparison](#performance-comparison)
13 |
14 | ## Usage
15 |
16 | We try to be as close to the [lottie-react-native](https://github.com/lottie-react-native/lottie-react-native) implementation API, so you can use this library as drop-in replacement/complement.
17 |
18 | So loading a local animation really is the same:
19 |
20 | ```jsx
21 | import React from 'react';
22 | import {View} from 'react-native';
23 | import RLottieView from 'react-native-rlottie';
24 |
25 | const lottieAnim = require('./assets/icon_trophy.json');
26 |
27 | const App = () => {
28 | return (
29 |
30 |
31 |
32 | );
33 | };
34 |
35 | const styles = StyleSheet.create({
36 | animation: {
37 | height: 700,
38 | width: 700,
39 | },
40 | });
41 |
42 | export default App;
43 | ```
44 |
45 | ## Performance Comparison
46 |
47 | All data for the comparison can be found here: https://docs.google.com/spreadsheets/d/1Akz2As7HSJ7n9kmpIMYG966GY4QybOkJth5nNewYZhs/edit?usp=sharing
48 |
49 | We compared react-native-rlottie with lottie-react-native:
50 |
51 |
52 | ### 🤖 Android
53 |
54 | 
55 |
56 | #### Key observations
57 |
58 | - Running the animation consumes less CPU (-76%) and memory (-41%).
59 | - The animation runs fluently in 60 FPS, whereas lottie-android causes the FPS to drop.
60 | - This is due to the fact that the animation used for testing is a "complex" one, and running the animation with the platform's animated/art API is more expensive then to render the animation as bitmaps.
61 |
62 | ### 🍎 iOS
63 |
64 | ```
65 | // TODO: Comparison for ios
66 | ```
67 |
68 | #### Key observations
69 |
70 | - Running the animation with lottie-react-native adds CPU pressure. Using the example with an iPhone 7+ there is a ~10% CPU pressure during running the animation with lottie-rn, whereas with rlottie its 0%
71 |
72 | ### Overall key points
73 |
74 | - Constantly running an animation with rlottie is in general more resource-saving, thus it can ensure more stable FPS, specially on low end devices.
75 | - **HOWEVER**, the first time you render the animation rlottie will use _more_ resources than lottie-rn, as it needs to decode all frames for the first time. For large and complex animations this can be a severe factor. That's why, especially on iOS, its recommanded to pre-load an animation.
76 | - In general, you should check the performance implications for each animation you are using, and test yourself if you are getting better results with lottie-rn or rlottie.
77 |
78 | _Note:_ The performance results have been recorded with [react-native-performance-stats](https://github.com/skillnation/react-native-performance-stats).
79 |
80 | ### How to test yourself
81 |
82 |
83 | Click to expand:
84 |
85 | - Setup the example app on your machine
86 | - You might want to replace the animation to test with your own. Simply replace the file `example/assets/icon_trophy.json`
87 | - First, open the "Performance test: RLottie" screen in the example app and press start.
88 | - Wait ~20 seconds until an array is printed to your console output
89 | - Copy that data to a online service that convert JSON data in CSV: https://www.convertcsv.com/json-to-csv.htm
90 | - Copy the resulting table and paste the data in a copy of the benchmark google sheet named earlier
91 | - Repeat the same with the lottie-react-native screen
92 |
93 |
94 | ## Installation
95 |
96 | ```bash
97 | yarn add react-native-rlottie@alpha
98 |
99 | npm i react-native-rlottie@alpha
100 | ```
101 |
102 | ### iOS
103 |
104 | Run pod install:
105 |
106 | ```bash
107 | npx pod-install
108 | ```
109 |
110 | ### Android
111 |
112 | No additional steps for android are required, except when using the new react native architecture:
113 |
114 |
115 | Click to expand for the instructions:
116 |
117 | (_Note:_ This setup is required to to the fact that the on android Autolinking doesn't work with the new architecture out of the box. This procedure will change in the future.)
118 |
119 | 1. Open `android/app/build.gradle` file and update the file as it follows:
120 | ```diff
121 | defaultConfig {
122 | ...
123 | "PROJECT_BUILD_DIR=$buildDir",
124 | "REACT_ANDROID_DIR=$rootDir/../node_modules/react-native/ReactAndroid",
125 | - "REACT_ANDROID_BUILD_DIR=$rootDir/../node_modules/react-native/ReactAndroid/build"
126 | + "REACT_ANDROID_BUILD_DIR=$rootDir/../node_modules/react-native/ReactAndroid/build",
127 | + "NODE_MODULES_DIR=$rootDir/../node_modules/"
128 | cFlags "-Wall", "-Werror", "-fexceptions", "-frtti", "-DWITH_INSPECTOR=1"
129 | cppFlags "-std=c++17"
130 | ```
131 | 1. Open the `android/app/src/main/jni/Android.mk` file and update the file as it follows:
132 | ```diff
133 | # If you wish to add a custom TurboModule or Fabric component in your app you
134 | # will have to include the following autogenerated makefile.
135 | # include $(GENERATED_SRC_DIR)/codegen/jni/Android.mk
136 | +
137 | + # Includes the MK file for `react-native-rlottie`
138 | + include $(NODE_MODULES_DIR)/react-native-rlottie/android/build/generated/source/codegen/jni/Android.mk
139 | +
140 | include $(CLEAR_VARS)
141 | ```
142 | 1. In the same file above, go to the `LOCAL_SHARED_LIBRARIES` setting and add the following line:
143 | ```diff
144 | libreact_codegen_rncore \
145 | + libreact_codegen_rlottieview \
146 | libreact_debug \
147 | ```
148 | 1. Open the `android/app/src/main/jni/MainComponentsRegistry.cpp` file and update the file as it follows:
149 | 1. Add the import for the RLottieView:
150 | ```diff
151 | #include
152 | + #include
153 | #include
154 | ```
155 | 1. Add the following check in the `sharedProviderRegistry` constructor:
156 | ```diff
157 | auto providerRegistry = CoreComponentsRegistry::sharedProviderRegistry();
158 |
159 | // Custom Fabric Components go here. You can register custom
160 | // components coming from your App or from 3rd party libraries here.
161 | //
162 | // providerRegistry->add(concreteComponentDescriptorProvider<
163 | // AocViewerComponentDescriptor>());
164 | + providerRegistry->add(concreteComponentDescriptorProvider());
165 |
166 | return providerRegistry;
167 | }
168 | ```
169 |
170 |
171 | ## Supported After Effects Features
172 |
173 | This has full feature parity with rlottie, so check their [supported features here](https://github.com/Samsung/rlottie#supported-after-effects-features)
174 |
175 | ## Caveats
176 |
177 | In our testing, on iOS, there is a blocking of the UI thread and it takes some time until the animation is ready (for our most complex animation its 2s!).
178 | On iOS we are still missing some of the optimziation that we have already on android such as async/threaded frame decoding on the fly.
179 | Once we add those features we believe the performance can be similar to android. However, more development/research is needed.
180 | If you are an iOS dev, we welcome you to take on the challenge and improve or provide wisdom 🙌
181 |
182 | ## Development
183 |
184 | We are open for and welcoming contribution of any kind!
185 |
186 | To develop this library use the `example/`. Simply install the dependencies in the root dir
187 | with `yarn` and then install the dependencies in the `example/`.
188 |
189 | As this library is compatible with the old and the new arch, it can be useful to check both versions during development.
190 |
191 | ### 🤖 Switching arch:
192 |
193 | In `example/android/gradle.properties` you can simply toggle the `newArchEnabled` variable.
194 |
195 | ### 🍎 Switching arch:
196 |
197 | Go into `example/ios` and run the following command setting `RCT_NEW_ARCH_ENABLED` to `1` or `0` depending on which arch you want to test:
198 |
199 | ```bash
200 | cd ios && RCT_NEW_ARCH_ENABLED=1 pod install && cd ..
201 | ```
202 |
203 | ## References / Used libraries / Thanks
204 |
205 | - https://github.com/Aghajari/AXrLottie - Used for android implementation, does all the heavy lifting, thx <3
206 | - https://github.com/SDWebImage/librlottie-Xcode - Providing rlottie as cocoapods package, ready to be consumed by XCode, thx <3
207 |
--------------------------------------------------------------------------------
/_img/android_metrics.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hannojg/react-native-rlottie/db08d2b8e9ac6459e0f11b4d9acb705b1cfbb775/_img/android_metrics.png
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext.safeExtGet = {prop, fallback ->
3 | rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
4 | }
5 | repositories {
6 | google()
7 | gradlePluginPortal()
8 | }
9 | dependencies {
10 | classpath("com.android.tools.build:gradle:7.0.4")
11 | }
12 | }
13 |
14 | def isNewArchitectureEnabled() {
15 | return project.hasProperty("newArchEnabled") && project.newArchEnabled == "true"
16 | }
17 |
18 | apply plugin: 'com.android.library'
19 | if (isNewArchitectureEnabled()) {
20 | apply plugin: 'com.facebook.react'
21 | }
22 |
23 | android {
24 | compileSdkVersion safeExtGet('compileSdkVersion', 31)
25 |
26 | defaultConfig {
27 | minSdkVersion safeExtGet('minSdkVersion', 21)
28 | targetSdkVersion safeExtGet('targetSdkVersion', 31)
29 | buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
30 | }
31 |
32 | sourceSets {
33 | main {
34 | if (isNewArchitectureEnabled()) {
35 | java.srcDirs += ['src/newarch']
36 | } else {
37 | java.srcDirs += ['src/oldarch']
38 | }
39 | }
40 | }
41 | }
42 |
43 | repositories {
44 | maven {
45 | // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
46 | url "$projectDir/../node_modules/react-native/android"
47 | }
48 | mavenCentral()
49 | google()
50 | }
51 |
52 | dependencies {
53 | implementation 'com.facebook.react:react-native:+'
54 | implementation 'io.github.aghajari:AXrLottie:1.3.1'
55 | }
56 |
57 | if (isNewArchitectureEnabled()) {
58 | react {
59 | jsRootDir = file("../src/")
60 | libraryName = "rlottieview"
61 | codegenJavaPackageName = "nl.skillnation.rlottie"
62 | }
63 | }
--------------------------------------------------------------------------------
/android/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/android/src/main/java/nl/skillnation/rlottie/RLottiePackage.java:
--------------------------------------------------------------------------------
1 | package nl.skillnation.rlottie;
2 |
3 | import androidx.annotation.NonNull;
4 |
5 | import com.facebook.react.ReactPackage;
6 | import com.facebook.react.bridge.NativeModule;
7 | import com.facebook.react.bridge.ReactApplicationContext;
8 | import com.facebook.react.uimanager.ViewManager;
9 |
10 | import java.util.Collections;
11 | import java.util.List;
12 |
13 | public class RLottiePackage implements ReactPackage {
14 | @NonNull
15 | @Override
16 | public List createNativeModules(@NonNull ReactApplicationContext reactContext) {
17 | return Collections.emptyList();
18 | }
19 |
20 | @NonNull
21 | @Override
22 | public List createViewManagers(@NonNull ReactApplicationContext reactContext) {
23 | return Collections.singletonList(
24 | new RLottieViewManager(reactContext)
25 | );
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/android/src/main/java/nl/skillnation/rlottie/RLottieView.java:
--------------------------------------------------------------------------------
1 | package nl.skillnation.rlottie;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 |
6 | import androidx.annotation.NonNull;
7 | import androidx.annotation.Nullable;
8 |
9 | import com.aghajari.rlottie.AXrLottieDrawable;
10 | import com.aghajari.rlottie.AXrLottieImageView;
11 |
12 | public class RLottieView extends AXrLottieImageView {
13 | private boolean isAutoPlay = false;
14 | private float speed = 1.0f;
15 |
16 | private int decodeWidth, decodeHeight;
17 | private String jsonString;
18 | private boolean isInit;
19 |
20 | public RLottieView(@NonNull Context context) {
21 | super(context);
22 | }
23 |
24 | public RLottieView(@NonNull Context context, @Nullable AttributeSet attrs) {
25 | super(context, attrs);
26 | }
27 |
28 | public RLottieView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
29 | super(context, attrs, defStyleAttr);
30 | }
31 |
32 | //#region Layout size
33 | @Override
34 | protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
35 | super.onLayout(changed, left, top, right, bottom);
36 | if (decodeWidth == 0) {
37 | decodeWidth = getWidth();
38 | }
39 | if (decodeHeight == 0) {
40 | decodeHeight = getHeight();
41 | }
42 |
43 | maybeInitAnimation();
44 | }
45 |
46 | public void setDecodeWidth(int decodeWidth) {
47 | this.decodeWidth = decodeWidth;
48 | maybeInitAnimation();
49 | }
50 |
51 | public void setDecodeHeight(int decodeHeight) {
52 | this.decodeHeight = decodeHeight;
53 | maybeInitAnimation();
54 | }
55 | //#endregion
56 |
57 | //#region Animation
58 | public void setJSONStringSource(String jsonString) {
59 | this.jsonString = jsonString;
60 | maybeInitAnimation();
61 | }
62 |
63 | private String getCacheKey() {
64 | if (jsonString == null || decodeWidth == 0 || decodeHeight == 0) {
65 | return null;
66 | }
67 | return jsonString.hashCode() + "-" + decodeWidth + "-" + decodeHeight;
68 | }
69 |
70 | private void maybeInitAnimation() {
71 | if (isInit) return;
72 | String cacheKey = getCacheKey();
73 | if (cacheKey == null) return;
74 | isInit = true;
75 |
76 | setLottieDrawable(
77 | AXrLottieDrawable.fromJson(jsonString, cacheKey)
78 | .setSize(decodeWidth, decodeHeight)
79 | .setSpeed(speed)
80 | .build()
81 | );
82 |
83 | maybeAutoStartAnimation();
84 | }
85 | //#endregion
86 |
87 | //#region AutoStart
88 | public void setAutoPlay(boolean autoPlay) {
89 | isAutoPlay = autoPlay;
90 | maybeAutoStartAnimation();
91 | if (!autoPlay && isInit && getLottieDrawable() != null && !getLottieDrawable().isRunning()) {
92 | this.stopAnimation();
93 | }
94 | }
95 |
96 | private void maybeAutoStartAnimation() {
97 | if (isAutoPlay && getLottieDrawable() != null && !getLottieDrawable().isRunning()) {
98 | playAnimation();
99 | }
100 | }
101 | //#endregion
102 |
103 | //#region Properties: Loop, speed
104 | public void setIsLoop(boolean loop) {
105 | super.setAutoRepeat(loop);
106 | if (getLottieDrawable() != null) {
107 | if (!loop) {
108 | stopAnimation();
109 | }
110 |
111 | isInit = false;
112 | maybeInitAnimation();
113 | }
114 | }
115 |
116 | public void setSpeed(float speed) {
117 | this.speed = speed;
118 | if (getLottieDrawable() != null) {
119 | if (speed <= 0) {
120 | stopAnimation();
121 | } else {
122 | isInit = false;
123 | maybeInitAnimation();
124 | }
125 | }
126 | }
127 | //#endregion
128 | }
129 |
--------------------------------------------------------------------------------
/android/src/main/java/nl/skillnation/rlottie/RLottieViewManagerImpl.java:
--------------------------------------------------------------------------------
1 | package nl.skillnation.rlottie;
2 |
3 | import android.widget.ImageView;
4 |
5 | import androidx.annotation.NonNull;
6 |
7 | import com.aghajari.rlottie.AXrLottie;
8 | import com.facebook.react.bridge.ReactApplicationContext;
9 | import com.facebook.react.uimanager.SimpleViewManager;
10 | import com.facebook.react.uimanager.ThemedReactContext;
11 | import com.facebook.react.uimanager.annotations.ReactProp;
12 |
13 | public class RLottieViewManagerImpl extends SimpleViewManager {
14 |
15 | public static final String NAME = "RLottieView";
16 |
17 | protected ReactApplicationContext mCallerContext;
18 |
19 | public RLottieViewManagerImpl(ReactApplicationContext reactContext) {
20 | mCallerContext = reactContext;
21 | AXrLottie.init(reactContext);
22 | }
23 |
24 | @NonNull
25 | @Override
26 | public String getName() {
27 | return NAME;
28 | }
29 |
30 | @NonNull
31 | @Override
32 | protected RLottieView createViewInstance(@NonNull ThemedReactContext context) {
33 | return new RLottieView(context);
34 | }
35 |
36 | @ReactProp(name="isAutoPlay")
37 | public void setIsAutoPlay(RLottieView view, boolean isAutoPlay) {
38 | view.setAutoPlay(isAutoPlay);
39 | }
40 |
41 | @ReactProp(name="src")
42 | public void setSrc(RLottieView view, String jsonString) {
43 | view.setJSONStringSource(jsonString);
44 | }
45 |
46 | @ReactProp(name="progress")
47 | public void setProgress(RLottieView view, float progress) {
48 | if (view == null || view.getLottieDrawable() == null) return; // TODO: With new arch setProgress isn't called (thus the animation isn't running)
49 | view.getLottieDrawable().setProgress(progress);
50 | }
51 |
52 | @ReactProp(name="decodeHeight")
53 | public void setDecodeHeight(RLottieView view, int height) {
54 | view.setDecodeHeight(height);
55 | }
56 |
57 | @ReactProp(name="decodeWidth")
58 | public void setDecodeWidth(RLottieView view, int width) {
59 | view.setDecodeWidth(width);
60 | }
61 |
62 | @ReactProp(name="resizeMode")
63 | public void setResizeMode(RLottieView view, String resizeMode) {
64 | ImageView.ScaleType mode = null;
65 | if ("cover".equals(resizeMode)) {
66 | mode = ImageView.ScaleType.CENTER_CROP;
67 | } else if ("contain".equals(resizeMode)) {
68 | mode = ImageView.ScaleType.CENTER;
69 | } else if ("center".equals(resizeMode)) {
70 | mode = ImageView.ScaleType.CENTER_INSIDE;
71 | }
72 | view.setScaleType(mode);
73 | }
74 |
75 | @ReactProp(name="loop")
76 | public void setLoop(RLottieView view, boolean loop) {
77 | view.setIsLoop(loop);
78 | }
79 |
80 | @ReactProp(name="speed")
81 | public void setSpeed(RLottieView view, float speed) {
82 | view.setSpeed(speed);
83 | }
84 |
85 | @Override
86 | public void onDropViewInstance(@NonNull RLottieView view) {
87 | super.onDropViewInstance(view);
88 | view.release();
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/android/src/newarch/java/nl/skillnation/rlottie/RLottieViewManager.java:
--------------------------------------------------------------------------------
1 | package nl.skillnation.rlottie;
2 |
3 | import androidx.annotation.Nullable;
4 |
5 | import com.facebook.react.bridge.ReactApplicationContext;
6 | import com.facebook.react.module.annotations.ReactModule;
7 | import com.facebook.react.uimanager.ViewManagerDelegate;
8 | import com.facebook.react.viewmanagers.RLottieViewManagerDelegate;
9 | import com.facebook.react.viewmanagers.RLottieViewManagerInterface;
10 |
11 | @ReactModule(name = RLottieViewManager.NAME)
12 | public class RLottieViewManager extends RLottieViewManagerImpl
13 | implements RLottieViewManagerInterface {
14 |
15 | public static final String NAME = "RLottieView";
16 |
17 | private final ViewManagerDelegate mDelegate;
18 |
19 | public RLottieViewManager(ReactApplicationContext reactContext) {
20 | super(reactContext);
21 | mDelegate = new RLottieViewManagerDelegate<>(this);
22 | }
23 |
24 | @Nullable
25 | @Override
26 | protected ViewManagerDelegate getDelegate() {
27 | return mDelegate;
28 | }
29 |
30 | @Override
31 | public void setDecodeWidth(RLottieView view, float value) {
32 | this.setDecodeWidth(view, Math.round(value));
33 | }
34 |
35 | @Override
36 | public void setDecodeHeight(RLottieView view, float value) {
37 | this.setDecodeHeight(view, Math.round(value));
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/android/src/oldarch/java/nl/skillnation/rlottie/RLottieViewManager.java:
--------------------------------------------------------------------------------
1 | package nl.skillnation.rlottie;
2 |
3 | import com.facebook.react.bridge.ReactApplicationContext;
4 |
5 | public class RLottieViewManager extends RLottieViewManagerImpl {
6 | public RLottieViewManager(ReactApplicationContext reactContext) {
7 | super(reactContext);
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: ['module:metro-react-native-babel-preset'],
3 | };
4 |
--------------------------------------------------------------------------------
/example/.buckconfig:
--------------------------------------------------------------------------------
1 |
2 | [android]
3 | target = Google Inc.:Google APIs:23
4 |
5 | [maven_repositories]
6 | central = https://repo1.maven.org/maven2
7 |
--------------------------------------------------------------------------------
/example/.bundle/config:
--------------------------------------------------------------------------------
1 | BUNDLE_PATH: "vendor/bundle"
2 | BUNDLE_FORCE_RUBY_PLATFORM: 1
3 |
--------------------------------------------------------------------------------
/example/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | extends: '@react-native-community',
4 | parser: '@typescript-eslint/parser',
5 | plugins: ['@typescript-eslint'],
6 | overrides: [
7 | {
8 | files: ['*.ts', '*.tsx'],
9 | rules: {
10 | '@typescript-eslint/no-shadow': ['error'],
11 | 'no-shadow': 'off',
12 | 'no-undef': 'off',
13 | },
14 | },
15 | ],
16 | };
17 |
--------------------------------------------------------------------------------
/example/.gitignore:
--------------------------------------------------------------------------------
1 | # OSX
2 | #
3 | .DS_Store
4 |
5 | # Xcode
6 | #
7 | build/
8 | *.pbxuser
9 | !default.pbxuser
10 | *.mode1v3
11 | !default.mode1v3
12 | *.mode2v3
13 | !default.mode2v3
14 | *.perspectivev3
15 | !default.perspectivev3
16 | xcuserdata
17 | *.xccheckout
18 | *.moved-aside
19 | DerivedData
20 | *.hmap
21 | *.ipa
22 | *.xcuserstate
23 |
24 | # Android/IntelliJ
25 | #
26 | build/
27 | .idea
28 | .gradle
29 | local.properties
30 | *.iml
31 | *.hprof
32 |
33 | # node.js
34 | #
35 | node_modules/
36 | npm-debug.log
37 | yarn-error.log
38 |
39 | # BUCK
40 | buck-out/
41 | \.buckd/
42 | *.keystore
43 | !debug.keystore
44 |
45 | # fastlane
46 | #
47 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
48 | # screenshots whenever they are needed.
49 | # For more information about the recommended setup visit:
50 | # https://docs.fastlane.tools/best-practices/source-control/
51 |
52 | */fastlane/report.xml
53 | */fastlane/Preview.html
54 | */fastlane/screenshots
55 |
56 | # Bundle artifact
57 | *.jsbundle
58 |
59 | # Ruby / CocoaPods
60 | /ios/Pods/
61 | /vendor/bundle/
62 |
--------------------------------------------------------------------------------
/example/.prettierrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | arrowParens: 'avoid',
3 | bracketSameLine: true,
4 | bracketSpacing: false,
5 | singleQuote: true,
6 | trailingComma: 'all',
7 | };
8 |
--------------------------------------------------------------------------------
/example/.ruby-version:
--------------------------------------------------------------------------------
1 | 2.7.4
2 |
--------------------------------------------------------------------------------
/example/App.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {NavigationContainer} from '@react-navigation/native';
3 | import {createNativeStackNavigator} from '@react-navigation/native-stack';
4 | import {HomeScreen} from './src/screens/HomeScreen';
5 | import {SimpleViewScreen} from './src/screens/SimpleViewScreen';
6 | import {ManualControlScreen} from './src/screens/ManualControlScreen';
7 | import {PerformanceRLottieScreen} from './src/screens/PerformanceRLottieScreen';
8 | import {PerformanceLottieScreen} from './src/screens/PerformanceLottieScreen';
9 |
10 | const Stack = createNativeStackNavigator();
11 |
12 | const App = () => {
13 | return (
14 |
15 |
16 |
17 |
18 |
22 |
26 |
30 |
31 |
32 | );
33 | };
34 | export default App;
35 |
--------------------------------------------------------------------------------
/example/Gemfile:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 |
3 | # You may use http://rbenv.org/ or https://rvm.io/ to install and use this version
4 | ruby '2.7.4'
5 |
6 | gem 'cocoapods', '~> 1.11', '>= 1.11.2'
7 |
--------------------------------------------------------------------------------
/example/__tests__/App-test.tsx:
--------------------------------------------------------------------------------
1 | /**
2 | * @format
3 | */
4 |
5 | import 'react-native';
6 | import React from 'react';
7 | import App from '../App';
8 |
9 | // Note: test renderer must be required after react-native.
10 | import renderer from 'react-test-renderer';
11 |
12 | it('renders correctly', () => {
13 | renderer.create();
14 | });
15 |
--------------------------------------------------------------------------------
/example/android/app/_BUCK:
--------------------------------------------------------------------------------
1 | # To learn about Buck see [Docs](https://buckbuild.com/).
2 | # To run your application with Buck:
3 | # - install Buck
4 | # - `npm start` - to start the packager
5 | # - `cd android`
6 | # - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"`
7 | # - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck
8 | # - `buck install -r android/app` - compile, install and run application
9 | #
10 |
11 | load(":build_defs.bzl", "create_aar_targets", "create_jar_targets")
12 |
13 | lib_deps = []
14 |
15 | create_aar_targets(glob(["libs/*.aar"]))
16 |
17 | create_jar_targets(glob(["libs/*.jar"]))
18 |
19 | android_library(
20 | name = "all-libs",
21 | exported_deps = lib_deps,
22 | )
23 |
24 | android_library(
25 | name = "app-code",
26 | srcs = glob([
27 | "src/main/java/**/*.java",
28 | ]),
29 | deps = [
30 | ":all-libs",
31 | ":build_config",
32 | ":res",
33 | ],
34 | )
35 |
36 | android_build_config(
37 | name = "build_config",
38 | package = "com.newarchitecture",
39 | )
40 |
41 | android_resource(
42 | name = "res",
43 | package = "com.newarchitecture",
44 | res = "src/main/res",
45 | )
46 |
47 | android_binary(
48 | name = "app",
49 | keystore = "//android/keystores:debug",
50 | manifest = "src/main/AndroidManifest.xml",
51 | package_type = "debug",
52 | deps = [
53 | ":app-code",
54 | ],
55 | )
56 |
--------------------------------------------------------------------------------
/example/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: "com.android.application"
2 | apply from: "../../node_modules/react-native-vector-icons/fonts.gradle"
3 |
4 | import com.android.build.OutputFile
5 | import org.apache.tools.ant.taskdefs.condition.Os
6 |
7 | /**
8 | * The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets
9 | * and bundleReleaseJsAndAssets).
10 | * These basically call `react-native bundle` with the correct arguments during the Android build
11 | * cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the
12 | * bundle directly from the development server. Below you can see all the possible configurations
13 | * and their defaults. If you decide to add a configuration block, make sure to add it before the
14 | * `apply from: "../../node_modules/react-native/react.gradle"` line.
15 | *
16 | * project.ext.react = [
17 | * // the name of the generated asset file containing your JS bundle
18 | * bundleAssetName: "index.android.bundle",
19 | *
20 | * // the entry file for bundle generation. If none specified and
21 | * // "index.android.js" exists, it will be used. Otherwise "index.js" is
22 | * // default. Can be overridden with ENTRY_FILE environment variable.
23 | * entryFile: "index.android.js",
24 | *
25 | * // https://reactnative.dev/docs/performance#enable-the-ram-format
26 | * bundleCommand: "ram-bundle",
27 | *
28 | * // whether to bundle JS and assets in debug mode
29 | * bundleInDebug: false,
30 | *
31 | * // whether to bundle JS and assets in release mode
32 | * bundleInRelease: true,
33 | *
34 | * // whether to bundle JS and assets in another build variant (if configured).
35 | * // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants
36 | * // The configuration property can be in the following formats
37 | * // 'bundleIn${productFlavor}${buildType}'
38 | * // 'bundleIn${buildType}'
39 | * // bundleInFreeDebug: true,
40 | * // bundleInPaidRelease: true,
41 | * // bundleInBeta: true,
42 | *
43 | * // whether to disable dev mode in custom build variants (by default only disabled in release)
44 | * // for example: to disable dev mode in the staging build type (if configured)
45 | * devDisabledInStaging: true,
46 | * // The configuration property can be in the following formats
47 | * // 'devDisabledIn${productFlavor}${buildType}'
48 | * // 'devDisabledIn${buildType}'
49 | *
50 | * // the root of your project, i.e. where "package.json" lives
51 | * root: "../../",
52 | *
53 | * // where to put the JS bundle asset in debug mode
54 | * jsBundleDirDebug: "$buildDir/intermediates/assets/debug",
55 | *
56 | * // where to put the JS bundle asset in release mode
57 | * jsBundleDirRelease: "$buildDir/intermediates/assets/release",
58 | *
59 | * // where to put drawable resources / React Native assets, e.g. the ones you use via
60 | * // require('./image.png')), in debug mode
61 | * resourcesDirDebug: "$buildDir/intermediates/res/merged/debug",
62 | *
63 | * // where to put drawable resources / React Native assets, e.g. the ones you use via
64 | * // require('./image.png')), in release mode
65 | * resourcesDirRelease: "$buildDir/intermediates/res/merged/release",
66 | *
67 | * // by default the gradle tasks are skipped if none of the JS files or assets change; this means
68 | * // that we don't look at files in android/ or ios/ to determine whether the tasks are up to
69 | * // date; if you have any other folders that you want to ignore for performance reasons (gradle
70 | * // indexes the entire tree), add them here. Alternatively, if you have JS files in android/
71 | * // for example, you might want to remove it from here.
72 | * inputExcludes: ["android/**", "ios/**"],
73 | *
74 | * // override which node gets called and with what additional arguments
75 | * nodeExecutableAndArgs: ["node"],
76 | *
77 | * // supply additional arguments to the packager
78 | * extraPackagerArgs: []
79 | * ]
80 | */
81 |
82 | project.ext.react = [
83 | enableHermes: true, // clean and rebuild if changing
84 | ]
85 |
86 | apply from: "../../node_modules/react-native/react.gradle"
87 |
88 | /**
89 | * Set this to true to create two separate APKs instead of one:
90 | * - An APK that only works on ARM devices
91 | * - An APK that only works on x86 devices
92 | * The advantage is the size of the APK is reduced by about 4MB.
93 | * Upload all the APKs to the Play Store and people will download
94 | * the correct one based on the CPU architecture of their device.
95 | */
96 | def enableSeparateBuildPerCPUArchitecture = false
97 |
98 | /**
99 | * Run Proguard to shrink the Java bytecode in release builds.
100 | */
101 | def enableProguardInReleaseBuilds = false
102 |
103 | /**
104 | * The preferred build flavor of JavaScriptCore.
105 | *
106 | * For example, to use the international variant, you can use:
107 | * `def jscFlavor = 'org.webkit:android-jsc-intl:+'`
108 | *
109 | * The international variant includes ICU i18n library and necessary data
110 | * allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that
111 | * give correct results when using with locales other than en-US. Note that
112 | * this variant is about 6MiB larger per architecture than default.
113 | */
114 | def jscFlavor = 'org.webkit:android-jsc:+'
115 |
116 | /**
117 | * Whether to enable the Hermes VM.
118 | *
119 | * This should be set on project.ext.react and that value will be read here. If it is not set
120 | * on project.ext.react, JavaScript will not be compiled to Hermes Bytecode
121 | * and the benefits of using Hermes will therefore be sharply reduced.
122 | */
123 | def enableHermes = project.ext.react.get("enableHermes", false);
124 |
125 | /**
126 | * Architectures to build native code for.
127 | */
128 | def reactNativeArchitectures() {
129 | def value = project.getProperties().get("reactNativeArchitectures")
130 | return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"]
131 | }
132 |
133 | android {
134 | ndkVersion rootProject.ext.ndkVersion
135 |
136 | compileSdkVersion rootProject.ext.compileSdkVersion
137 |
138 | defaultConfig {
139 | applicationId "com.newarchitecture"
140 | minSdkVersion rootProject.ext.minSdkVersion
141 | targetSdkVersion rootProject.ext.targetSdkVersion
142 | versionCode 1
143 | versionName "1.0"
144 | buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
145 |
146 | if (isNewArchitectureEnabled()) {
147 | // We configure the NDK build only if you decide to opt-in for the New Architecture.
148 | externalNativeBuild {
149 | ndkBuild {
150 | arguments "APP_PLATFORM=android-21",
151 | "APP_STL=c++_shared",
152 | "NDK_TOOLCHAIN_VERSION=clang",
153 | "GENERATED_SRC_DIR=$buildDir/generated/source",
154 | "PROJECT_BUILD_DIR=$buildDir",
155 | "REACT_ANDROID_DIR=$rootDir/../node_modules/react-native/ReactAndroid",
156 | "REACT_ANDROID_BUILD_DIR=$rootDir/../node_modules/react-native/ReactAndroid/build",
157 | "NODE_MODULES_DIR=$rootDir/../node_modules/"
158 | cFlags "-Wall", "-Werror", "-fexceptions", "-frtti", "-DWITH_INSPECTOR=1"
159 | cppFlags "-std=c++17"
160 | // Make sure this target name is the same you specify inside the
161 | // src/main/jni/Android.mk file for the `LOCAL_MODULE` variable.
162 | targets "newarchitecture_appmodules"
163 |
164 | // Fix for windows limit on number of character in file paths and in command lines
165 | if (Os.isFamily(Os.FAMILY_WINDOWS)) {
166 | arguments "NDK_APP_SHORT_COMMANDS=true"
167 | }
168 | }
169 | }
170 | if (!enableSeparateBuildPerCPUArchitecture) {
171 | ndk {
172 | abiFilters (*reactNativeArchitectures())
173 | }
174 | }
175 | }
176 | }
177 |
178 | if (isNewArchitectureEnabled()) {
179 | // We configure the NDK build only if you decide to opt-in for the New Architecture.
180 | externalNativeBuild {
181 | ndkBuild {
182 | path "$projectDir/src/main/jni/Android.mk"
183 | }
184 | }
185 | def reactAndroidProjectDir = project(':ReactAndroid').projectDir
186 | def packageReactNdkDebugLibs = tasks.register("packageReactNdkDebugLibs", Copy) {
187 | dependsOn(":ReactAndroid:packageReactNdkDebugLibsForBuck")
188 | from("$reactAndroidProjectDir/src/main/jni/prebuilt/lib")
189 | into("$buildDir/react-ndk/exported")
190 | }
191 | def packageReactNdkReleaseLibs = tasks.register("packageReactNdkReleaseLibs", Copy) {
192 | dependsOn(":ReactAndroid:packageReactNdkReleaseLibsForBuck")
193 | from("$reactAndroidProjectDir/src/main/jni/prebuilt/lib")
194 | into("$buildDir/react-ndk/exported")
195 | }
196 | afterEvaluate {
197 | // If you wish to add a custom TurboModule or component locally,
198 | // you should uncomment this line.
199 | // preBuild.dependsOn("generateCodegenArtifactsFromSchema")
200 | preDebugBuild.dependsOn(packageReactNdkDebugLibs)
201 | preReleaseBuild.dependsOn(packageReactNdkReleaseLibs)
202 |
203 | // Due to a bug inside AGP, we have to explicitly set a dependency
204 | // between configureNdkBuild* tasks and the preBuild tasks.
205 | // This can be removed once this is solved: https://issuetracker.google.com/issues/207403732
206 | configureNdkBuildRelease.dependsOn(preReleaseBuild)
207 | configureNdkBuildDebug.dependsOn(preDebugBuild)
208 | reactNativeArchitectures().each { architecture ->
209 | tasks.findByName("configureNdkBuildDebug[${architecture}]")?.configure {
210 | dependsOn("preDebugBuild")
211 | }
212 | tasks.findByName("configureNdkBuildRelease[${architecture}]")?.configure {
213 | dependsOn("preReleaseBuild")
214 | }
215 | }
216 | }
217 | }
218 |
219 | splits {
220 | abi {
221 | reset()
222 | enable enableSeparateBuildPerCPUArchitecture
223 | universalApk false // If true, also generate a universal APK
224 | include (*reactNativeArchitectures())
225 | }
226 | }
227 | signingConfigs {
228 | debug {
229 | storeFile file('debug.keystore')
230 | storePassword 'android'
231 | keyAlias 'androiddebugkey'
232 | keyPassword 'android'
233 | }
234 | }
235 | buildTypes {
236 | debug {
237 | signingConfig signingConfigs.debug
238 | }
239 | release {
240 | // Caution! In production, you need to generate your own keystore file.
241 | // see https://reactnative.dev/docs/signed-apk-android.
242 | signingConfig signingConfigs.debug
243 | minifyEnabled enableProguardInReleaseBuilds
244 | proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
245 | }
246 | }
247 |
248 | // applicationVariants are e.g. debug, release
249 | applicationVariants.all { variant ->
250 | variant.outputs.each { output ->
251 | // For each separate APK per architecture, set a unique version code as described here:
252 | // https://developer.android.com/studio/build/configure-apk-splits.html
253 | // Example: versionCode 1 will generate 1001 for armeabi-v7a, 1002 for x86, etc.
254 | def versionCodes = ["armeabi-v7a": 1, "x86": 2, "arm64-v8a": 3, "x86_64": 4]
255 | def abi = output.getFilter(OutputFile.ABI)
256 | if (abi != null) { // null for the universal-debug, universal-release variants
257 | output.versionCodeOverride =
258 | defaultConfig.versionCode * 1000 + versionCodes.get(abi)
259 | }
260 |
261 | }
262 | }
263 | }
264 |
265 | dependencies {
266 | implementation fileTree(dir: "libs", include: ["*.jar"])
267 |
268 | //noinspection GradleDynamicVersion
269 | implementation "com.facebook.react:react-native:+" // From node_modules
270 |
271 | implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0"
272 |
273 | debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") {
274 | exclude group:'com.facebook.fbjni'
275 | }
276 |
277 | debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") {
278 | exclude group:'com.facebook.flipper'
279 | exclude group:'com.squareup.okhttp3', module:'okhttp'
280 | }
281 |
282 | debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}") {
283 | exclude group:'com.facebook.flipper'
284 | }
285 |
286 | if (enableHermes) {
287 | def hermesPath = "../../node_modules/hermes-engine/android/";
288 | debugImplementation files(hermesPath + "hermes-debug.aar")
289 | releaseImplementation files(hermesPath + "hermes-release.aar")
290 | } else {
291 | implementation jscFlavor
292 | }
293 | }
294 |
295 | if (isNewArchitectureEnabled()) {
296 | // If new architecture is enabled, we let you build RN from source
297 | // Otherwise we fallback to a prebuilt .aar bundled in the NPM package.
298 | // This will be applied to all the imported transtitive dependency.
299 | configurations.all {
300 | resolutionStrategy.dependencySubstitution {
301 | substitute(module("com.facebook.react:react-native"))
302 | .using(project(":ReactAndroid")).because("On New Architecture we're building React Native from source")
303 | }
304 | }
305 | }
306 |
307 | // Run this once to be able to run the application with BUCK
308 | // puts all compile dependencies into folder libs for BUCK to use
309 | task copyDownloadableDepsToLibs(type: Copy) {
310 | from configurations.implementation
311 | into 'libs'
312 | }
313 |
314 | apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)
315 |
316 | def isNewArchitectureEnabled() {
317 | // To opt-in for the New Architecture, you can either:
318 | // - Set `newArchEnabled` to true inside the `gradle.properties` file
319 | // - Invoke gradle with `-newArchEnabled=true`
320 | // - Set an environment variable `ORG_GRADLE_PROJECT_newArchEnabled=true`
321 | return project.hasProperty("newArchEnabled") && project.newArchEnabled == "true"
322 | }
323 |
--------------------------------------------------------------------------------
/example/android/app/build_defs.bzl:
--------------------------------------------------------------------------------
1 | """Helper definitions to glob .aar and .jar targets"""
2 |
3 | def create_aar_targets(aarfiles):
4 | for aarfile in aarfiles:
5 | name = "aars__" + aarfile[aarfile.rindex("/") + 1:aarfile.rindex(".aar")]
6 | lib_deps.append(":" + name)
7 | android_prebuilt_aar(
8 | name = name,
9 | aar = aarfile,
10 | )
11 |
12 | def create_jar_targets(jarfiles):
13 | for jarfile in jarfiles:
14 | name = "jars__" + jarfile[jarfile.rindex("/") + 1:jarfile.rindex(".jar")]
15 | lib_deps.append(":" + name)
16 | prebuilt_jar(
17 | name = name,
18 | binary_jar = jarfile,
19 | )
20 |
--------------------------------------------------------------------------------
/example/android/app/debug.keystore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hannojg/react-native-rlottie/db08d2b8e9ac6459e0f11b4d9acb705b1cfbb775/example/android/app/debug.keystore
--------------------------------------------------------------------------------
/example/android/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
--------------------------------------------------------------------------------
/example/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/example/android/app/src/debug/java/com/newarchitecture/ReactNativeFlipper.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) Meta Platforms, Inc. and affiliates.
3 | *
4 | *
This source code is licensed under the MIT license found in the LICENSE file in the root
5 | * directory of this source tree.
6 | */
7 | package com.newarchitecture;
8 |
9 | import android.content.Context;
10 | import com.facebook.flipper.android.AndroidFlipperClient;
11 | import com.facebook.flipper.android.utils.FlipperUtils;
12 | import com.facebook.flipper.core.FlipperClient;
13 | import com.facebook.flipper.plugins.crashreporter.CrashReporterPlugin;
14 | import com.facebook.flipper.plugins.databases.DatabasesFlipperPlugin;
15 | import com.facebook.flipper.plugins.fresco.FrescoFlipperPlugin;
16 | import com.facebook.flipper.plugins.inspector.DescriptorMapping;
17 | import com.facebook.flipper.plugins.inspector.InspectorFlipperPlugin;
18 | import com.facebook.flipper.plugins.network.FlipperOkhttpInterceptor;
19 | import com.facebook.flipper.plugins.network.NetworkFlipperPlugin;
20 | import com.facebook.flipper.plugins.react.ReactFlipperPlugin;
21 | import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPlugin;
22 | import com.facebook.react.ReactInstanceEventListener;
23 | import com.facebook.react.ReactInstanceManager;
24 | import com.facebook.react.bridge.ReactContext;
25 | import com.facebook.react.modules.network.NetworkingModule;
26 | import okhttp3.OkHttpClient;
27 |
28 | public class ReactNativeFlipper {
29 | public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) {
30 | if (FlipperUtils.shouldEnableFlipper(context)) {
31 | final FlipperClient client = AndroidFlipperClient.getInstance(context);
32 |
33 | client.addPlugin(new InspectorFlipperPlugin(context, DescriptorMapping.withDefaults()));
34 | client.addPlugin(new ReactFlipperPlugin());
35 | client.addPlugin(new DatabasesFlipperPlugin(context));
36 | client.addPlugin(new SharedPreferencesFlipperPlugin(context));
37 | client.addPlugin(CrashReporterPlugin.getInstance());
38 |
39 | NetworkFlipperPlugin networkFlipperPlugin = new NetworkFlipperPlugin();
40 | NetworkingModule.setCustomClientBuilder(
41 | new NetworkingModule.CustomClientBuilder() {
42 | @Override
43 | public void apply(OkHttpClient.Builder builder) {
44 | builder.addNetworkInterceptor(new FlipperOkhttpInterceptor(networkFlipperPlugin));
45 | }
46 | });
47 | client.addPlugin(networkFlipperPlugin);
48 | client.start();
49 |
50 | // Fresco Plugin needs to ensure that ImagePipelineFactory is initialized
51 | // Hence we run if after all native modules have been initialized
52 | ReactContext reactContext = reactInstanceManager.getCurrentReactContext();
53 | if (reactContext == null) {
54 | reactInstanceManager.addReactInstanceEventListener(
55 | new ReactInstanceEventListener() {
56 | @Override
57 | public void onReactContextInitialized(ReactContext reactContext) {
58 | reactInstanceManager.removeReactInstanceEventListener(this);
59 | reactContext.runOnNativeModulesQueueThread(
60 | new Runnable() {
61 | @Override
62 | public void run() {
63 | client.addPlugin(new FrescoFlipperPlugin());
64 | }
65 | });
66 | }
67 | });
68 | } else {
69 | client.addPlugin(new FrescoFlipperPlugin());
70 | }
71 | }
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/example/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
13 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/example/android/app/src/main/java/com/newarchitecture/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.newarchitecture;
2 |
3 | import com.facebook.react.ReactActivity;
4 | import com.facebook.react.ReactActivityDelegate;
5 | import com.facebook.react.ReactRootView;
6 |
7 | public class MainActivity extends ReactActivity {
8 |
9 | /**
10 | * Returns the name of the main component registered from JavaScript. This is used to schedule
11 | * rendering of the component.
12 | */
13 | @Override
14 | protected String getMainComponentName() {
15 | return "NewArchitecture";
16 | }
17 |
18 | /**
19 | * Returns the instance of the {@link ReactActivityDelegate}. There the RootView is created and
20 | * you can specify the rendered you wish to use (Fabric or the older renderer).
21 | */
22 | @Override
23 | protected ReactActivityDelegate createReactActivityDelegate() {
24 | return new MainActivityDelegate(this, getMainComponentName());
25 | }
26 |
27 | public static class MainActivityDelegate extends ReactActivityDelegate {
28 | public MainActivityDelegate(ReactActivity activity, String mainComponentName) {
29 | super(activity, mainComponentName);
30 | }
31 |
32 | @Override
33 | protected ReactRootView createRootView() {
34 | ReactRootView reactRootView = new ReactRootView(getContext());
35 | // If you opted-in for the New Architecture, we enable the Fabric Renderer.
36 | reactRootView.setIsFabric(BuildConfig.IS_NEW_ARCHITECTURE_ENABLED);
37 | return reactRootView;
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/example/android/app/src/main/java/com/newarchitecture/MainApplication.java:
--------------------------------------------------------------------------------
1 | package com.newarchitecture;
2 |
3 | import android.app.Application;
4 | import android.content.Context;
5 | import com.facebook.react.PackageList;
6 | import com.facebook.react.ReactApplication;
7 | import com.facebook.react.ReactInstanceManager;
8 | import com.facebook.react.ReactNativeHost;
9 | import com.facebook.react.ReactPackage;
10 | import com.facebook.react.config.ReactFeatureFlags;
11 | import com.facebook.soloader.SoLoader;
12 | import com.newarchitecture.newarchitecture.MainApplicationReactNativeHost;
13 | import java.lang.reflect.InvocationTargetException;
14 | import java.util.List;
15 |
16 | public class MainApplication extends Application implements ReactApplication {
17 |
18 | private final ReactNativeHost mReactNativeHost =
19 | new ReactNativeHost(this) {
20 | @Override
21 | public boolean getUseDeveloperSupport() {
22 | return BuildConfig.DEBUG;
23 | }
24 |
25 | @Override
26 | protected List getPackages() {
27 | @SuppressWarnings("UnnecessaryLocalVariable")
28 | List packages = new PackageList(this).getPackages();
29 | // Packages that cannot be autolinked yet can be added manually here, for example:
30 | // packages.add(new MyReactNativePackage());
31 | return packages;
32 | }
33 |
34 | @Override
35 | protected String getJSMainModuleName() {
36 | return "index";
37 | }
38 | };
39 |
40 | private final ReactNativeHost mNewArchitectureNativeHost =
41 | new MainApplicationReactNativeHost(this);
42 |
43 | @Override
44 | public ReactNativeHost getReactNativeHost() {
45 | if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
46 | return mNewArchitectureNativeHost;
47 | } else {
48 | return mReactNativeHost;
49 | }
50 | }
51 |
52 | @Override
53 | public void onCreate() {
54 | super.onCreate();
55 | // If you opted-in for the New Architecture, we enable the TurboModule system
56 | ReactFeatureFlags.useTurboModules = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;
57 | SoLoader.init(this, /* native exopackage */ false);
58 | initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
59 | }
60 |
61 | /**
62 | * Loads Flipper in React Native templates. Call this in the onCreate method with something like
63 | * initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
64 | *
65 | * @param context
66 | * @param reactInstanceManager
67 | */
68 | private static void initializeFlipper(
69 | Context context, ReactInstanceManager reactInstanceManager) {
70 | if (BuildConfig.DEBUG) {
71 | try {
72 | /*
73 | We use reflection here to pick up the class that initializes Flipper,
74 | since Flipper library is not available in release mode
75 | */
76 | Class> aClass = Class.forName("com.newarchitecture.ReactNativeFlipper");
77 | aClass
78 | .getMethod("initializeFlipper", Context.class, ReactInstanceManager.class)
79 | .invoke(null, context, reactInstanceManager);
80 | } catch (ClassNotFoundException e) {
81 | e.printStackTrace();
82 | } catch (NoSuchMethodException e) {
83 | e.printStackTrace();
84 | } catch (IllegalAccessException e) {
85 | e.printStackTrace();
86 | } catch (InvocationTargetException e) {
87 | e.printStackTrace();
88 | }
89 | }
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/example/android/app/src/main/java/com/newarchitecture/newarchitecture/MainApplicationReactNativeHost.java:
--------------------------------------------------------------------------------
1 | package com.newarchitecture.newarchitecture;
2 |
3 | import android.app.Application;
4 | import androidx.annotation.NonNull;
5 | import com.facebook.react.PackageList;
6 | import com.facebook.react.ReactInstanceManager;
7 | import com.facebook.react.ReactNativeHost;
8 | import com.facebook.react.ReactPackage;
9 | import com.facebook.react.ReactPackageTurboModuleManagerDelegate;
10 | import com.facebook.react.bridge.JSIModulePackage;
11 | import com.facebook.react.bridge.JSIModuleProvider;
12 | import com.facebook.react.bridge.JSIModuleSpec;
13 | import com.facebook.react.bridge.JSIModuleType;
14 | import com.facebook.react.bridge.JavaScriptContextHolder;
15 | import com.facebook.react.bridge.ReactApplicationContext;
16 | import com.facebook.react.bridge.UIManager;
17 | import com.facebook.react.fabric.ComponentFactory;
18 | import com.facebook.react.fabric.CoreComponentsRegistry;
19 | import com.facebook.react.fabric.EmptyReactNativeConfig;
20 | import com.facebook.react.fabric.FabricJSIModuleProvider;
21 | import com.facebook.react.uimanager.ViewManagerRegistry;
22 | import com.newarchitecture.BuildConfig;
23 | import com.newarchitecture.newarchitecture.components.MainComponentsRegistry;
24 | import com.newarchitecture.newarchitecture.modules.MainApplicationTurboModuleManagerDelegate;
25 | import java.util.ArrayList;
26 | import java.util.List;
27 |
28 | /**
29 | * A {@link ReactNativeHost} that helps you load everything needed for the New Architecture, both
30 | * TurboModule delegates and the Fabric Renderer.
31 | *
32 | *
Please note that this class is used ONLY if you opt-in for the New Architecture (see the
33 | * `newArchEnabled` property). Is ignored otherwise.
34 | */
35 | public class MainApplicationReactNativeHost extends ReactNativeHost {
36 | public MainApplicationReactNativeHost(Application application) {
37 | super(application);
38 | }
39 |
40 | @Override
41 | public boolean getUseDeveloperSupport() {
42 | return BuildConfig.DEBUG;
43 | }
44 |
45 | @Override
46 | protected List getPackages() {
47 | List packages = new PackageList(this).getPackages();
48 | // Packages that cannot be autolinked yet can be added manually here, for example:
49 | // packages.add(new MyReactNativePackage());
50 | // TurboModules must also be loaded here providing a valid TurboReactPackage implementation:
51 | // packages.add(new TurboReactPackage() { ... });
52 | // If you have custom Fabric Components, their ViewManagers should also be loaded here
53 | // inside a ReactPackage.
54 | return packages;
55 | }
56 |
57 | @Override
58 | protected String getJSMainModuleName() {
59 | return "index";
60 | }
61 |
62 | @NonNull
63 | @Override
64 | protected ReactPackageTurboModuleManagerDelegate.Builder
65 | getReactPackageTurboModuleManagerDelegateBuilder() {
66 | // Here we provide the ReactPackageTurboModuleManagerDelegate Builder. This is necessary
67 | // for the new architecture and to use TurboModules correctly.
68 | return new MainApplicationTurboModuleManagerDelegate.Builder();
69 | }
70 |
71 | @Override
72 | protected JSIModulePackage getJSIModulePackage() {
73 | return new JSIModulePackage() {
74 | @Override
75 | public List getJSIModules(
76 | final ReactApplicationContext reactApplicationContext,
77 | final JavaScriptContextHolder jsContext) {
78 | final List specs = new ArrayList<>();
79 |
80 | // Here we provide a new JSIModuleSpec that will be responsible of providing the
81 | // custom Fabric Components.
82 | specs.add(
83 | new JSIModuleSpec() {
84 | @Override
85 | public JSIModuleType getJSIModuleType() {
86 | return JSIModuleType.UIManager;
87 | }
88 |
89 | @Override
90 | public JSIModuleProvider getJSIModuleProvider() {
91 | final ComponentFactory componentFactory = new ComponentFactory();
92 | CoreComponentsRegistry.register(componentFactory);
93 |
94 | // Here we register a Components Registry.
95 | // The one that is generated with the template contains no components
96 | // and just provides you the one from React Native core.
97 | MainComponentsRegistry.register(componentFactory);
98 |
99 | final ReactInstanceManager reactInstanceManager = getReactInstanceManager();
100 |
101 | ViewManagerRegistry viewManagerRegistry =
102 | new ViewManagerRegistry(
103 | reactInstanceManager.getOrCreateViewManagers(reactApplicationContext));
104 |
105 | return new FabricJSIModuleProvider(
106 | reactApplicationContext,
107 | componentFactory,
108 | new EmptyReactNativeConfig(),
109 | viewManagerRegistry);
110 | }
111 | });
112 | return specs;
113 | }
114 | };
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/example/android/app/src/main/java/com/newarchitecture/newarchitecture/components/MainComponentsRegistry.java:
--------------------------------------------------------------------------------
1 | package com.newarchitecture.newarchitecture.components;
2 |
3 | import com.facebook.jni.HybridData;
4 | import com.facebook.proguard.annotations.DoNotStrip;
5 | import com.facebook.react.fabric.ComponentFactory;
6 | import com.facebook.soloader.SoLoader;
7 |
8 | /**
9 | * Class responsible to load the custom Fabric Components. This class has native methods and needs a
10 | * corresponding C++ implementation/header file to work correctly (already placed inside the jni/
11 | * folder for you).
12 | *
13 | *
Please note that this class is used ONLY if you opt-in for the New Architecture (see the
14 | * `newArchEnabled` property). Is ignored otherwise.
15 | */
16 | @DoNotStrip
17 | public class MainComponentsRegistry {
18 | static {
19 | SoLoader.loadLibrary("fabricjni");
20 | }
21 |
22 | @DoNotStrip private final HybridData mHybridData;
23 |
24 | @DoNotStrip
25 | private native HybridData initHybrid(ComponentFactory componentFactory);
26 |
27 | @DoNotStrip
28 | private MainComponentsRegistry(ComponentFactory componentFactory) {
29 | mHybridData = initHybrid(componentFactory);
30 | }
31 |
32 | @DoNotStrip
33 | public static MainComponentsRegistry register(ComponentFactory componentFactory) {
34 | return new MainComponentsRegistry(componentFactory);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/example/android/app/src/main/java/com/newarchitecture/newarchitecture/modules/MainApplicationTurboModuleManagerDelegate.java:
--------------------------------------------------------------------------------
1 | package com.newarchitecture.newarchitecture.modules;
2 |
3 | import com.facebook.jni.HybridData;
4 | import com.facebook.react.ReactPackage;
5 | import com.facebook.react.ReactPackageTurboModuleManagerDelegate;
6 | import com.facebook.react.bridge.ReactApplicationContext;
7 | import com.facebook.soloader.SoLoader;
8 | import java.util.List;
9 |
10 | /**
11 | * Class responsible to load the TurboModules. This class has native methods and needs a
12 | * corresponding C++ implementation/header file to work correctly (already placed inside the jni/
13 | * folder for you).
14 | *
15 | *