= {},
29 | {
30 | sizeLineHeight = val => val * 1.35,
31 | }: {
32 | sizeLineHeight?: (val: number) => number;
33 | } = {},
34 | ): A {
35 | const size = font.size || genericFontSizes;
36 | return createFont({
37 | family,
38 | size,
39 | lineHeight: Object.fromEntries(
40 | Object.entries(size).map(([k, v]) => [k, sizeLineHeight(+v)]),
41 | ) as typeof size,
42 | weight: {0: '300'},
43 | letterSpacing: {4: 0},
44 | ...(font as any),
45 | });
46 | }
47 |
48 | const systemFamily =
49 | process.env.TAMAGUI_TARGET === 'native'
50 | ? 'Inter-Medium'
51 | : '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"';
52 |
53 | const silkscreenFont = createSilkscreenFont();
54 | const headingFont = createInterFont(
55 | {
56 | size: {
57 | 5: 13,
58 | 6: 15,
59 | 9: 32,
60 | 10: 44,
61 | },
62 | transform: {
63 | 6: 'uppercase',
64 | 7: 'none',
65 | },
66 | weight: {
67 | 6: '400',
68 | 7: '700',
69 | },
70 | color: {
71 | 6: '$colorFocus',
72 | 7: '$color',
73 | },
74 | letterSpacing: {
75 | 5: 2,
76 | 6: 1,
77 | 7: 0,
78 | 8: 0,
79 | 9: -1,
80 | 10: -1.5,
81 | 12: -2,
82 | 14: -3,
83 | 15: -4,
84 | },
85 | // for native
86 | face: {
87 | 700: {normal: 'Inter-Bold'},
88 | 800: {normal: 'Inter-Bold'},
89 | 900: {normal: 'Inter-Bold'},
90 | },
91 | },
92 | {sizeLineHeight: size => Math.round(size * 1.1 + (size < 30 ? 10 : 5))},
93 | );
94 |
95 | const bodyFont = createInterFont(
96 | {
97 | family: systemFamily,
98 | weight: {
99 | 1: '500',
100 | 7: '600',
101 | },
102 | // for native
103 | face: {
104 | 900: {normal: 'Inter-Bold'},
105 | },
106 | },
107 | {
108 | sizeSize: size => Math.round(size),
109 | sizeLineHeight: size => Math.round(size * 1.1 + (size >= 12 ? 8 : 4)),
110 | },
111 | );
112 |
113 | const monoFont = createGenericFont(
114 | '"ui-monospace", "SFMono-Regular", "SF Mono", Menlo, Consolas, "Liberation Mono", monospace',
115 | {
116 | weight: {
117 | 1: '500',
118 | },
119 | size: {
120 | 1: 11,
121 | 2: 12,
122 | 3: 13,
123 | 4: 14,
124 | 5: 16,
125 | 6: 18,
126 | 7: 20,
127 | 8: 22,
128 | 9: 30,
129 | 10: 42,
130 | 11: 52,
131 | 12: 62,
132 | 13: 72,
133 | 14: 92,
134 | 15: 114,
135 | 16: 124,
136 | },
137 | },
138 | {
139 | sizeLineHeight: x => x * 1.5,
140 | },
141 | );
142 |
143 | export default {
144 | // noto: notoFont as any,
145 | heading: headingFont,
146 | body: bodyFont,
147 | mono: monoFont,
148 | silkscreen: silkscreenFont,
149 | };
150 |
151 |
152 |
--------------------------------------------------------------------------------
/templates/vanilla/template/ios/Podfile:
--------------------------------------------------------------------------------
1 | require_relative '../node_modules/react-native/scripts/react_native_pods'
2 | require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'
3 |
4 | platform :ios, '13.0'
5 | prepare_react_native_project!
6 |
7 | # If you are using a `react-native-flipper` your iOS build will fail when `NO_FLIPPER=1` is set.
8 | # because `react-native-flipper` depends on (FlipperKit,...) that will be excluded
9 | #
10 | # To fix this you can also exclude `react-native-flipper` using a `react-native.config.js`
11 | # ```js
12 | # module.exports = {
13 | # dependencies: {
14 | # ...(process.env.NO_FLIPPER ? { 'react-native-flipper': { platforms: { ios: null } } } : {}),
15 | # ```
16 |
17 | flipper_config = ENV['NO_FLIPPER'] == "1" ? FlipperConfiguration.disabled : FlipperConfiguration.enabled
18 |
19 | linkage = ENV['USE_FRAMEWORKS']
20 | if linkage != nil
21 | Pod::UI.puts "Configuring Pod with #{linkage}ally linked Frameworks".green
22 | use_frameworks! :linkage => linkage.to_sym
23 | end
24 |
25 | target 'ProjectName' do
26 | config = use_native_modules!
27 |
28 | # Flags change depending on the env values.
29 | flags = get_default_flags()
30 |
31 | use_react_native!(
32 | :path => config[:reactNativePath],
33 | # Hermes is now enabled by default. Disable by setting this flag to false.
34 | # Upcoming versions of React Native may rely on get_default_flags(), but
35 | # we make it explicit here to aid in the React Native upgrade process.
36 | :hermes_enabled => flags[:hermes_enabled],
37 | :fabric_enabled => flags[:fabric_enabled],
38 | # Enables Flipper.
39 | #
40 | # Note that if you have use_frameworks! enabled, Flipper will not work and
41 | # you should disable the next line.
42 | :flipper_configuration => flipper_config,
43 | # An absolute path to your application root.
44 | :app_path => "#{Pod::Config.instance.installation_root}/.."
45 | )
46 |
47 | target 'ProjectNameTests' do
48 | inherit! :complete
49 | # Pods for testing
50 | end
51 |
52 | post_install do |installer|
53 | react_native_post_install(
54 | installer,
55 | # Set `mac_catalyst_enabled` to `true` in order to apply patches
56 | # necessary for Mac Catalyst builds
57 | :mac_catalyst_enabled => false
58 | )
59 |
60 | # Performance optimization - use relative path to compiler binaries
61 | # in combination with ccache (`brew install ccache`) this will really speed up your build (10x? 100x?)
62 | # ccache config settings that work well with react-native:
63 | # depend_mode = true
64 | # file_clone = true
65 | # inode_cache = true
66 | # max_size = 7.0G
67 | # sloppiness = include_file_mtime, include_file_ctime, time_macros, pch_defines, file_stat_matches, system_headers, clang_index_store, modules, ivfsoverlay
68 | installer.pods_project.targets.each do |target|
69 | target.build_configurations.each do |config|
70 | config.build_settings["CC"] = "clang"
71 | config.build_settings["LD"] = "clang"
72 | config.build_settings["CXX"] = "clang++"
73 | config.build_settings["LDPLUSPLUS"] = "clang++"
74 | end
75 | end
76 |
77 | # Turn off warnings - react-native builds are really really noisy, but it's not project code
78 | installer.pods_project.targets.each do |target|
79 | target.build_configurations.each do |config|
80 | config.build_settings["GCC_WARN_INHIBIT_ALL_WARNINGS"] = "YES"
81 | end
82 | end
83 |
84 | __apply_Xcode_12_5_M1_post_install_workaround(installer)
85 | end
86 | end
87 |
--------------------------------------------------------------------------------
/templates/vanilla/template/android/app/src/debug/java/com/projectname/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.projectname;
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.sharedpreferences.SharedPreferencesFlipperPlugin;
21 | import com.facebook.react.ReactInstanceEventListener;
22 | import com.facebook.react.ReactInstanceManager;
23 | import com.facebook.react.bridge.ReactContext;
24 | import com.facebook.react.modules.network.NetworkingModule;
25 | import okhttp3.OkHttpClient;
26 |
27 | /**
28 | * Class responsible of loading Flipper inside your React Native application. This is the debug
29 | * flavor of it. Here you can add your own plugins and customize the Flipper setup.
30 | */
31 | public class ReactNativeFlipper {
32 | public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) {
33 | if (FlipperUtils.shouldEnableFlipper(context)) {
34 | final FlipperClient client = AndroidFlipperClient.getInstance(context);
35 |
36 | client.addPlugin(new InspectorFlipperPlugin(context, DescriptorMapping.withDefaults()));
37 | client.addPlugin(new DatabasesFlipperPlugin(context));
38 | client.addPlugin(new SharedPreferencesFlipperPlugin(context));
39 | client.addPlugin(CrashReporterPlugin.getInstance());
40 |
41 | NetworkFlipperPlugin networkFlipperPlugin = new NetworkFlipperPlugin();
42 | NetworkingModule.setCustomClientBuilder(
43 | new NetworkingModule.CustomClientBuilder() {
44 | @Override
45 | public void apply(OkHttpClient.Builder builder) {
46 | builder.addNetworkInterceptor(new FlipperOkhttpInterceptor(networkFlipperPlugin));
47 | }
48 | });
49 | client.addPlugin(networkFlipperPlugin);
50 | client.start();
51 |
52 | // Fresco Plugin needs to ensure that ImagePipelineFactory is initialized
53 | // Hence we run if after all native modules have been initialized
54 | ReactContext reactContext = reactInstanceManager.getCurrentReactContext();
55 | if (reactContext == null) {
56 | reactInstanceManager.addReactInstanceEventListener(
57 | new ReactInstanceEventListener() {
58 | @Override
59 | public void onReactContextInitialized(ReactContext reactContext) {
60 | reactInstanceManager.removeReactInstanceEventListener(this);
61 | reactContext.runOnNativeModulesQueueThread(
62 | new Runnable() {
63 | @Override
64 | public void run() {
65 | client.addPlugin(new FrescoFlipperPlugin());
66 | }
67 | });
68 | }
69 | });
70 | } else {
71 | client.addPlugin(new FrescoFlipperPlugin());
72 | }
73 | }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/templates/vanilla/template/ios/ProjectName.xcodeproj/xcshareddata/xcschemes/ProjectName.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
39 |
40 |
41 |
42 |
43 |
53 |
55 |
61 |
62 |
63 |
64 |
70 |
72 |
78 |
79 |
80 |
81 |
83 |
84 |
87 |
88 |
89 |
--------------------------------------------------------------------------------
/templates/vanilla/template/src/App.tsx:
--------------------------------------------------------------------------------
1 | import {StyleSheet, StatusBar, useColorScheme} from 'react-native';
2 | import {GestureHandlerRootView} from 'react-native-gesture-handler';
3 | import {TamaguiProvider, useTheme, Stack, H4} from 'tamagui';
4 | import {SolitoImageProvider} from 'solito/image';
5 | import {
6 | initialWindowMetrics,
7 | SafeAreaProvider,
8 | SafeAreaView,
9 | } from 'react-native-safe-area-context';
10 | import {
11 | DefaultTheme,
12 | NavigationContainer,
13 | DarkTheme,
14 | } from '@react-navigation/native';
15 | import {
16 | createDrawerNavigator,
17 | DrawerToggleButton,
18 | DrawerNavigationOptions,
19 | DrawerHeaderProps,
20 | } from '@react-navigation/drawer';
21 | import {Home} from './features/Home';
22 | import {Logo} from './components/Logo';
23 | import config from '../tamagui';
24 | import {UserDetailScreen} from './features/DetailScreen';
25 |
26 | const Drawer = createDrawerNavigator();
27 |
28 | const Header = ({route}: DrawerHeaderProps) => {
29 | const theme = useTheme();
30 |
31 | return (
32 |
33 |
34 |
35 |
36 |
37 | {route.name.toUpperCase()}
38 |
39 |
40 |
41 | );
42 | };
43 |
44 | const screenOptions: DrawerNavigationOptions = {
45 | header: props => ,
46 | };
47 |
48 | const TopTabNavigator = () => {
49 | return (
50 |
51 |
57 |
64 |
65 | );
66 | };
67 |
68 | const linking = {
69 | prefixes: ['criszz77.github.io/luna', 'localhost'],
70 | config: {
71 | screens: {
72 | home: '',
73 | 'user-detail': 'user/:id',
74 | },
75 | },
76 | };
77 |
78 | const InnerApp = () => {
79 | const colorScheme = useColorScheme() || 'light';
80 | const isDarkMode = colorScheme === 'dark';
81 | const theme = useTheme();
82 |
83 | return (
84 |
85 |
86 |
90 |
93 |
94 |
95 |
96 |
97 | );
98 | };
99 |
100 | const App = () => {
101 | const theme = useColorScheme() || 'light';
102 | return (
103 |
104 |
105 |
106 |
107 |
108 | );
109 | };
110 |
111 | const styles = StyleSheet.create({
112 | container: {
113 | flex: 1,
114 | },
115 | headerContainer: {
116 | flexDirection: 'row',
117 | alignItems: 'center',
118 | },
119 | logo: {
120 | flex: 1,
121 | },
122 | logoContainer: {
123 | flex: 1,
124 | height: 50,
125 | width: 50,
126 | },
127 | routeName: {
128 | flex: 1,
129 | textAlign: 'right',
130 | marginRight: 15,
131 | },
132 | });
133 |
134 | export default App;
135 |
--------------------------------------------------------------------------------
/templates/expo/src/App.tsx:
--------------------------------------------------------------------------------
1 | import {StyleSheet, StatusBar, useColorScheme} from 'react-native';
2 | import {GestureHandlerRootView} from 'react-native-gesture-handler';
3 | import {TamaguiProvider, useTheme, Stack, H4} from 'tamagui';
4 | import {SolitoImageProvider} from 'solito/image';
5 | import {
6 | initialWindowMetrics,
7 | SafeAreaProvider,
8 | SafeAreaView,
9 | } from 'react-native-safe-area-context';
10 | import {
11 | DefaultTheme,
12 | NavigationContainer,
13 | DarkTheme,
14 | } from '@react-navigation/native';
15 | import {
16 | createDrawerNavigator,
17 | DrawerToggleButton,
18 | DrawerNavigationOptions,
19 | DrawerHeaderProps,
20 | } from '@react-navigation/drawer';
21 | import {Home} from './features/Home';
22 | import {Logo} from './components/Logo';
23 | import config from '../tamagui';
24 | import {UserDetailScreen} from './features/DetailScreen';
25 | import {useFonts} from "expo-font";
26 | import {tamaguiFonts} from "../tamagui/tamaguiFonts.native";
27 |
28 | const Drawer = createDrawerNavigator();
29 |
30 | const Header = ({route}: DrawerHeaderProps) => {
31 | const theme = useTheme();
32 |
33 | return (
34 |
35 |
36 |
37 |
38 |
39 | {route.name.toUpperCase()}
40 |
41 |
42 |
43 | );
44 | };
45 |
46 | const screenOptions: DrawerNavigationOptions = {
47 | header: props => ,
48 | };
49 |
50 | const TopTabNavigator = () => {
51 | return (
52 |
53 |
59 |
66 |
67 | );
68 | };
69 |
70 | const linking = {
71 | prefixes: ['criszz77.github.io/luna', 'localhost'],
72 | config: {
73 | screens: {
74 | home: '',
75 | 'user-detail': 'user/:id',
76 | },
77 | },
78 | };
79 |
80 | const InnerApp = () => {
81 | const colorScheme = useColorScheme() || 'light';
82 | const isDarkMode = colorScheme === 'dark';
83 | const theme = useTheme();
84 |
85 | return (
86 |
87 |
88 |
92 |
95 |
96 |
97 |
98 |
99 | );
100 | };
101 |
102 | const App = () => {
103 | const theme = useColorScheme() || 'light';
104 |
105 | const [loaded] = useFonts(tamaguiFonts)
106 |
107 | if (!loaded) {
108 | return null
109 | }
110 |
111 | return (
112 |
113 |
114 |
115 |
116 |
117 | );
118 | };
119 |
120 | const styles = StyleSheet.create({
121 | container: {
122 | flex: 1,
123 | },
124 | headerContainer: {
125 | flexDirection: 'row',
126 | alignItems: 'center',
127 | },
128 | logo: {
129 | flex: 1,
130 | },
131 | logoContainer: {
132 | flex: 1,
133 | height: 50,
134 | width: 50,
135 | },
136 | routeName: {
137 | flex: 1,
138 | textAlign: 'right',
139 | marginRight: 15,
140 | },
141 | });
142 |
143 | export default App;
144 |
--------------------------------------------------------------------------------
/templates/vanilla/template/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ProjectName",
3 | "version": "3.0.3",
4 | "private": true,
5 | "scripts": {
6 | "android": "react-native run-android",
7 | "ios": "react-native run-ios",
8 | "ios:pods": "npx pod-install",
9 | "start": "react-native start",
10 | "web": "next dev",
11 | "build": "next build",
12 | "next-start": "next start",
13 | "test:all": "yarn test:jest",
14 | "test:jest": "jest",
15 | "lint:all": "yarn lint:eslint && yarn lint:prettier && yarn lint:types",
16 | "lint:eslint": "eslint src/",
17 | "lint:eslint:fix": "eslint --fix src/",
18 | "lint:prettier": "prettier --check \"src/**/*.+(js|jsx|ts|tsx|json|css|md)\"",
19 | "lint:prettier:fix": "prettier --write \"src/**/*.+(js|jsx|ts|tsx|json|css|md)\"",
20 | "lint:types": "tsc",
21 | "package:install": "yarn && yarn ios:pods || true",
22 | "package:update": "yarn upgrade --latest && cd ios && rm -f Podfile.lock && yarn ios:pods && pod update",
23 | "next-lint": "next lint",
24 | "postinstall": "patch-package"
25 | },
26 | "dependencies": {
27 | "@react-native-masked-view/masked-view": "^0.2.8",
28 | "@react-navigation/drawer": "^6.6.2",
29 | "@react-navigation/native": "^6.1.6",
30 | "@tamagui/animations-react-native": "1.7.2",
31 | "@tamagui/animations-reanimated": "1.7.2",
32 | "@tamagui/babel-plugin": "1.7.2",
33 | "@tamagui/font-inter": "1.7.2",
34 | "@tamagui/font-silkscreen": "1.7.2",
35 | "@tamagui/lucide-icons": "1.7.2",
36 | "@tamagui/next-plugin": "1.7.2",
37 | "@tamagui/next-theme": "1.7.2",
38 | "@tamagui/shorthands": "1.7.2",
39 | "@tamagui/themes": "1.7.2",
40 | "@types/node": "^18.14.6",
41 | "next": "^13.2.3",
42 | "raf": "^3.4.1",
43 | "react": "^18.2.0",
44 | "react-dom": "^18.2.0",
45 | "react-native": "^0.71.3",
46 | "react-native-fast-image": "^8.6.3",
47 | "react-native-gesture-handler": "^2.9.0",
48 | "react-native-pager-view": "^6.1.4",
49 | "react-native-reanimated": "~2.14.4",
50 | "react-native-reanimated-swc-plugin": "^0.3.0",
51 | "react-native-safe-area-context": "^4.5.0",
52 | "react-native-screens": "^3.20.0",
53 | "react-native-svg": "^13.8.0",
54 | "react-native-tab-view": "^3.5.1",
55 | "react-native-web": "^0.18.12",
56 | "sharp": "^0.31.3",
57 | "solito": "^3.0.0",
58 | "tamagui": "1.7.2"
59 | },
60 | "devDependencies": {
61 | "@babel/core": "^7.20.0",
62 | "@babel/preset-env": "^7.20.0",
63 | "@babel/runtime": "^7.20.0",
64 | "@react-native-community/eslint-config": "^3.2.0",
65 | "@tsconfig/react-native": "^2.0.2",
66 | "@types/jest": "^29.2.1",
67 | "@types/react": "^18.0.28",
68 | "@types/react-dom": "^18.0.10",
69 | "@types/react-test-renderer": "^18.0.0",
70 | "babel-jest": "29.2.1",
71 | "babel-plugin-module-resolver": "^5.0.0",
72 | "babel-plugin-transform-inline-environment-variables": "^0.4.4",
73 | "eslint": "^8.19.0",
74 | "eslint-config-next": "^13.1.2",
75 | "jest": "^29.2.1",
76 | "metro-react-native-babel-preset": "^0.73.8",
77 | "patch-package": "^6.5.1",
78 | "pod-install": "^0.1.38",
79 | "postinstall-postinstall": "^2.1.0",
80 | "prettier": "^2.4.1",
81 | "react-test-renderer": "^18.2.0",
82 | "typescript": "^4.8.4"
83 | },
84 | "resolutions": {
85 | "@babel/plugin-transform-typescript": "7.19.3"
86 | },
87 | "jest": {
88 | "preset": "react-native",
89 | "moduleFileExtensions": [
90 | "ts",
91 | "tsx",
92 | "js",
93 | "jsx",
94 | "json",
95 | "node"
96 | ],
97 | "transformIgnorePatterns": [
98 | "node_modules/(?!((jest-)?react-native|@react-native(-community)?)|expo(nent)?|@expo(nent)?/.*|@expo-google-fonts/.*|react-navigation|@react-navigation/.*|@unimodules/.*|unimodules|sentry-expo|native-base|react-native-svg|solito)"
99 | ]
100 | },
101 | "browserslist": {
102 | "production": [
103 | ">0.2%",
104 | "not dead",
105 | "not op_mini all"
106 | ],
107 | "development": [
108 | "last 1 chrome version",
109 | "last 1 firefox version",
110 | "last 1 safari version"
111 | ]
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/templates/vanilla/template/ios/ProjectName/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
24 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
10 | [![reactnative][3]][4]
11 | [![Expo][34]][35]
12 | [![nextjs][5]][6]
13 | [![platforms][7]][8]
14 | [![GitHub top language][31]][32]
15 | [![ci][1]][2]
16 | [![GitHub][9]][10]
17 | [![npm][13]][14]
18 |
19 |
20 |
21 |
22 | > ### 🚧 🚧 OBSOLETE 🚧 🚧
23 | >
24 | > I believe expo-router (with a simpler setup) achieves the same thing as this template. There's no need to go down the rabbit hole and use Next.js + Expo.
25 |
26 | # 🌒 `Luna`
27 | ### `🌒 Luna` is a `React Native` and `Next.js` boilerplate so your app can run on `Android`, `IOS` and `Web` concurrently.
28 | [You can try the live example here.][19]
29 |
30 | ## ⭐ Features
31 | > 📖 Please visit the [`🌒 Luna Wiki`][20] to see why and how we decided to implement all those features. \
32 | > 🚀 For an advanced start, but currently without `Next.js`, you can head to [react-native-firebase-authentification-example][21] which is built on top of Luna template
33 |
34 | - [React Native Web][22]
35 | - [Next.js][6]
36 | - [Solito][23]
37 | - [Tamagui][29]
38 | - [TypeScript][24]
39 | - No monorepo (everything in one app)
40 | - Other
41 |
42 | ## 🎛 Setup
43 | > ⚠️ Please be sure your environment is set up correctly for React Native \
44 | > 🔗 https://reactnative.dev/docs/environment-setup
45 |
46 | ## 🛸 Usage
47 |
48 |
49 | You can create a new project interactively by running:
50 |
51 | ```bash
52 | yarn create luna-app
53 | ```
54 |
55 | 
56 |
57 |
58 | After that, all the commands from below are available:
59 |
60 | - ### 📱 **Native**
61 |
62 | #### `yarn start`
63 |
64 | Start Metro Bundler. After that, you can press `i` or `a` to run the app on iOS or Android simulator respectively.
65 |
66 | - ### 💻 **Web**
67 | #### `yarn web`
68 |
69 | Runs the app in the web in development mode.\
70 | Open [http://localhost:3000][25] to view it in the browser.
71 |
72 | The page will reload if you make edits.\
73 | You will also see any lint errors in the console.
74 |
75 | #### `yarn build`
76 |
77 | Builds the web app for production with Next.js.
78 |
79 | #### `yarn next-start`
80 |
81 | Runs the web app in production mode with Next.js. \
82 | Open [http://localhost:3000][25] to view it in the browser. \
83 | **Note:** You have to run `yarn build` first!
84 |
85 |
86 | ## 🪲 Debugging
87 | - ### React Native CLI
88 | > This template only works with the new CLI. Please make sure that:
89 | > - [your environment is set up correctly for React Native CLI.][26]
90 | > - you have uninstalled the legacy `react-native-cli` first (`npm uninstall -g react-native-cli`) for the below command to work. If you wish to not use npx, you can also install the new CLI globally (`npm i -g @react-native-community/cli` or `yarn global add @react-native-community/cli`).
91 |
92 | > If you tried the above and still get the @criszz77/luna: Not found error, please try adding the `--ignore-existing` flag to [force npx to ignore][30] any locally installed versions of the CLI and use the latest.
93 | Further information can be found here: https://github.com/react-native-community/cli#about
94 |
95 | - ### React Native Web
96 | > [React Dev Tools][27] supports inspecting and editing of React Native styles. It’s recommended that you rely more on React Dev Tools and live/hot-reloading rather than inspecting and editing the **DOM** directly.
97 |
98 |
99 | ## 📃 License
100 |
101 | > 📃 This project is released under the [MIT License](LICENSE). \
102 | > 💻 By contributing, you agree that your contributions will be licensed under its MIT License.
103 |
104 | ## 🏆 Sponsors
105 |
106 | | |
107 | |---------------------------|
108 | | [![jetbrains100][33]][28] |
109 |
110 | [1]: https://github.com/LunatiqueCoder/react-native-media-console/workflows/ci/badge.svg
111 | [2]: https://github.com/LunatiqueCoder/luna/actions
112 | [3]: https://img.shields.io/badge/-React%20Native%20CLI-282C34?style=flat-square&logo=react&logoColor=61DAFB
113 | [4]: https://reactnative.dev/
114 |
115 | [5]: https://img.shields.io/badge/Next.js-black?style=flat-square&logo=next.js&logoColor=white
116 |
117 | [6]: https://nextjs.org/
118 | [7]: https://img.shields.io/badge/platforms-Android%20%7C%20iOS%20%7C%20Web-brightgreen.svg?style=flat-square&colorB=191A17
119 | [8]: https://necolas.github.io/react-native-web/
120 | [9]: https://img.shields.io/github/license/LunatiqueCoder/luna
121 | [10]: https://github.com/LunatiqueCoder/luna/blob/master/LICENSE
122 | [11]: https://img.shields.io/maintenance/yes/2023
123 | [12]: https://github.com/LunatiqueCoder/luna/graphs/contributors
124 | [13]: https://img.shields.io/npm/v/create-luna-app
125 | [14]: https://www.npmjs.com/package/create-luna-app
126 | [15]: https://img.shields.io/github/issues/criszz77/luna
127 | [16]: https://github.com/LunatiqueCoder/luna/issues
128 | [17]: https://img.shields.io/github/issues-closed/LunatiqueCoder/luna
129 | [18]: https://github.com/LunatiqueCoder/luna/issues?q=is%3Aissue+is%3Aclosed
130 | [19]: https://luna-gamma.vercel.app/
131 | [20]: https://github.com/LunatiqueCoder/luna/wiki/v2.0.0
132 | [21]: https://github.com/invertase/react-native-firebase-authentication-example
133 | [22]: https://necolas.github.io/react-native-web/
134 | [23]: https://solito.dev/
135 | [24]: https://www.typescriptlang.org/
136 | [25]: http://localhost:3000
137 | [26]: https://reactnative.dev/docs/environment-setup
138 | [27]: https://beta.reactjs.org/learn/react-developer-tools
139 | [28]: https://www.jetbrains.com/
140 | [29]: https://tamagui.dev
141 | [30]: https://github.com/npm/npx#description
142 | [31]: https://img.shields.io/github/languages/top/LunatiqueCoder/luna
143 | [32]: https://github.com/criszz77/luna/search?l=typescript
144 | [33]: https://user-images.githubusercontent.com/55203625/213786907-b95dfb4b-08bf-4449-a055-72edf401da23.png
145 | [34]: https://img.shields.io/badge/-Expo%20CLI-282C34?style=flat-square&logo=expo&logoColor=#D04A37
146 | [35]: https://expo.dev/
147 |
--------------------------------------------------------------------------------
/templates/expo/react-native-web.d.ts:
--------------------------------------------------------------------------------
1 | // This file is adapted from: https://github.com/necolas/react-native-web/issues/832#issuecomment-1027393818
2 |
3 | import {MouseEvent, UIEvent, FocusEvent, ReactNode} from 'react';
4 | export * from 'react-native';
5 |
6 | declare module 'react-native' {
7 | namespace AppRegistry {
8 | function getApplication(string): {getStyleElement: () => ReactNode};
9 | }
10 |
11 | // The following list is sourced from:
12 | // - https://github.com/necolas/react-native-web/blob/0.17.5/packages/react-native-web/src/types/styles.js#L76
13 | type CursorValue =
14 | | 'alias'
15 | | 'all-scroll'
16 | | 'auto'
17 | | 'cell'
18 | | 'context-menu'
19 | | 'copy'
20 | | 'crosshair'
21 | | 'default'
22 | | 'grab'
23 | | 'grabbing'
24 | | 'help'
25 | | 'pointer'
26 | | 'progress'
27 | | 'wait'
28 | | 'text'
29 | | 'vertical-text'
30 | | 'move'
31 | | 'none'
32 | | 'no-drop'
33 | | 'not-allowed'
34 | | 'zoom-in'
35 | | 'zoom-out'
36 | | 'col-resize'
37 | | 'e-resize'
38 | | 'ew-resize'
39 | | 'n-resize'
40 | | 'ne-resize'
41 | | 'ns-resize'
42 | | 'nw-resize'
43 | | 'row-resize'
44 | | 's-resize'
45 | | 'se-resize'
46 | | 'sw-resize'
47 | | 'w-resize'
48 | | 'nesw-resize'
49 | | 'nwse-resize';
50 |
51 | // This list is the combination of the following two lists:
52 | // - https://github.com/necolas/react-native-web/blob/0.17.5/packages/react-native-web/src/modules/AccessibilityUtil/propsToAriaRole.js#L10
53 | // - https://github.com/necolas/react-native-web/blob/0.17.5/packages/react-native-web/src/modules/AccessibilityUtil/propsToAccessibilityComponent.js#L12
54 | // Plus the single hard-coded value "label" from here:
55 | // - https://github.com/necolas/react-native-web/blob/0.17.5/packages/react-native-web/src/modules/AccessibilityUtil/propsToAccessibilityComponent.js#L36
56 | type WebAccessibilityRole =
57 | | 'adjustable'
58 | | 'article'
59 | | 'banner'
60 | | 'blockquote'
61 | | 'button'
62 | | 'code'
63 | | 'complementary'
64 | | 'contentinfo'
65 | | 'deletion'
66 | | 'emphasis'
67 | | 'figure'
68 | | 'form'
69 | | 'header'
70 | | 'image'
71 | | 'imagebutton'
72 | | 'insertion'
73 | | 'keyboardkey'
74 | | 'label'
75 | | 'link'
76 | | 'list'
77 | | 'listitem'
78 | | 'main'
79 | | 'navigation'
80 | | 'none'
81 | | 'region'
82 | | 'search'
83 | | 'strong'
84 | | 'summary'
85 | | 'text';
86 |
87 | interface PressableStateCallbackType {
88 | hovered?: boolean;
89 | focused?: boolean;
90 | }
91 |
92 | interface ViewProps {
93 | accessibilityRole?: WebAccessibilityRole;
94 | href?: string;
95 | hrefAttrs?: {
96 | target?: '_blank' | '_self' | '_top' | 'blank' | 'self' | 'top';
97 | rel?: string;
98 | download?: boolean;
99 | };
100 | onMouseDown?: (event: MouseEvent) => void;
101 | onMouseUp?: (event: MouseEvent) => void;
102 | onMouseEnter?: (event: MouseEvent) => void;
103 | onMouseLeave?: (event: MouseEvent) => void;
104 | onClick?: (event: MouseEvent) => void;
105 | onFocus?: (event: FocusEvent) => void;
106 | onScroll?: (event: UIEvent) => void;
107 | // For compatibility with RNW internals
108 | onScrollShouldSetResponder?: unknown;
109 | onScrollShouldSetResponderCapture?: unknown;
110 | onSelectionChangeShouldSetResponder?: unknown;
111 | onSelectionChangeShouldSetResponderCapture?: unknown;
112 | }
113 |
114 | interface TextProps {
115 | dir?: 'ltr' | 'rtl' | 'auto';
116 | focusable?: boolean;
117 | accessibilityRole?: WebAccessibilityRole;
118 | accessibilityState?: {
119 | busy?: boolean;
120 | checked?: boolean | 'mixed';
121 | disabled?: boolean;
122 | expanded?: boolean;
123 | grabbed?: boolean;
124 | hidden?: boolean;
125 | invalid?: boolean;
126 | pressed?: boolean;
127 | readonly?: boolean;
128 | required?: boolean;
129 | selected?: boolean;
130 | };
131 | href?: string;
132 | hrefAttrs?: {
133 | target?: '_blank' | '_self' | '_top' | 'blank' | 'self' | 'top';
134 | rel?: string;
135 | download?: boolean;
136 | };
137 | onMouseEnter?: (event: MouseEvent) => void;
138 | onMouseLeave?: (event: MouseEvent) => void;
139 | onClick?: (event: MouseEvent) => void;
140 | onFocus?: (event: FocusEvent) => void;
141 | // For compatibility with RNW internals
142 | onMoveShouldSetResponder?: unknown;
143 | onMoveShouldSetResponderCapture?: unknown;
144 | onResponderEnd?: unknown;
145 | onResponderGrant?: unknown;
146 | onResponderMove?: unknown;
147 | onResponderReject?: unknown;
148 | onResponderRelease?: unknown;
149 | onResponderStart?: unknown;
150 | onResponderTerminate?: unknown;
151 | onResponderTerminationRequest?: unknown;
152 | onScrollShouldSetResponder?: unknown;
153 | onScrollShouldSetResponderCapture?: unknown;
154 | onSelectionChangeShouldSetResponder?: unknown;
155 | onSelectionChangeShouldSetResponderCapture?: unknown;
156 | onStartShouldSetResponder?: unknown;
157 | onStartShouldSetResponderCapture?: unknown;
158 | }
159 |
160 | interface TouchableOpacityProps {
161 | accessibilityRole?: WebAccessibilityRole;
162 | href?: string;
163 | hrefAttrs?: {
164 | target?: '_blank' | '_self' | '_top' | 'blank' | 'self' | 'top';
165 | rel?: string;
166 | download?: boolean;
167 | };
168 | nativeID?: string;
169 | onMouseEnter?: (event: MouseEvent) => void;
170 | onMouseLeave?: (event: MouseEvent) => void;
171 | }
172 |
173 | interface CheckBoxProps {
174 | color?: string | null;
175 | }
176 |
177 | interface ViewStyle {
178 | cursor?: CursorValue;
179 | transitionProperty?: string;
180 | display?: 'flex' | 'inline-flex' | 'none';
181 | outlineWidth?: number | string;
182 | boxShadow?: string;
183 | visibility?: 'hidden' | 'visible' | 'collapse' | 'initial';
184 | position?: 'absolute' | 'relative' | 'fixed';
185 | }
186 |
187 | interface TextStyle {
188 | // The following list is sourced from:
189 | // - https://github.com/necolas/react-native-web/blob/0.17.5/packages/react-native-web/src/types/styles.js#L128
190 | userSelect?: 'all' | 'auto' | 'contain' | 'none' | 'text';
191 | }
192 | }
193 |
--------------------------------------------------------------------------------
/templates/vanilla/template/react-native-web.d.ts:
--------------------------------------------------------------------------------
1 | // This file is adapted from: https://github.com/necolas/react-native-web/issues/832#issuecomment-1027393818
2 |
3 | import {MouseEvent, UIEvent, FocusEvent, ReactNode} from 'react';
4 | export * from 'react-native';
5 |
6 | declare module 'react-native' {
7 | namespace AppRegistry {
8 | function getApplication(string): {getStyleElement: () => ReactNode};
9 | }
10 |
11 | // The following list is sourced from:
12 | // - https://github.com/necolas/react-native-web/blob/0.17.5/packages/react-native-web/src/types/styles.js#L76
13 | type CursorValue =
14 | | 'alias'
15 | | 'all-scroll'
16 | | 'auto'
17 | | 'cell'
18 | | 'context-menu'
19 | | 'copy'
20 | | 'crosshair'
21 | | 'default'
22 | | 'grab'
23 | | 'grabbing'
24 | | 'help'
25 | | 'pointer'
26 | | 'progress'
27 | | 'wait'
28 | | 'text'
29 | | 'vertical-text'
30 | | 'move'
31 | | 'none'
32 | | 'no-drop'
33 | | 'not-allowed'
34 | | 'zoom-in'
35 | | 'zoom-out'
36 | | 'col-resize'
37 | | 'e-resize'
38 | | 'ew-resize'
39 | | 'n-resize'
40 | | 'ne-resize'
41 | | 'ns-resize'
42 | | 'nw-resize'
43 | | 'row-resize'
44 | | 's-resize'
45 | | 'se-resize'
46 | | 'sw-resize'
47 | | 'w-resize'
48 | | 'nesw-resize'
49 | | 'nwse-resize';
50 |
51 | // This list is the combination of the following two lists:
52 | // - https://github.com/necolas/react-native-web/blob/0.17.5/packages/react-native-web/src/modules/AccessibilityUtil/propsToAriaRole.js#L10
53 | // - https://github.com/necolas/react-native-web/blob/0.17.5/packages/react-native-web/src/modules/AccessibilityUtil/propsToAccessibilityComponent.js#L12
54 | // Plus the single hard-coded value "label" from here:
55 | // - https://github.com/necolas/react-native-web/blob/0.17.5/packages/react-native-web/src/modules/AccessibilityUtil/propsToAccessibilityComponent.js#L36
56 | type WebAccessibilityRole =
57 | | 'adjustable'
58 | | 'article'
59 | | 'banner'
60 | | 'blockquote'
61 | | 'button'
62 | | 'code'
63 | | 'complementary'
64 | | 'contentinfo'
65 | | 'deletion'
66 | | 'emphasis'
67 | | 'figure'
68 | | 'form'
69 | | 'header'
70 | | 'image'
71 | | 'imagebutton'
72 | | 'insertion'
73 | | 'keyboardkey'
74 | | 'label'
75 | | 'link'
76 | | 'list'
77 | | 'listitem'
78 | | 'main'
79 | | 'navigation'
80 | | 'none'
81 | | 'region'
82 | | 'search'
83 | | 'strong'
84 | | 'summary'
85 | | 'text';
86 |
87 | interface PressableStateCallbackType {
88 | hovered?: boolean;
89 | focused?: boolean;
90 | }
91 |
92 | interface ViewProps {
93 | accessibilityRole?: WebAccessibilityRole;
94 | href?: string;
95 | hrefAttrs?: {
96 | target?: '_blank' | '_self' | '_top' | 'blank' | 'self' | 'top';
97 | rel?: string;
98 | download?: boolean;
99 | };
100 | onMouseDown?: (event: MouseEvent) => void;
101 | onMouseUp?: (event: MouseEvent) => void;
102 | onMouseEnter?: (event: MouseEvent) => void;
103 | onMouseLeave?: (event: MouseEvent) => void;
104 | onClick?: (event: MouseEvent) => void;
105 | onFocus?: (event: FocusEvent) => void;
106 | onScroll?: (event: UIEvent) => void;
107 | // For compatibility with RNW internals
108 | onScrollShouldSetResponder?: unknown;
109 | onScrollShouldSetResponderCapture?: unknown;
110 | onSelectionChangeShouldSetResponder?: unknown;
111 | onSelectionChangeShouldSetResponderCapture?: unknown;
112 | }
113 |
114 | interface TextProps {
115 | dir?: 'ltr' | 'rtl' | 'auto';
116 | focusable?: boolean;
117 | accessibilityRole?: WebAccessibilityRole;
118 | accessibilityState?: {
119 | busy?: boolean;
120 | checked?: boolean | 'mixed';
121 | disabled?: boolean;
122 | expanded?: boolean;
123 | grabbed?: boolean;
124 | hidden?: boolean;
125 | invalid?: boolean;
126 | pressed?: boolean;
127 | readonly?: boolean;
128 | required?: boolean;
129 | selected?: boolean;
130 | };
131 | href?: string;
132 | hrefAttrs?: {
133 | target?: '_blank' | '_self' | '_top' | 'blank' | 'self' | 'top';
134 | rel?: string;
135 | download?: boolean;
136 | };
137 | onMouseEnter?: (event: MouseEvent) => void;
138 | onMouseLeave?: (event: MouseEvent) => void;
139 | onClick?: (event: MouseEvent) => void;
140 | onFocus?: (event: FocusEvent) => void;
141 | // For compatibility with RNW internals
142 | onMoveShouldSetResponder?: unknown;
143 | onMoveShouldSetResponderCapture?: unknown;
144 | onResponderEnd?: unknown;
145 | onResponderGrant?: unknown;
146 | onResponderMove?: unknown;
147 | onResponderReject?: unknown;
148 | onResponderRelease?: unknown;
149 | onResponderStart?: unknown;
150 | onResponderTerminate?: unknown;
151 | onResponderTerminationRequest?: unknown;
152 | onScrollShouldSetResponder?: unknown;
153 | onScrollShouldSetResponderCapture?: unknown;
154 | onSelectionChangeShouldSetResponder?: unknown;
155 | onSelectionChangeShouldSetResponderCapture?: unknown;
156 | onStartShouldSetResponder?: unknown;
157 | onStartShouldSetResponderCapture?: unknown;
158 | }
159 |
160 | interface TouchableOpacityProps {
161 | accessibilityRole?: WebAccessibilityRole;
162 | href?: string;
163 | hrefAttrs?: {
164 | target?: '_blank' | '_self' | '_top' | 'blank' | 'self' | 'top';
165 | rel?: string;
166 | download?: boolean;
167 | };
168 | nativeID?: string;
169 | onMouseEnter?: (event: MouseEvent) => void;
170 | onMouseLeave?: (event: MouseEvent) => void;
171 | }
172 |
173 | interface CheckBoxProps {
174 | color?: string | null;
175 | }
176 |
177 | interface ViewStyle {
178 | cursor?: CursorValue;
179 | transitionProperty?: string;
180 | display?: 'flex' | 'inline-flex' | 'none';
181 | outlineWidth?: number | string;
182 | boxShadow?: string;
183 | visibility?: 'hidden' | 'visible' | 'collapse' | 'initial';
184 | position?: 'absolute' | 'relative' | 'fixed';
185 | }
186 |
187 | interface TextStyle {
188 | // The following list is sourced from:
189 | // - https://github.com/necolas/react-native-web/blob/0.17.5/packages/react-native-web/src/types/styles.js#L128
190 | userSelect?: 'all' | 'auto' | 'contain' | 'none' | 'text';
191 | }
192 | }
193 |
--------------------------------------------------------------------------------
/templates/vanilla/template/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: "com.android.application"
2 | apply plugin: "com.facebook.react"
3 |
4 | import com.android.build.OutputFile
5 |
6 | /**
7 | * This is the configuration block to customize your React Native Android app.
8 | * By default you don't need to apply any configuration, just uncomment the lines you need.
9 | */
10 | react {
11 | /* Folders */
12 | // The root of your project, i.e. where "package.json" lives. Default is '..'
13 | // root = file("../")
14 | // The folder where the react-native NPM package is. Default is ../node_modules/react-native
15 | // reactNativeDir = file("../node_modules/react-native")
16 | // The folder where the react-native Codegen package is. Default is ../node_modules/react-native-codegen
17 | // codegenDir = file("../node_modules/react-native-codegen")
18 | // The cli.js file which is the React Native CLI entrypoint. Default is ../node_modules/react-native/cli.js
19 | // cliFile = file("../node_modules/react-native/cli.js")
20 |
21 | /* Variants */
22 | // The list of variants to that are debuggable. For those we're going to
23 | // skip the bundling of the JS bundle and the assets. By default is just 'debug'.
24 | // If you add flavors like lite, prod, etc. you'll have to list your debuggableVariants.
25 | // debuggableVariants = ["liteDebug", "prodDebug"]
26 |
27 | /* Bundling */
28 | // A list containing the node command and its flags. Default is just 'node'.
29 | // nodeExecutableAndArgs = ["node"]
30 | //
31 | // The command to run when bundling. By default is 'bundle'
32 | // bundleCommand = "ram-bundle"
33 | //
34 | // The path to the CLI configuration file. Default is empty.
35 | // bundleConfig = file(../rn-cli.config.js)
36 | //
37 | // The name of the generated asset file containing your JS bundle
38 | // bundleAssetName = "MyApplication.android.bundle"
39 | //
40 | // The entry file for bundle generation. Default is 'index.android.js' or 'index.js'
41 | // entryFile = file("../js/MyApplication.android.js")
42 | //
43 | // A list of extra flags to pass to the 'bundle' commands.
44 | // See https://github.com/react-native-community/cli/blob/main/docs/commands.md#bundle
45 | // extraPackagerArgs = []
46 |
47 | /* Hermes Commands */
48 | // The hermes compiler command to run. By default it is 'hermesc'
49 | // hermesCommand = "$rootDir/my-custom-hermesc/bin/hermesc"
50 | //
51 | // The list of flags to pass to the Hermes compiler. By default is "-O", "-output-source-map"
52 | // hermesFlags = ["-O", "-output-source-map"]
53 | }
54 |
55 | /**
56 | * Set this to true to create four separate APKs instead of one,
57 | * one for each native architecture. This is useful if you don't
58 | * use App Bundles (https://developer.android.com/guide/app-bundle/)
59 | * and want to have separate APKs to upload to the Play Store.
60 | */
61 | def enableSeparateBuildPerCPUArchitecture = false
62 |
63 | /**
64 | * Set this to true to Run Proguard on Release builds to minify the Java bytecode.
65 | */
66 | def enableProguardInReleaseBuilds = false
67 |
68 | /**
69 | * The preferred build flavor of JavaScriptCore (JSC)
70 | *
71 | * For example, to use the international variant, you can use:
72 | * `def jscFlavor = 'org.webkit:android-jsc-intl:+'`
73 | *
74 | * The international variant includes ICU i18n library and necessary data
75 | * allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that
76 | * give correct results when using with locales other than en-US. Note that
77 | * this variant is about 6MiB larger per architecture than default.
78 | */
79 | def jscFlavor = 'org.webkit:android-jsc:+'
80 |
81 | /**
82 | * Private function to get the list of Native Architectures you want to build.
83 | * This reads the value from reactNativeArchitectures in your gradle.properties
84 | * file and works together with the --active-arch-only flag of react-native run-android.
85 | */
86 | def reactNativeArchitectures() {
87 | def value = project.getProperties().get("reactNativeArchitectures")
88 | return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"]
89 | }
90 |
91 | android {
92 | ndkVersion rootProject.ext.ndkVersion
93 |
94 | compileSdkVersion rootProject.ext.compileSdkVersion
95 |
96 | namespace "com.projectname"
97 | defaultConfig {
98 | applicationId "com.projectname"
99 | minSdkVersion rootProject.ext.minSdkVersion
100 | targetSdkVersion rootProject.ext.targetSdkVersion
101 | versionCode 1
102 | versionName "1.0"
103 | }
104 |
105 | splits {
106 | abi {
107 | reset()
108 | enable enableSeparateBuildPerCPUArchitecture
109 | universalApk false // If true, also generate a universal APK
110 | include (*reactNativeArchitectures())
111 | }
112 | }
113 | signingConfigs {
114 | debug {
115 | storeFile file('debug.keystore')
116 | storePassword 'android'
117 | keyAlias 'androiddebugkey'
118 | keyPassword 'android'
119 | }
120 | }
121 | buildTypes {
122 | debug {
123 | signingConfig signingConfigs.debug
124 | }
125 | release {
126 | // Caution! In production, you need to generate your own keystore file.
127 | // see https://reactnative.dev/docs/signed-apk-android.
128 | signingConfig signingConfigs.debug
129 | minifyEnabled enableProguardInReleaseBuilds
130 | proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
131 | }
132 | }
133 |
134 | // applicationVariants are e.g. debug, release
135 | applicationVariants.all { variant ->
136 | variant.outputs.each { output ->
137 | // For each separate APK per architecture, set a unique version code as described here:
138 | // https://developer.android.com/studio/build/configure-apk-splits.html
139 | // Example: versionCode 1 will generate 1001 for armeabi-v7a, 1002 for x86, etc.
140 | def versionCodes = ["armeabi-v7a": 1, "x86": 2, "arm64-v8a": 3, "x86_64": 4]
141 | def abi = output.getFilter(OutputFile.ABI)
142 | if (abi != null) { // null for the universal-debug, universal-release variants
143 | output.versionCodeOverride =
144 | defaultConfig.versionCode * 1000 + versionCodes.get(abi)
145 | }
146 |
147 | }
148 | }
149 | }
150 |
151 | dependencies {
152 | // The version of react-native is set by the React Native Gradle Plugin
153 | implementation("com.facebook.react:react-android")
154 |
155 | implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.0.0")
156 |
157 | debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}")
158 | debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") {
159 | exclude group:'com.squareup.okhttp3', module:'okhttp'
160 | }
161 |
162 | debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}")
163 | if (hermesEnabled.toBoolean()) {
164 | implementation("com.facebook.react:hermes-android")
165 | } else {
166 | implementation jscFlavor
167 | }
168 | }
169 |
170 | apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)
171 |
--------------------------------------------------------------------------------
/templates/vanilla/template/android/gradlew:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | #
4 | # Copyright © 2015-2021 the original authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | #
21 | # Gradle start up script for POSIX generated by Gradle.
22 | #
23 | # Important for running:
24 | #
25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
26 | # noncompliant, but you have some other compliant shell such as ksh or
27 | # bash, then to run this script, type that shell name before the whole
28 | # command line, like:
29 | #
30 | # ksh Gradle
31 | #
32 | # Busybox and similar reduced shells will NOT work, because this script
33 | # requires all of these POSIX shell features:
34 | # * functions;
35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»;
37 | # * compound commands having a testable exit status, especially «case»;
38 | # * various built-in commands including «command», «set», and «ulimit».
39 | #
40 | # Important for patching:
41 | #
42 | # (2) This script targets any POSIX shell, so it avoids extensions provided
43 | # by Bash, Ksh, etc; in particular arrays are avoided.
44 | #
45 | # The "traditional" practice of packing multiple parameters into a
46 | # space-separated string is a well documented source of bugs and security
47 | # problems, so this is (mostly) avoided, by progressively accumulating
48 | # options in "$@", and eventually passing that to Java.
49 | #
50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
52 | # see the in-line comments for details.
53 | #
54 | # There are tweaks for specific operating systems such as AIX, CygWin,
55 | # Darwin, MinGW, and NonStop.
56 | #
57 | # (3) This script is generated from the Groovy template
58 | # https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
59 | # within the Gradle project.
60 | #
61 | # You can find Gradle at https://github.com/gradle/gradle/.
62 | #
63 | ##############################################################################
64 |
65 | # Attempt to set APP_HOME
66 |
67 | # Resolve links: $0 may be a link
68 | app_path=$0
69 |
70 | # Need this for daisy-chained symlinks.
71 | while
72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
73 | [ -h "$app_path" ]
74 | do
75 | ls=$( ls -ld "$app_path" )
76 | link=${ls#*' -> '}
77 | case $link in #(
78 | /*) app_path=$link ;; #(
79 | *) app_path=$APP_HOME$link ;;
80 | esac
81 | done
82 |
83 | APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
84 |
85 | APP_NAME="Gradle"
86 | APP_BASE_NAME=${0##*/}
87 |
88 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
89 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
90 |
91 | # Use the maximum available, or set MAX_FD != -1 to use that value.
92 | MAX_FD=maximum
93 |
94 | warn () {
95 | echo "$*"
96 | } >&2
97 |
98 | die () {
99 | echo
100 | echo "$*"
101 | echo
102 | exit 1
103 | } >&2
104 |
105 | # OS specific support (must be 'true' or 'false').
106 | cygwin=false
107 | msys=false
108 | darwin=false
109 | nonstop=false
110 | case "$( uname )" in #(
111 | CYGWIN* ) cygwin=true ;; #(
112 | Darwin* ) darwin=true ;; #(
113 | MSYS* | MINGW* ) msys=true ;; #(
114 | NONSTOP* ) nonstop=true ;;
115 | esac
116 |
117 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
118 |
119 |
120 | # Determine the Java command to use to start the JVM.
121 | if [ -n "$JAVA_HOME" ] ; then
122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
123 | # IBM's JDK on AIX uses strange locations for the executables
124 | JAVACMD=$JAVA_HOME/jre/sh/java
125 | else
126 | JAVACMD=$JAVA_HOME/bin/java
127 | fi
128 | if [ ! -x "$JAVACMD" ] ; then
129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
130 |
131 | Please set the JAVA_HOME variable in your environment to match the
132 | location of your Java installation."
133 | fi
134 | else
135 | JAVACMD=java
136 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
137 |
138 | Please set the JAVA_HOME variable in your environment to match the
139 | location of your Java installation."
140 | fi
141 |
142 | # Increase the maximum file descriptors if we can.
143 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
144 | case $MAX_FD in #(
145 | max*)
146 | MAX_FD=$( ulimit -H -n ) ||
147 | warn "Could not query maximum file descriptor limit"
148 | esac
149 | case $MAX_FD in #(
150 | '' | soft) :;; #(
151 | *)
152 | ulimit -n "$MAX_FD" ||
153 | warn "Could not set maximum file descriptor limit to $MAX_FD"
154 | esac
155 | fi
156 |
157 | # Collect all arguments for the java command, stacking in reverse order:
158 | # * args from the command line
159 | # * the main class name
160 | # * -classpath
161 | # * -D...appname settings
162 | # * --module-path (only if needed)
163 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
164 |
165 | # For Cygwin or MSYS, switch paths to Windows format before running java
166 | if "$cygwin" || "$msys" ; then
167 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
168 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
169 |
170 | JAVACMD=$( cygpath --unix "$JAVACMD" )
171 |
172 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
173 | for arg do
174 | if
175 | case $arg in #(
176 | -*) false ;; # don't mess with options #(
177 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
178 | [ -e "$t" ] ;; #(
179 | *) false ;;
180 | esac
181 | then
182 | arg=$( cygpath --path --ignore --mixed "$arg" )
183 | fi
184 | # Roll the args list around exactly as many times as the number of
185 | # args, so each arg winds up back in the position where it started, but
186 | # possibly modified.
187 | #
188 | # NB: a `for` loop captures its iteration list before it begins, so
189 | # changing the positional parameters here affects neither the number of
190 | # iterations, nor the values presented in `arg`.
191 | shift # remove old arg
192 | set -- "$@" "$arg" # push replacement arg
193 | done
194 | fi
195 |
196 | # Collect all arguments for the java command;
197 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
198 | # shell script including quotes and variable substitutions, so put them in
199 | # double quotes to make sure that they get re-expanded; and
200 | # * put everything else in single quotes, so that it's not re-expanded.
201 |
202 | set -- \
203 | "-Dorg.gradle.appname=$APP_BASE_NAME" \
204 | -classpath "$CLASSPATH" \
205 | org.gradle.wrapper.GradleWrapperMain \
206 | "$@"
207 |
208 | # Use "xargs" to parse quoted args.
209 | #
210 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed.
211 | #
212 | # In Bash we could simply go:
213 | #
214 | # readarray ARGS < <( xargs -n1 <<<"$var" ) &&
215 | # set -- "${ARGS[@]}" "$@"
216 | #
217 | # but POSIX shell has neither arrays nor command substitution, so instead we
218 | # post-process each arg (as a line of input to sed) to backslash-escape any
219 | # character that might be a shell metacharacter, then use eval to reverse
220 | # that process (while maintaining the separation between arguments), and wrap
221 | # the whole thing up as a single "set" statement.
222 | #
223 | # This will of course break if any of these variables contains a newline or
224 | # an unmatched quote.
225 | #
226 |
227 | eval "set -- $(
228 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
229 | xargs -n1 |
230 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
231 | tr '\n' ' '
232 | )" '"$@"'
233 |
234 | exec "$JAVACMD" "$@"
235 |
--------------------------------------------------------------------------------