17 |
18 | # Version 1 🚀
19 |
20 | Finally we're published the `version 1` for the bounceable library
21 | - Much better animation with `pressIn` and `pressOut` bounces 😍
22 | - More than 90k downloads and battle tested 💪
23 |
24 | # Installation
25 |
26 | Add the dependency:
27 |
28 | ```bash
29 | npm i @freakycoder/react-native-bounceable
30 | ```
31 |
32 | # Usage
33 |
34 | ## Import
35 |
36 | ```jsx
37 | import RNBounceable from "@freakycoder/react-native-bounceable";
38 | ```
39 |
40 | ## Fundamental Usage
41 |
42 | You can put **ANY children component** inside the **RNBounceable** component, it will make it bounce when it is pressed
43 |
44 | ```jsx
45 | {}}>
46 |
47 | Bounce
48 |
49 |
50 | ```
51 |
52 | # Configuration - Props
53 |
54 | | Property | Type | Default | Description |
55 | | --------------- | :------: | :-------: | ------------------------------------------------ |
56 | | onPress | function | undefined | set your own logic for the onPress functionality |
57 | | style | style | undefined | set the style like any other View container |
58 | | bounceEffect | number | 0.9 | change the bounce effect's value |
59 | | bounceFriction | number | 3 | change the bounce effect's friction value |
60 | | useNativeDriver | boolean | true | change the useNativeDriver's usage |
61 | | animate | function | default | activate the bounce effect animation |
62 |
63 | ## Future Plans
64 |
65 | - [x] ~~LICENSE~~
66 | - [x] ~~More customizable animation props~~
67 | - [ ] Write an article about the lib on Medium
68 |
69 | ## Author
70 |
71 | FreakyCoder, kurayogun@gmail.com
72 |
73 | ## License
74 |
75 | React Native Bounceable is available under the MIT license. See the LICENSE file for more info.
76 |
--------------------------------------------------------------------------------
/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WrathChaos/react-native-bounceable/e0b586dd61749ade17df5357f2f4d72a00e0ffb4/assets/logo.png
--------------------------------------------------------------------------------
/assets/react-native-bounceable.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WrathChaos/react-native-bounceable/e0b586dd61749ade17df5357f2f4d72a00e0ffb4/assets/react-native-bounceable.gif
--------------------------------------------------------------------------------
/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: [
4 | "eslint:recommended",
5 | "plugin:react/recommended",
6 | "plugin:@typescript-eslint/recommended",
7 | "@react-native-community",
8 | "prettier",
9 | ],
10 | ignorePatterns: [
11 | "**/*/*.js",
12 | "*.js",
13 | "*.svg",
14 | "*.json",
15 | "*.png",
16 | "package.json",
17 | "package-lock.json",
18 | ],
19 | parser: "@typescript-eslint/parser",
20 | plugins: [
21 | "import",
22 | "react",
23 | "react-native",
24 | "prettier",
25 | "react-hooks",
26 | "@typescript-eslint",
27 | "promise",
28 | "jest",
29 | "unused-imports",
30 | ],
31 | env: {
32 | browser: true,
33 | es2021: true,
34 | "jest/globals": true,
35 | "react-native/react-native": true,
36 | },
37 | settings: {
38 | "import/resolver": {
39 | node: {
40 | extensions: [
41 | ".js",
42 | ".jsx",
43 | ".ts",
44 | ".tsx",
45 | ".d.ts",
46 | ".android.js",
47 | ".android.jsx",
48 | ".android.ts",
49 | ".android.tsx",
50 | ".ios.js",
51 | ".ios.jsx",
52 | ".ios.ts",
53 | ".ios.tsx",
54 | ".web.js",
55 | ".web.jsx",
56 | ".web.ts",
57 | ".web.tsx",
58 | ],
59 | },
60 | },
61 | },
62 | rules: {
63 | quotes: [
64 | "error",
65 | "double",
66 | {
67 | avoidEscape: true,
68 | },
69 | ],
70 | "import/extensions": [
71 | "error",
72 | "never",
73 | {
74 | svg: "always",
75 | model: "always",
76 | style: "always",
77 | png: "always",
78 | jpg: "always",
79 | json: "always",
80 | constant: "always",
81 | },
82 | ],
83 | "no-useless-catch": 0,
84 | "react-hooks/exhaustive-deps": 0,
85 | "max-len": ["error", 120],
86 | "@typescript-eslint/ban-ts-comment": 1,
87 | "@typescript-eslint/no-empty-function": 0,
88 | "@typescript-eslint/no-explicit-any": 1,
89 | "@typescript-eslint/explicit-module-boundary-types": 0,
90 | "react/jsx-filename-extension": ["error", { extensions: [".tsx"] }],
91 | "react-native/no-unused-styles": 2,
92 | "react-native/split-platform-components": 2,
93 | "react-native/no-inline-styles": 0,
94 | "react-native/no-color-literals": 0,
95 | "react-native/no-raw-text": 0,
96 | "import/no-extraneous-dependencies": 2,
97 | "import/no-named-as-default-member": 2,
98 | "import/order": 0,
99 | "import/no-duplicates": 2,
100 | "import/no-useless-path-segments": 2,
101 | "import/no-cycle": 2,
102 | "import/prefer-default-export": 0,
103 | "import/no-anonymous-default-export": 0,
104 | "import/named": 0,
105 | "@typescript-eslint/no-empty-interface": 0,
106 | "import/namespace": 0,
107 | "import/default": 0,
108 | "import/no-named-as-default": 0,
109 | "import/no-unused-modules": 0,
110 | "import/no-deprecated": 0,
111 | "@typescript-eslint/indent": 0,
112 | "react-hooks/rules-of-hooks": 2,
113 | camelcase: 2,
114 | "prefer-destructuring": 2,
115 | "no-nested-ternary": 2,
116 | "prettier/prettier": [
117 | "error",
118 | {
119 | endOfLine: "auto",
120 | },
121 | ],
122 | },
123 | };
124 |
--------------------------------------------------------------------------------
/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 |
32 | # Visual Studio Code
33 | #
34 | .vscode/
35 |
36 | # node.js
37 | #
38 | node_modules/
39 | npm-debug.log
40 | yarn-error.log
41 |
42 | # BUCK
43 | buck-out/
44 | \.buckd/
45 | *.keystore
46 | !debug.keystore
47 |
48 | # fastlane
49 | #
50 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
51 | # screenshots whenever they are needed.
52 | # For more information about the recommended setup visit:
53 | # https://docs.fastlane.tools/best-practices/source-control/
54 |
55 | */fastlane/report.xml
56 | */fastlane/Preview.html
57 | */fastlane/screenshots
58 |
59 | # Bundle artifact
60 | *.jsbundle
61 |
62 | # CocoaPods
63 | /ios/Pods/
64 |
--------------------------------------------------------------------------------
/example/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "bracketSpacing": true,
3 | "jsxBracketSameLine": false,
4 | "singleQuote": false,
5 | "trailingComma": "all",
6 | "tabWidth": 2,
7 | "semi": true
8 | }
9 |
--------------------------------------------------------------------------------
/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.5
2 |
--------------------------------------------------------------------------------
/example/.watchmanconfig:
--------------------------------------------------------------------------------
1 | {}
--------------------------------------------------------------------------------
/example/App.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import {
3 | View,
4 | ScrollView,
5 | StatusBar,
6 | Text,
7 | SafeAreaView,
8 | Alert,
9 | } from "react-native";
10 | import ProfileHeader from "react-native-profile-header";
11 | import IGStoryCircle from "react-native-instagram-story-circle";
12 | import { AppleCard, AppOfTheDayCard } from "react-native-apple-card-views";
13 | import RNBounceable from "./lib/RNBounceable";
14 |
15 | const coloredNotification = require("./assets/notification-colored.png");
16 | const notification = require("./assets/notification.png");
17 |
18 | const stories = [
19 | {
20 | key: "Lorem Sit",
21 | hasStory: true,
22 | storyRingColor: ["#20fab1", "#20fab1"],
23 | notificationCount: 3,
24 | source: {
25 | uri: "https://images.unsplash.com/uploads/14110635637836178f553/dcc2ccd9?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1350&q=80",
26 | },
27 | },
28 | {
29 | key: "Parturient Aenean Fringilla",
30 | hasStory: true,
31 | storyRingColor: ["#eb3434", "#eb3434"],
32 | isStoryRead: true,
33 | source: {
34 | uri: "https://images.unsplash.com/photo-1496440737103-cd596325d314?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=634&q=80",
35 | },
36 | },
37 | {
38 | key: "Parturient",
39 | hasStory: true,
40 | storyRingColor: ["#e22ae8", "#e22ae8"],
41 | source: {
42 | uri: "https://images.unsplash.com/photo-1514846226882-28b324ef7f28?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=634&q=80",
43 | },
44 | },
45 | {
46 | key: "Adipiscing",
47 | hasStory: true,
48 | storyRingColor: ["#3492eb", "#3492eb"],
49 | notificationCount: 16,
50 | source: {
51 | uri: "https://images.unsplash.com/photo-1469334031218-e382a71b716b?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1350&q=80",
52 | },
53 | },
54 | {
55 | key: "Mollis",
56 | hasStory: true,
57 | notificationCount: 1,
58 | source: {
59 | uri: "https://images.unsplash.com/photo-1448376561459-dbe8868fa34c?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1350&q=80",
60 | },
61 | },
62 | {
63 | key: "Dapibus Euismod",
64 | hasStory: true,
65 | source: {
66 | uri: "https://images.unsplash.com/photo-1539811107033-3a67f3ebc852?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=564&q=80",
67 | },
68 | },
69 | {
70 | key: "Pellentesque",
71 | hasStory: true,
72 | source: {
73 | uri: "https://images.unsplash.com/photo-1551292831-023188e78222?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1350&q=80",
74 | },
75 | },
76 | ];
77 |
78 | const App = () => {
79 | const [notificationIcon, setNotificationIcon] = React.useState(notification);
80 |
81 | const renderHeader = () => (
82 | {
86 | if (notificationIcon === notification)
87 | setNotificationIcon(coloredNotification);
88 | else setNotificationIcon(notification);
89 | }}
90 | />
91 | );
92 |
93 | const renderIGStories = () => (
94 |
104 | {stories.map((item) => {
105 | return (
106 |
107 | {}}
113 | />
114 |
115 | );
116 | })}
117 |
118 | );
119 |
120 | const renderAppleCards = () => (
121 |
128 |
129 | {}}
133 | resizeMode="cover"
134 | />
135 |
136 | {}}
140 | buttonOnPress={() => {}}
141 | />
142 |
143 | );
144 |
145 | return (
146 | <>
147 |
148 |
149 | {renderHeader()}
150 | {renderIGStories()}
151 | {renderAppleCards()}
152 |
153 | >
154 | );
155 | };
156 |
157 | export default App;
158 |
--------------------------------------------------------------------------------
/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.5'
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.example",
39 | )
40 |
41 | android_resource(
42 | name = "res",
43 | package = "com.example",
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 |
3 | import com.android.build.OutputFile
4 |
5 | /**
6 | * The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets
7 | * and bundleReleaseJsAndAssets).
8 | * These basically call `react-native bundle` with the correct arguments during the Android build
9 | * cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the
10 | * bundle directly from the development server. Below you can see all the possible configurations
11 | * and their defaults. If you decide to add a configuration block, make sure to add it before the
12 | * `apply from: "../../node_modules/react-native/react.gradle"` line.
13 | *
14 | * project.ext.react = [
15 | * // the name of the generated asset file containing your JS bundle
16 | * bundleAssetName: "index.android.bundle",
17 | *
18 | * // the entry file for bundle generation. If none specified and
19 | * // "index.android.js" exists, it will be used. Otherwise "index.js" is
20 | * // default. Can be overridden with ENTRY_FILE environment variable.
21 | * entryFile: "index.android.js",
22 | *
23 | * // https://reactnative.dev/docs/performance#enable-the-ram-format
24 | * bundleCommand: "ram-bundle",
25 | *
26 | * // whether to bundle JS and assets in debug mode
27 | * bundleInDebug: false,
28 | *
29 | * // whether to bundle JS and assets in release mode
30 | * bundleInRelease: true,
31 | *
32 | * // whether to bundle JS and assets in another build variant (if configured).
33 | * // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants
34 | * // The configuration property can be in the following formats
35 | * // 'bundleIn${productFlavor}${buildType}'
36 | * // 'bundleIn${buildType}'
37 | * // bundleInFreeDebug: true,
38 | * // bundleInPaidRelease: true,
39 | * // bundleInBeta: true,
40 | *
41 | * // whether to disable dev mode in custom build variants (by default only disabled in release)
42 | * // for example: to disable dev mode in the staging build type (if configured)
43 | * devDisabledInStaging: true,
44 | * // The configuration property can be in the following formats
45 | * // 'devDisabledIn${productFlavor}${buildType}'
46 | * // 'devDisabledIn${buildType}'
47 | *
48 | * // the root of your project, i.e. where "package.json" lives
49 | * root: "../../",
50 | *
51 | * // where to put the JS bundle asset in debug mode
52 | * jsBundleDirDebug: "$buildDir/intermediates/assets/debug",
53 | *
54 | * // where to put the JS bundle asset in release mode
55 | * jsBundleDirRelease: "$buildDir/intermediates/assets/release",
56 | *
57 | * // where to put drawable resources / React Native assets, e.g. the ones you use via
58 | * // require('./image.png')), in debug mode
59 | * resourcesDirDebug: "$buildDir/intermediates/res/merged/debug",
60 | *
61 | * // where to put drawable resources / React Native assets, e.g. the ones you use via
62 | * // require('./image.png')), in release mode
63 | * resourcesDirRelease: "$buildDir/intermediates/res/merged/release",
64 | *
65 | * // by default the gradle tasks are skipped if none of the JS files or assets change; this means
66 | * // that we don't look at files in android/ or ios/ to determine whether the tasks are up to
67 | * // date; if you have any other folders that you want to ignore for performance reasons (gradle
68 | * // indexes the entire tree), add them here. Alternatively, if you have JS files in android/
69 | * // for example, you might want to remove it from here.
70 | * inputExcludes: ["android/**", "ios/**"],
71 | *
72 | * // override which node gets called and with what additional arguments
73 | * nodeExecutableAndArgs: ["node"],
74 | *
75 | * // supply additional arguments to the packager
76 | * extraPackagerArgs: []
77 | * ]
78 | */
79 |
80 | project.ext.react = [
81 | enableHermes: false, // clean and rebuild if changing
82 | ]
83 |
84 | apply from: "../../node_modules/react-native/react.gradle"
85 |
86 | /**
87 | * Set this to true to create two separate APKs instead of one:
88 | * - An APK that only works on ARM devices
89 | * - An APK that only works on x86 devices
90 | * The advantage is the size of the APK is reduced by about 4MB.
91 | * Upload all the APKs to the Play Store and people will download
92 | * the correct one based on the CPU architecture of their device.
93 | */
94 | def enableSeparateBuildPerCPUArchitecture = false
95 |
96 | /**
97 | * Run Proguard to shrink the Java bytecode in release builds.
98 | */
99 | def enableProguardInReleaseBuilds = false
100 |
101 | /**
102 | * The preferred build flavor of JavaScriptCore.
103 | *
104 | * For example, to use the international variant, you can use:
105 | * `def jscFlavor = 'org.webkit:android-jsc-intl:+'`
106 | *
107 | * The international variant includes ICU i18n library and necessary data
108 | * allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that
109 | * give correct results when using with locales other than en-US. Note that
110 | * this variant is about 6MiB larger per architecture than default.
111 | */
112 | def jscFlavor = 'org.webkit:android-jsc:+'
113 |
114 | /**
115 | * Whether to enable the Hermes VM.
116 | *
117 | * This should be set on project.ext.react and that value will be read here. If it is not set
118 | * on project.ext.react, JavaScript will not be compiled to Hermes Bytecode
119 | * and the benefits of using Hermes will therefore be sharply reduced.
120 | */
121 | def enableHermes = project.ext.react.get("enableHermes", false);
122 |
123 | /**
124 | * Architectures to build native code for.
125 | */
126 | def reactNativeArchitectures() {
127 | def value = project.getProperties().get("reactNativeArchitectures")
128 | return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"]
129 | }
130 |
131 | android {
132 | ndkVersion rootProject.ext.ndkVersion
133 |
134 | compileSdkVersion rootProject.ext.compileSdkVersion
135 |
136 | defaultConfig {
137 | applicationId "com.example"
138 | minSdkVersion rootProject.ext.minSdkVersion
139 | targetSdkVersion rootProject.ext.targetSdkVersion
140 | versionCode 1
141 | versionName "1.0"
142 | buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
143 |
144 | if (isNewArchitectureEnabled()) {
145 | // We configure the NDK build only if you decide to opt-in for the New Architecture.
146 | externalNativeBuild {
147 | ndkBuild {
148 | arguments "APP_PLATFORM=android-21",
149 | "APP_STL=c++_shared",
150 | "NDK_TOOLCHAIN_VERSION=clang",
151 | "GENERATED_SRC_DIR=$buildDir/generated/source",
152 | "PROJECT_BUILD_DIR=$buildDir",
153 | "REACT_ANDROID_DIR=$rootDir/../node_modules/react-native/ReactAndroid",
154 | "REACT_ANDROID_BUILD_DIR=$rootDir/../node_modules/react-native/ReactAndroid/build",
155 | "NODE_MODULES_DIR=$rootDir/../node_modules"
156 | cFlags "-Wall", "-Werror", "-fexceptions", "-frtti", "-DWITH_INSPECTOR=1"
157 | cppFlags "-std=c++17"
158 | // Make sure this target name is the same you specify inside the
159 | // src/main/jni/Android.mk file for the `LOCAL_MODULE` variable.
160 | targets "example_appmodules"
161 | }
162 | }
163 | if (!enableSeparateBuildPerCPUArchitecture) {
164 | ndk {
165 | abiFilters (*reactNativeArchitectures())
166 | }
167 | }
168 | }
169 | }
170 |
171 | if (isNewArchitectureEnabled()) {
172 | // We configure the NDK build only if you decide to opt-in for the New Architecture.
173 | externalNativeBuild {
174 | ndkBuild {
175 | path "$projectDir/src/main/jni/Android.mk"
176 | }
177 | }
178 | def reactAndroidProjectDir = project(':ReactAndroid').projectDir
179 | def packageReactNdkDebugLibs = tasks.register("packageReactNdkDebugLibs", Copy) {
180 | dependsOn(":ReactAndroid:packageReactNdkDebugLibsForBuck")
181 | from("$reactAndroidProjectDir/src/main/jni/prebuilt/lib")
182 | into("$buildDir/react-ndk/exported")
183 | }
184 | def packageReactNdkReleaseLibs = tasks.register("packageReactNdkReleaseLibs", Copy) {
185 | dependsOn(":ReactAndroid:packageReactNdkReleaseLibsForBuck")
186 | from("$reactAndroidProjectDir/src/main/jni/prebuilt/lib")
187 | into("$buildDir/react-ndk/exported")
188 | }
189 | afterEvaluate {
190 | // If you wish to add a custom TurboModule or component locally,
191 | // you should uncomment this line.
192 | // preBuild.dependsOn("generateCodegenArtifactsFromSchema")
193 | preDebugBuild.dependsOn(packageReactNdkDebugLibs)
194 | preReleaseBuild.dependsOn(packageReactNdkReleaseLibs)
195 |
196 | // Due to a bug inside AGP, we have to explicitly set a dependency
197 | // between configureNdkBuild* tasks and the preBuild tasks.
198 | // This can be removed once this is solved: https://issuetracker.google.com/issues/207403732
199 | configureNdkBuildRelease.dependsOn(preReleaseBuild)
200 | configureNdkBuildDebug.dependsOn(preDebugBuild)
201 | reactNativeArchitectures().each { architecture ->
202 | tasks.findByName("configureNdkBuildDebug[${architecture}]")?.configure {
203 | dependsOn("preDebugBuild")
204 | }
205 | tasks.findByName("configureNdkBuildRelease[${architecture}]")?.configure {
206 | dependsOn("preReleaseBuild")
207 | }
208 | }
209 | }
210 | }
211 |
212 | splits {
213 | abi {
214 | reset()
215 | enable enableSeparateBuildPerCPUArchitecture
216 | universalApk false // If true, also generate a universal APK
217 | include (*reactNativeArchitectures())
218 | }
219 | }
220 | signingConfigs {
221 | debug {
222 | storeFile file('debug.keystore')
223 | storePassword 'android'
224 | keyAlias 'androiddebugkey'
225 | keyPassword 'android'
226 | }
227 | }
228 | buildTypes {
229 | debug {
230 | signingConfig signingConfigs.debug
231 | }
232 | release {
233 | // Caution! In production, you need to generate your own keystore file.
234 | // see https://reactnative.dev/docs/signed-apk-android.
235 | signingConfig signingConfigs.debug
236 | minifyEnabled enableProguardInReleaseBuilds
237 | proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
238 | }
239 | }
240 |
241 | // applicationVariants are e.g. debug, release
242 | applicationVariants.all { variant ->
243 | variant.outputs.each { output ->
244 | // For each separate APK per architecture, set a unique version code as described here:
245 | // https://developer.android.com/studio/build/configure-apk-splits.html
246 | // Example: versionCode 1 will generate 1001 for armeabi-v7a, 1002 for x86, etc.
247 | def versionCodes = ["armeabi-v7a": 1, "x86": 2, "arm64-v8a": 3, "x86_64": 4]
248 | def abi = output.getFilter(OutputFile.ABI)
249 | if (abi != null) { // null for the universal-debug, universal-release variants
250 | output.versionCodeOverride =
251 | defaultConfig.versionCode * 1000 + versionCodes.get(abi)
252 | }
253 |
254 | }
255 | }
256 | }
257 |
258 | dependencies {
259 | implementation fileTree(dir: "libs", include: ["*.jar"])
260 |
261 | //noinspection GradleDynamicVersion
262 | implementation "com.facebook.react:react-native:+" // From node_modules
263 |
264 | implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0"
265 |
266 | debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") {
267 | exclude group:'com.facebook.fbjni'
268 | }
269 |
270 | debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") {
271 | exclude group:'com.facebook.flipper'
272 | exclude group:'com.squareup.okhttp3', module:'okhttp'
273 | }
274 |
275 | debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}") {
276 | exclude group:'com.facebook.flipper'
277 | }
278 |
279 | if (enableHermes) {
280 | //noinspection GradleDynamicVersion
281 | implementation("com.facebook.react:hermes-engine:+") { // From node_modules
282 | exclude group:'com.facebook.fbjni'
283 | }
284 | } else {
285 | implementation jscFlavor
286 | }
287 | }
288 |
289 | if (isNewArchitectureEnabled()) {
290 | // If new architecture is enabled, we let you build RN from source
291 | // Otherwise we fallback to a prebuilt .aar bundled in the NPM package.
292 | // This will be applied to all the imported transtitive dependency.
293 | configurations.all {
294 | resolutionStrategy.dependencySubstitution {
295 | substitute(module("com.facebook.react:react-native"))
296 | .using(project(":ReactAndroid"))
297 | .because("On New Architecture we're building React Native from source")
298 | substitute(module("com.facebook.react:hermes-engine"))
299 | .using(project(":ReactAndroid:hermes-engine"))
300 | .because("On New Architecture we're building Hermes from source")
301 | }
302 | }
303 | }
304 |
305 | // Run this once to be able to run the application with BUCK
306 | // puts all compile dependencies into folder libs for BUCK to use
307 | task copyDownloadableDepsToLibs(type: Copy) {
308 | from configurations.implementation
309 | into 'libs'
310 | }
311 |
312 | apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)
313 |
314 | def isNewArchitectureEnabled() {
315 | // To opt-in for the New Architecture, you can either:
316 | // - Set `newArchEnabled` to true inside the `gradle.properties` file
317 | // - Invoke gradle with `-newArchEnabled=true`
318 | // - Set an environment variable `ORG_GRADLE_PROJECT_newArchEnabled=true`
319 | return project.hasProperty("newArchEnabled") && project.newArchEnabled == "true"
320 | }
321 |
--------------------------------------------------------------------------------
/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/WrathChaos/react-native-bounceable/e0b586dd61749ade17df5357f2f4d72a00e0ffb4/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/example/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.example;
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/example/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.example;
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 "example";
16 | }
17 |
18 | /**
19 | * Returns the instance of the {@link ReactActivityDelegate}. There the RootView is created and
20 | * you can specify the renderer you wish to use - the new renderer (Fabric) or the old renderer
21 | * (Paper).
22 | */
23 | @Override
24 | protected ReactActivityDelegate createReactActivityDelegate() {
25 | return new MainActivityDelegate(this, getMainComponentName());
26 | }
27 |
28 | public static class MainActivityDelegate extends ReactActivityDelegate {
29 | public MainActivityDelegate(ReactActivity activity, String mainComponentName) {
30 | super(activity, mainComponentName);
31 | }
32 |
33 | @Override
34 | protected ReactRootView createRootView() {
35 | ReactRootView reactRootView = new ReactRootView(getContext());
36 | // If you opted-in for the New Architecture, we enable the Fabric Renderer.
37 | reactRootView.setIsFabric(BuildConfig.IS_NEW_ARCHITECTURE_ENABLED);
38 | return reactRootView;
39 | }
40 |
41 | @Override
42 | protected boolean isConcurrentRootEnabled() {
43 | // If you opted-in for the New Architecture, we enable Concurrent Root (i.e. React 18).
44 | // More on this on https://reactjs.org/blog/2022/03/29/react-v18.html
45 | return BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/example/android/app/src/main/java/com/example/MainApplication.java:
--------------------------------------------------------------------------------
1 | package com.example;
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.example.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.example.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/example/newarchitecture/MainApplicationReactNativeHost.java:
--------------------------------------------------------------------------------
1 | package com.example.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.FabricJSIModuleProvider;
20 | import com.facebook.react.fabric.ReactNativeConfig;
21 | import com.facebook.react.uimanager.ViewManagerRegistry;
22 | import com.example.BuildConfig;
23 | import com.example.newarchitecture.components.MainComponentsRegistry;
24 | import com.example.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 | ReactNativeConfig.DEFAULT_CONFIG,
109 | viewManagerRegistry);
110 | }
111 | });
112 | return specs;
113 | }
114 | };
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/example/android/app/src/main/java/com/example/newarchitecture/components/MainComponentsRegistry.java:
--------------------------------------------------------------------------------
1 | package com.example.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/example/newarchitecture/modules/MainApplicationTurboModuleManagerDelegate.java:
--------------------------------------------------------------------------------
1 | package com.example.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 | *