@fadyshawky/react-native-magic 2.0.9 → 2.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/.vscode/settings.json +2 -1
  2. package/README.md +55 -214
  3. package/package.json +9 -90
  4. package/scripts/askPackageName.js +165 -0
  5. package/template/.env.example +12 -0
  6. package/template/App.tsx +20 -16
  7. package/template/CHANGELOG.md +25 -0
  8. package/template/android/app/build.gradle +3 -3
  9. package/template/android/app/src/main/java/com/reactnativemagic/MainActivity.kt +8 -2
  10. package/template/android/app/src/main/java/com/reactnativemagic/MainApplication.kt +12 -29
  11. package/template/android/build.gradle +5 -5
  12. package/template/android/gradle/wrapper/gradle-wrapper.properties +1 -1
  13. package/template/docs/ARCHITECTURE.md +27 -0
  14. package/template/docs/BEST_PRACTICES.md +33 -0
  15. package/template/docs/CUSTOMIZATION.md +53 -0
  16. package/template/index.js +1 -0
  17. package/template/package.json +44 -89
  18. package/template/src/common/components/AppStatusBar.tsx +24 -0
  19. package/template/src/common/components/Cards.tsx +1 -1
  20. package/template/src/common/components/EmptyView.tsx +1 -1
  21. package/template/src/common/components/OTPInput.tsx +1 -1
  22. package/template/src/common/components/PrimaryButton.tsx +5 -5
  23. package/template/src/common/components/PrimaryTextInput.tsx +4 -4
  24. package/template/src/common/components/RadioButton.tsx +1 -1
  25. package/template/src/common/components/RadioIcon.tsx +4 -4
  26. package/template/src/common/components/SnackbarProvider.tsx +11 -0
  27. package/template/src/common/components/TryAgain.tsx +3 -3
  28. package/template/src/common/validations/errorValidations.ts +1 -1
  29. package/template/src/core/api/serverHeaders.ts +38 -9
  30. package/template/src/core/config/index.ts +13 -0
  31. package/template/src/core/store/store.tsx +3 -53
  32. package/template/src/core/theme/colors.ts +3 -0
  33. package/template/src/core/theme/commonSizes.ts +3 -0
  34. package/template/src/core/theme/fonts.ts +3 -0
  35. package/template/src/core/utils/stringUtils.ts +2 -45
  36. package/template/src/navigation/TabBar.tsx +5 -5
  37. package/template/src/screens/index.tsx +0 -15
  38. package/template/tsconfig.json +6 -1
  39. package/template.config.js +4 -2
@@ -3,5 +3,6 @@
3
3
  "activityBar.background": "#342D0C",
4
4
  "titleBar.activeBackground": "#493F10",
5
5
  "titleBar.activeForeground": "#FCFAF0"
6
- }
6
+ },
7
+ "java.configuration.updateBuildConfiguration": "automatic"
7
8
  }
package/README.md CHANGED
@@ -1,266 +1,107 @@
1
1
  # ReactNativeMagic
2
2
 
3
- A modern, production-ready React Native template with best practices, common dependencies, and a scalable architecture.
3
+ **Plug and play** create your app and start developing without hassle.
4
+
5
+ A production-ready React Native template with TypeScript, Redux, React Navigation, and a scalable architecture (Uprise-style). Use it to bootstrap new apps with one command.
4
6
 
5
7
  ## Requirements
6
8
 
7
- - Node.js >= 14 ([Download](https://nodejs.org/en/download/))
9
+ - **Node.js >= 20** ([Download](https://nodejs.org/en/download/))
8
10
  - JDK >= 11 ([Download](https://www.oracle.com/java/technologies/downloads/))
9
- - Ruby >= 2.7.5 (for iOS) ([Download](https://www.ruby-lang.org/en/downloads/))
10
- - Xcode (for iOS) ([Mac App Store](https://apps.apple.com/us/app/xcode/id497799835))
11
- - Android Studio (for Android) ([Download](https://developer.android.com/studio))
11
+ - Ruby >= 2.7.5 (for iOS)
12
+ - Xcode (for iOS) / Android Studio (for Android)
12
13
 
13
- ## Installation
14
+ ## Quick start
14
15
 
15
16
  ```bash
16
17
  npx @react-native-community/cli init YourAppName --template @fadyshawky/react-native-magic
17
18
  cd YourAppName
18
19
  ```
19
20
 
20
- For iOS, install pods:
21
+ Optional: set your bundle ID at creation:
21
22
 
22
23
  ```bash
23
- cd ios && pod install && cd ..
24
- ```
25
-
26
- ## Project Structure
27
-
24
+ npx @react-native-community/cli init YourAppName --template @fadyshawky/react-native-magic --package-name com.yourcompany.yourapp
28
25
  ```
29
- YourAppName/
30
- ├── src/
31
- │ ├── components/ # Reusable UI components
32
- │ ├── screens/ # Screen components
33
- │ ├── navigation/ # Navigation configurations
34
- │ ├── services/ # API services and other external services
35
- │ ├── store/ # State management
36
- │ │ ├── slices/ # Redux slices
37
- │ │ └── index.ts # Store configuration
38
- │ ├── theme/ # Theme configurations
39
- │ ├── utils/ # Utility functions
40
- │ └── types/ # TypeScript type definitions
41
- ├── android/
42
- ├── ios/
43
- └── ...
44
- ```
45
-
46
- ## Features
47
-
48
- ### 1. Type Safety
49
-
50
- - Full TypeScript support
51
- - Pre-configured tsconfig.json
52
- - Type definitions for all components
53
-
54
- ### 2. Navigation
55
-
56
- - React Navigation v6
57
- - Type-safe navigation
58
- - Bottom tabs setup
59
- - Stack navigation setup
60
-
61
- Documentation: [React Navigation](https://reactnavigation.org/docs/getting-started)
62
-
63
- ### 3. State Management
64
-
65
- - Redux Toolkit
66
- - Async storage integration
67
- - Predefined store setup
68
26
 
69
- Documentation: [Redux Toolkit](https://redux-toolkit.js.org/introduction/getting-started)
70
-
71
- ### 4. Environment Variables
72
-
73
- - React Native Config integration
74
- - Secure environment configuration
75
- - Type-safe environment variables
76
-
77
- Documentation: [React Native Config](https://github.com/luggit/react-native-config)
78
-
79
- ### 5. Styling
80
-
81
- - React Native Paper
82
- - Custom theming system
83
- - Dark mode support
84
-
85
- Documentation: [React Native Paper](https://callstack.github.io/react-native-paper/)
86
-
87
- ### 6. Testing
88
-
89
- - Jest configuration
90
- - React Native Testing Library
91
- - Example tests included
92
-
93
- Documentation:
94
-
95
- - [Jest](https://jestjs.io/docs/getting-started)
96
- - [React Native Testing Library](https://callstack.github.io/react-native-testing-library/)
97
-
98
- ## Available Scripts
27
+ For iOS, install pods:
99
28
 
100
29
  ```bash
101
- # Start the Metro bundler
102
- npm start
103
-
104
- # Run on iOS
105
- npm run ios
106
-
107
- # Run on Android
108
- npm run android
109
-
110
- # Run tests
111
- npm test
112
-
113
- # Lint code
114
- npm run lint
115
-
116
- # Type checking
117
- npm run typescript
118
- ```
119
-
120
- ## Dependencies
121
-
122
- ### Production Dependencies
123
-
124
- ```json
125
- {
126
- "@react-navigation/bottom-tabs": "^6.x",
127
- "@react-navigation/native": "^6.x",
128
- "@react-navigation/native-stack": "^6.x",
129
- "@reduxjs/toolkit": "^1.x",
130
- "react-native-paper": "^5.x",
131
- "react-native-safe-area-context": "^4.x",
132
- "react-native-screens": "^3.x",
133
- "@react-native-async-storage/async-storage": "^1.x",
134
- "react-native-config": "^1.x"
135
- }
136
- ```
137
-
138
- ### Development Dependencies
139
-
140
- ```json
141
- {
142
- "@testing-library/react-native": "^11.x",
143
- "@types/jest": "^29.x",
144
- "@types/react": "^18.x",
145
- "typescript": "^4.x",
146
- "jest": "^29.x"
147
- }
30
+ cd ios && pod install && cd ..
148
31
  ```
149
32
 
150
- ## Common Issues & Solutions
151
-
152
- ### iOS Build Issues
153
-
154
- 1. Pod installation fails:
33
+ Then run:
155
34
 
156
35
  ```bash
157
- cd ios
158
- pod deintegrate
159
- pod install
36
+ npm start
37
+ npm run ios # or: npm run android
160
38
  ```
161
39
 
162
- 2. Clean build:
40
+ ## First steps after creating your app
163
41
 
164
- ```bash
165
- cd ios
166
- xcodebuild clean
167
- cd ..
168
- npm run ios
169
- ```
42
+ 1. **App name & bundle ID** – Set at init (or you’ll be prompted for package name if you didn’t pass `--package-name`). See [CUSTOMIZATION.md](template/docs/CUSTOMIZATION.md#app-name-and-bundle-id).
43
+ 2. **API** – Copy `.env.example` to `.env` and set `API_BASE_URL` (and other vars) for your backend.
44
+ 3. **Theme** – Edit `src/core/theme/colors.ts` (and `fonts.ts`, `commonSizes.ts` if needed) for your brand.
45
+ 4. **Config** – Optional: adjust `src/core/config/index.ts` for feature toggles or app-level constants.
170
46
 
171
- ### Android Build Issues
47
+ ## Documentation
172
48
 
173
- 1. Gradle issues:
49
+ In your generated project you’ll have:
174
50
 
175
- ```bash
176
- cd android
177
- ./gradlew clean
178
- cd ..
179
- npm run android
180
- ```
51
+ - **[docs/ARCHITECTURE.md](template/docs/ARCHITECTURE.md)** – Layers, folder map, data flow, SOLID.
52
+ - **[docs/CUSTOMIZATION.md](template/docs/CUSTOMIZATION.md)** – App name, bundle ID, API, theme, adding a screen/slice/language.
53
+ - **[docs/BEST_PRACTICES.md](template/docs/BEST_PRACTICES.md)** – Code style, structure, testing, security, upgrades.
181
54
 
182
- 2. SDK location issues:
183
- Create a `local.properties` file in the android folder with your SDK path:
55
+ ## Project structure (in your app)
184
56
 
185
- ```properties
186
- sdk.dir=/Users/USERNAME/Library/Android/sdk
187
57
  ```
188
-
189
- ## Customization
190
-
191
- ### 1. Changing Theme
192
-
193
- Edit `src/theme/index.ts`:
194
-
195
- ```typescript
196
- export const theme = {
197
- colors: {
198
- primary: "#YOUR_COLOR",
199
- // ...
200
- },
201
- // ...
202
- };
58
+ src/
59
+ ├── common/ # Shared components, localization, helpers, validations, utils
60
+ ├── core/ # Store (Redux), API, theme, config
61
+ ├── navigation/ # Auth stack, main stack, tabs
62
+ ├── screens/ # Feature screens
63
+ └── sheetManager/ # Action sheets
203
64
  ```
204
65
 
205
- ### 2. Adding New Navigation Screens
66
+ ## Scripts
206
67
 
207
- 1. Create screen in `src/screens`
208
- 2. Add to navigation stack in `src/navigation`
209
- 3. Update types in `src/types/navigation.ts`
68
+ | Command | Description |
69
+ |---------|-------------|
70
+ | `npm start` | Start Metro bundler |
71
+ | `npm run ios` | Run on iOS |
72
+ | `npm run android` | Run on Android |
73
+ | `npm test` | Run tests |
74
+ | `npm run lint` | Lint code |
210
75
 
211
- ### 3. Environment Variables
76
+ ## Versioning
212
77
 
213
- 1. Create `.env` file in root directory:
78
+ - **React Native**: ^0.84.x (current stable at release).
79
+ - **React**: ^19.2.x.
80
+ - **Node**: >= 20 (LTS).
214
81
 
215
- ```env
216
- API_URL=https://api.example.com
217
- ENV=development
218
- ```
82
+ Dependencies use **caret (^)** so your app can get patch/minor updates independently.
219
83
 
220
- 2. Access variables in your code:
84
+ ## Common issues
221
85
 
222
- ```typescript
223
- import Config from "react-native-config";
86
+ **iOS – Pod install fails**
224
87
 
225
- console.log(Config.API_URL);
88
+ ```bash
89
+ cd ios && pod deintegrate && pod install && cd ..
226
90
  ```
227
91
 
228
- Note: Remember to add `.env` to your `.gitignore` file and provide a `.env.example` template.
92
+ **Android Gradle / SDK**
229
93
 
230
- ## Contributing
94
+ - Run `./gradlew clean` in `android/`.
95
+ - Ensure `android/local.properties` has `sdk.dir` set to your Android SDK path.
231
96
 
232
- 1. Fork the repository
233
- 2. Create your feature branch (`git checkout -b feature/AmazingFeature`)
234
- 3. Commit your changes (`git commit -m 'Add some AmazingFeature'`)
235
- 4. Push to the branch (`git push origin feature/AmazingFeature`)
236
- 5. Open a Pull Request
97
+ **Upgrading React Native**
237
98
 
238
- ## Useful Links
239
-
240
- - [React Native Documentation](https://reactnative.dev/docs/getting-started)
241
- - [TypeScript Documentation](https://www.typescriptlang.org/docs/)
242
- - [React Navigation Documentation](https://reactnavigation.org/docs/getting-started)
243
- - [Redux Toolkit Documentation](https://redux-toolkit.js.org/introduction/getting-started)
244
- - [React Native Paper Documentation](https://callstack.github.io/react-native-paper/)
99
+ Use [React Native Upgrade Helper](https://react-native-community.github.io/upgrade-helper/) (select current → target version) and apply the suggested changes.
245
100
 
246
101
  ## License
247
102
 
248
- This project is licensed under the MIT License - see the [LICENSE.md](LICENSE.md) file for details
249
-
250
- ## Support
251
-
252
- If you find this template helpful, consider buying me a beer! 🍺
253
-
254
- <a href="https://www.buymeacoffee.com/fadytshawke"><img src="https://img.buymeacoffee.com/button-api/?text=Buy me a beer&emoji=🍺&slug=fadytshawke&button_colour=FFDD00&font_colour=000000&font_family=Cookie&outline_colour=000000&coffee_colour=ffffff" /></a>
103
+ MIT see [LICENSE.md](LICENSE.md).
255
104
 
256
105
  ## Author
257
106
 
258
- Fady Shawky
259
-
260
- - GitHub: [@fadyshawky](https://github.com/fadyshawky)
261
-
262
- ## Acknowledgments
263
-
264
- - React Native Team
265
- - React Navigation Team
266
- - All contributors who help maintain this template
107
+ Fady Shawky – [GitHub](https://github.com/fadyshawky)
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@fadyshawky/react-native-magic",
3
- "version": "2.0.9",
4
- "description": "react native template with ready components, hooks, react navigation, redux, typescript, etc.",
3
+ "version": "2.1.1",
4
+ "description": "Plug-and-play React Native template: TypeScript, Redux, React Navigation, scalable architecture. Init and start developing without hassle.",
5
5
  "keywords": [
6
6
  "react-native-magic",
7
7
  "react-native",
@@ -19,97 +19,16 @@
19
19
  "author": "Fady Shawky",
20
20
  "type": "commonjs",
21
21
  "main": "index.js",
22
- "dependencies": {
23
- "@fontsource/poppins": "^5.1.0",
24
- "@react-native-async-storage/async-storage": "^2.1.0",
25
- "@react-native-camera-roll/camera-roll": "^7.9.0",
26
- "@react-native-community/datetimepicker": "^8.2.0",
27
- "@react-native-community/image-editor": "^4.2.1",
28
- "@react-native-community/netinfo": "^11.4.1",
29
- "@react-native-community/slider": "^4.5.5",
30
- "@react-navigation/bottom-tabs": "^7.2.0",
31
- "@react-navigation/drawer": "^7.1.1",
32
- "@react-navigation/material-top-tabs": "^7.1.0",
33
- "@react-navigation/native": "^7.0.14",
34
- "@react-navigation/native-stack": "^7.2.0",
35
- "@reduxjs/toolkit": "^2.5.0",
36
- "@shopify/flash-list": "^1.7.2",
37
- "@types/intl": "^1.2.2",
38
- "@types/jest": "^29.5.14",
39
- "@types/lodash": "^4.17.13",
40
- "@types/react-native-vector-icons": "^6.4.18",
41
- "@types/react-redux": "^7.1.34",
42
- "axios": "^1.7.9",
43
- "babel-plugin-transform-remove-console": "^6.9.4",
44
- "dayjs": "^1.11.13",
45
- "detox": "^20.28.0",
46
- "intl": "^1.2.5",
47
- "lodash": "^4.17.21",
48
- "mime": "^4.0.6",
49
- "patch-package": "^8.0.0",
50
- "react": "^18.3.1",
51
- "react-native": "^0.76.5",
52
- "react-native-actions-sheet": "^0.9.7",
53
- "react-native-animated-pagination-dots": "^0.1.73",
54
- "react-native-calendars": "^1.1307.0",
55
- "react-native-config": "^1.5.3",
56
- "react-native-device-info": "^14.0.2",
57
- "react-native-dropdown-select-list": "^2.0.5",
58
- "react-native-gesture-handler": "^2.21.2",
59
- "react-native-image-crop-picker": "^0.41.6",
60
- "react-native-image-resource-generator": "^1.0.2",
61
- "react-native-in-app-review": "^4.3.3",
62
- "react-native-keyboard-aware-scroll-view": "^0.9.5",
63
- "react-native-localization": "^2.3.2",
64
- "react-native-mask-input": "^1.2.3",
65
- "react-native-orientation-locker": "^1.7.0",
66
- "react-native-pager-view": "^6.6.1",
67
- "react-native-permissions": "^5.2.1",
68
- "react-native-safe-area-context": "^5.0.0",
69
- "react-native-screens": "^4.4.0",
70
- "react-native-sfsymbols": "^1.2.2",
71
- "react-native-share": "^12.0.3",
72
- "react-native-snackbar": "^2.8.0",
73
- "react-native-svg": "^15.10.1",
74
- "react-native-tab-view": "^4.0.5",
75
- "react-native-vector-icons": "^10.2.0",
76
- "react-native-vision-camera": "^4.6.3",
77
- "react-native-webview": "^13.12.5",
78
- "react-redux": "^9.2.0",
79
- "redux": "^5.0.1",
80
- "redux-persist": "^6.0.0",
81
- "redux-persist-transform-filter": "^0.0.22"
82
- },
83
- "devDependencies": {
84
- "@babel/core": "^7.25.2",
85
- "@babel/preset-env": "^7.26.0",
86
- "@babel/runtime": "^7.26.0",
87
- "@jest/globals": "^29.7.0",
88
- "@react-native-community/cli": "15.0.1",
89
- "@react-native-community/cli-platform-android": "15.0.1",
90
- "@react-native-community/cli-platform-ios": "15.0.1",
91
- "@react-native/babel-preset": "^0.76.5",
92
- "@react-native/eslint-config": "^0.76.5",
93
- "@react-native/metro-config": "^0.76.5",
94
- "@react-native/typescript-config": "^0.76.5",
95
- "@types/react": "^18.3.18",
96
- "@types/react-test-renderer": "^18.3.1",
97
- "babel-jest": "^29.7.0",
98
- "eslint": "^8.57.1",
99
- "eslint-plugin-import": "^2.31.0",
100
- "eslint-plugin-jest": "^28.10.0",
101
- "eslint-plugin-react": "^7.37.2",
102
- "eslint-plugin-react-hooks": "^5.1.0",
103
- "eslint-plugin-react-native": "^4.1.0",
104
- "eslint-plugin-unused-imports": "^4.1.4",
105
- "jest": "^29.7.0",
106
- "prettier": "^2.8.8",
107
- "react-test-renderer": "^18.3.1",
108
- "typescript": "^5.0.4"
109
- },
110
22
  "scripts": {
111
23
  "test": "exit 0"
112
24
  },
25
+ "peerDependencies": {
26
+ "react": "^19.2.0",
27
+ "react-native": "^0.84.0"
28
+ },
29
+ "engines": {
30
+ "node": ">=20"
31
+ },
113
32
  "repository": {
114
33
  "type": "git",
115
34
  "url": "https://github.com/fadyshawky/ReactNativeMagic.git"
@@ -0,0 +1,165 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Post-init script: if the user did not pass --package-name at init,
5
+ * prompt for a package name and apply it to .env and iOS project.
6
+ * Runs with cwd = the new project directory.
7
+ */
8
+
9
+ const fs = require('fs');
10
+ const path = require('path');
11
+ const readline = require('readline');
12
+
13
+ const PACKAGE_NAME_REGEX = /^([a-zA-Z][a-zA-Z0-9_]*\.)+[a-zA-Z][a-zA-Z0-9_]*$/;
14
+
15
+ function prompt(question) {
16
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
17
+ return new Promise((resolve) => {
18
+ rl.question(question, (answer) => {
19
+ rl.close();
20
+ resolve((answer || '').trim());
21
+ });
22
+ });
23
+ }
24
+
25
+ function validatePackageName(packageName) {
26
+ const parts = packageName.split('.');
27
+ if (parts.length < 2) {
28
+ return 'Package name must have at least two segments (e.g. com.app)';
29
+ }
30
+ if (!PACKAGE_NAME_REGEX.test(packageName)) {
31
+ return 'Package name can only contain letters, numbers, underscores and dots';
32
+ }
33
+ return null;
34
+ }
35
+
36
+ function ensureEnvHasPackageIds(envPath, packageName) {
37
+ const fullPath = path.join(process.cwd(), envPath);
38
+ let content = '';
39
+ if (fs.existsSync(fullPath)) {
40
+ content = fs.readFileSync(fullPath, 'utf8');
41
+ }
42
+ const lines = content.split('\n');
43
+ const updated = lines.map((line) => {
44
+ const eq = line.indexOf('=');
45
+ if (eq === -1) return line;
46
+ const key = line.slice(0, eq).trim();
47
+ if (key === 'APP_ID' || key === 'ANDROID_APP_ID') {
48
+ return `${key}=${packageName}`;
49
+ }
50
+ return line;
51
+ });
52
+ const hasAppId = lines.some((l) => /^APP_ID=/.test(l) || /^ANDROID_APP_ID=/.test(l));
53
+ if (!hasAppId) {
54
+ if (updated.length && updated[updated.length - 1] !== '') {
55
+ updated.push('');
56
+ }
57
+ updated.push(`APP_ID=${packageName}`);
58
+ updated.push(`ANDROID_APP_ID=${packageName}`);
59
+ }
60
+ fs.writeFileSync(fullPath, updated.join('\n'), 'utf8');
61
+ }
62
+
63
+ function getCurrentIosBundleId() {
64
+ const iosDir = path.join(process.cwd(), 'ios');
65
+ if (!fs.existsSync(iosDir)) return null;
66
+ const entries = fs.readdirSync(iosDir, { withFileTypes: true });
67
+ const pbxprojPaths = entries
68
+ .filter((d) => d.isDirectory() && d.name.endsWith('.xcodeproj'))
69
+ .map((d) => path.join(iosDir, d.name, 'project.pbxproj'))
70
+ .filter((p) => fs.existsSync(p));
71
+ const customPattern = /PRODUCT_BUNDLE_IDENTIFIER = "([^"]+)"/;
72
+ for (const pbx of pbxprojPaths) {
73
+ const content = fs.readFileSync(pbx, 'utf8');
74
+ const customMatch = content.match(customPattern);
75
+ if (customMatch) {
76
+ const id = customMatch[1];
77
+ if (!id.includes('$(')) return id;
78
+ }
79
+ }
80
+ return null;
81
+ }
82
+
83
+ function updateIosBundleId(packageName) {
84
+ const iosDir = path.join(process.cwd(), 'ios');
85
+ if (!fs.existsSync(iosDir)) return;
86
+
87
+ const entries = fs.readdirSync(iosDir, { withFileTypes: true });
88
+ const pbxprojPaths = entries
89
+ .filter((d) => d.isDirectory() && d.name.endsWith('.xcodeproj'))
90
+ .map((d) => path.join(iosDir, d.name, 'project.pbxproj'))
91
+ .filter((p) => fs.existsSync(p));
92
+
93
+ for (const pbx of pbxprojPaths) {
94
+ let content = fs.readFileSync(pbx, 'utf8');
95
+ const pattern = /PRODUCT_BUNDLE_IDENTIFIER = "org\.reactjs\.native\.example\.\$\(PRODUCT_NAME:rfc1034identifier\)"/g;
96
+ if (pattern.test(content)) {
97
+ content = content.replace(
98
+ /PRODUCT_BUNDLE_IDENTIFIER = "org\.reactjs\.native\.example\.\$\(PRODUCT_NAME:rfc1034identifier\)"/g,
99
+ `PRODUCT_BUNDLE_IDENTIFIER = "${packageName}"`
100
+ );
101
+ fs.writeFileSync(pbx, content, 'utf8');
102
+ }
103
+ }
104
+ }
105
+
106
+ async function main() {
107
+ const existingBundleId = getCurrentIosBundleId();
108
+ if (existingBundleId) {
109
+ // User passed --package-name; sync to .env for Android
110
+ const envPath = path.join(process.cwd(), '.env');
111
+ const examplePath = path.join(process.cwd(), '.env.example');
112
+ if (!fs.existsSync(envPath) && fs.existsSync(examplePath)) {
113
+ fs.copyFileSync(examplePath, envPath);
114
+ }
115
+ ensureEnvHasPackageIds('.env', existingBundleId);
116
+ for (const f of ['.env.development', '.env.staging', '.env.production']) {
117
+ if (fs.existsSync(path.join(process.cwd(), f))) {
118
+ ensureEnvHasPackageIds(f, existingBundleId);
119
+ }
120
+ }
121
+ console.log(`\nSynced package name ${existingBundleId} to .env (Android).\n`);
122
+ return;
123
+ }
124
+
125
+ console.log('\nYou did not pass --package-name. Set a bundle ID (Android applicationId / iOS PRODUCT_BUNDLE_IDENTIFIER) now.\n');
126
+
127
+ const answer = await prompt('Package name (e.g. com.company.app), or press Enter to skip: ');
128
+
129
+ if (!answer) {
130
+ console.log('\nSkipped. You can set APP_ID and ANDROID_APP_ID in .env later, and set the iOS bundle ID in Xcode or use react-native-rename.\n');
131
+ return;
132
+ }
133
+
134
+ const err = validatePackageName(answer);
135
+ if (err) {
136
+ console.error('\nInvalid package name:', err);
137
+ process.exit(1);
138
+ }
139
+
140
+ const packageName = answer;
141
+
142
+ // Ensure .env exists
143
+ const envPath = path.join(process.cwd(), '.env');
144
+ const examplePath = path.join(process.cwd(), '.env.example');
145
+ if (!fs.existsSync(envPath) && fs.existsSync(examplePath)) {
146
+ fs.copyFileSync(examplePath, envPath);
147
+ }
148
+
149
+ ensureEnvHasPackageIds('.env', packageName);
150
+ const envFiles = ['.env.development', '.env.staging', '.env.production'];
151
+ for (const f of envFiles) {
152
+ if (fs.existsSync(path.join(process.cwd(), f))) {
153
+ ensureEnvHasPackageIds(f, packageName);
154
+ }
155
+ }
156
+
157
+ updateIosBundleId(packageName);
158
+
159
+ console.log(`\nSet package name to ${packageName} in .env and iOS project.\n`);
160
+ }
161
+
162
+ main().catch((e) => {
163
+ console.error(e);
164
+ process.exit(1);
165
+ });
@@ -0,0 +1,12 @@
1
+ # Copy this file to .env and set your values.
2
+ # Do not commit .env (it is in .gitignore).
3
+
4
+ ENV=development
5
+ API_BASE_URL=https://api.example.com
6
+
7
+ # Bundle ID (Android applicationId / iOS). Set at init with --package-name or when prompted.
8
+ APP_ID=com.yourcompany.yourapp
9
+ ANDROID_APP_ID=com.yourcompany.yourapp
10
+
11
+ ANDROID_VERSION_CODE=1
12
+ ANDROID_VERSION_NAME=1.0.0