codingpixel-expo-app 0.1.2 → 0.1.3
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.
package/README.md
CHANGED
|
@@ -7,10 +7,13 @@ Opinionated Expo SDK 54+ app scaffolder. Mirrors the [MyRoster](https://github.c
|
|
|
7
7
|
```bash
|
|
8
8
|
npx codingpixel-expo-app my-app
|
|
9
9
|
cd my-app
|
|
10
|
-
|
|
11
|
-
yarn ios # or: npm run ios / yarn android / npm run android
|
|
10
|
+
yarn ios # or: yarn android (npm run ios / npm run android also work)
|
|
12
11
|
```
|
|
13
12
|
|
|
13
|
+
`yarn ios` / `yarn android` map to `expo run:ios` / `expo run:android` — these BUILD + install the custom dev-client + launch in one shot (3-10 min the first time, fast incremental after). No separate `expo prebuild` step needed.
|
|
14
|
+
|
|
15
|
+
For subsequent runs after the dev-client is installed, use `yarn start` (= `expo start --dev-client`) for faster iteration.
|
|
16
|
+
|
|
14
17
|
The bin name is `codingpixel-expo` (used after global install). Invoke through `npx codingpixel-expo-app` (the package name) for one-shot runs.
|
|
15
18
|
|
|
16
19
|
## Not Expo Go-compatible
|
|
@@ -23,14 +26,13 @@ This template ships native modules that Expo Go can't load:
|
|
|
23
26
|
- `react-native-keyboard-controller`
|
|
24
27
|
- `@gorhom/bottom-sheet` (when bottom-sheet support enabled)
|
|
25
28
|
|
|
26
|
-
You **must** prebuild +
|
|
29
|
+
You **must** run a custom dev-client. `yarn ios` / `yarn android` (= `expo run:ios` / `expo run:android`) handle prebuild + native build + dev-client install in one command:
|
|
27
30
|
|
|
28
31
|
```bash
|
|
29
|
-
npx expo prebuild
|
|
30
32
|
yarn ios # or yarn android / npm run ios / npm run android
|
|
31
33
|
```
|
|
32
34
|
|
|
33
|
-
Subsequent runs use the dev-client + bundler (`yarn start`).
|
|
35
|
+
Subsequent runs use the dev-client + bundler (`yarn start` = `expo start --dev-client`).
|
|
34
36
|
|
|
35
37
|
## Fonts
|
|
36
38
|
|
|
@@ -48,12 +50,14 @@ If your generated app's `tsconfig.json` already has a `@/*` mapping, the CLI pre
|
|
|
48
50
|
|
|
49
51
|
iOS:
|
|
50
52
|
- Xcode + CocoaPods installed (`sudo gem install cocoapods` if missing).
|
|
51
|
-
- `
|
|
53
|
+
- `yarn ios` (or `npm run ios`) — generates `ios/` dir, runs CocoaPods, builds the dev-client, installs in simulator, launches.
|
|
52
54
|
|
|
53
55
|
Android:
|
|
54
56
|
- Android SDK + emulator running (or a USB-attached device with debugging enabled).
|
|
55
57
|
- `JAVA_HOME` pointing at JDK 17.
|
|
56
|
-
- `
|
|
58
|
+
- `yarn android` (or `npm run android`) — generates `android/` dir, builds the dev-client APK, installs, launches.
|
|
59
|
+
|
|
60
|
+
Bundle identifier defaults to `com.<app-name-no-dashes>` (e.g. `com.myapp`). Edit `app.json` `expo.ios.bundleIdentifier` + `expo.android.package` before submitting to App Store / Play Store.
|
|
57
61
|
|
|
58
62
|
## Expo SDK compatibility
|
|
59
63
|
|
package/dist/index.js
CHANGED
|
@@ -107,10 +107,13 @@ async function main() {
|
|
|
107
107
|
log.success(`Project ready at ${target.dir}`);
|
|
108
108
|
log.raw("");
|
|
109
109
|
log.raw(` cd ${path.relative(process.cwd(), target.dir) || target.name}`);
|
|
110
|
-
log.raw(`
|
|
111
|
-
log.raw(` ${cmdPm}
|
|
110
|
+
log.raw(` ${cmdPm} ios # one-time: builds + installs custom dev-client + launches`);
|
|
111
|
+
log.raw(` ${cmdPm} android # same for android (needs emulator/device + Android SDK)`);
|
|
112
112
|
log.raw("");
|
|
113
|
-
log.
|
|
113
|
+
log.raw(` ${cmdPm} start # subsequent runs: faster — connects to installed dev-client`);
|
|
114
|
+
log.raw("");
|
|
115
|
+
log.info("First run takes 3-10 min (native build). After that, `start` is fast. " +
|
|
116
|
+
"iOS needs Xcode + CocoaPods; Android needs SDK + emulator. Not Expo-Go-compatible.");
|
|
114
117
|
}
|
|
115
118
|
main().catch((err) => {
|
|
116
119
|
log.error(err instanceof Error ? err.message : String(err));
|
package/dist/patch.js
CHANGED
|
@@ -37,9 +37,9 @@ export function bundleIdSegment(name) {
|
|
|
37
37
|
seg = `app${seg}`;
|
|
38
38
|
return seg || "app";
|
|
39
39
|
}
|
|
40
|
-
/** Compose the full bundle identifier
|
|
40
|
+
/** Compose the full bundle identifier — `com.<safeName>` (no app-author namespace). */
|
|
41
41
|
export function bundleIdFor(name) {
|
|
42
|
-
return `com
|
|
42
|
+
return `com.${bundleIdSegment(name)}`;
|
|
43
43
|
}
|
|
44
44
|
function readJson(p) {
|
|
45
45
|
return JSON.parse(fs.readFileSync(p, "utf8"));
|
|
@@ -99,6 +99,9 @@ export function patchAppJsonPlugins(target, answers) {
|
|
|
99
99
|
"expo-image-picker",
|
|
100
100
|
{
|
|
101
101
|
photosPermission: "The app accesses your photos to let you share them with your friends.",
|
|
102
|
+
cameraPermission: "The app accesses your camera to let you take photos to share.",
|
|
103
|
+
// microphone optional — only set if app records video. Add manually:
|
|
104
|
+
// "microphonePermission": "...",
|
|
102
105
|
},
|
|
103
106
|
];
|
|
104
107
|
if (!json.expo.plugins.some((e) => nameOf(e) === nameOf(entry))) {
|
|
@@ -161,17 +164,36 @@ export function patchPackageJsonScripts(target) {
|
|
|
161
164
|
const p = path.join(target, "package.json");
|
|
162
165
|
const pkg = readJson(p);
|
|
163
166
|
pkg.scripts ??= {};
|
|
167
|
+
// Use `run:android` / `run:ios` so first invocation builds + installs the
|
|
168
|
+
// custom dev-client (we ship `expo-dev-client` + `react-native-mmkv`, both
|
|
169
|
+
// Expo-Go-incompatible). `expo start --android` would error with "No
|
|
170
|
+
// development build for this project is installed" otherwise.
|
|
171
|
+
// `start` uses `--dev-client` so subsequent runs (after first build)
|
|
172
|
+
// connect to the installed client correctly.
|
|
164
173
|
const want = {
|
|
165
|
-
start: "expo start",
|
|
166
|
-
android: "expo
|
|
167
|
-
ios: "expo
|
|
174
|
+
start: "expo start --dev-client",
|
|
175
|
+
android: "expo run:android",
|
|
176
|
+
ios: "expo run:ios",
|
|
168
177
|
web: "expo start --web",
|
|
169
178
|
lint: "expo lint",
|
|
179
|
+
prebuild: "expo prebuild",
|
|
170
180
|
};
|
|
171
181
|
for (const [k, v] of Object.entries(want)) {
|
|
172
182
|
if (!(k in pkg.scripts))
|
|
173
183
|
pkg.scripts[k] = v;
|
|
174
184
|
}
|
|
185
|
+
// Force-update if upstream defaults from create-expo-app are present (so
|
|
186
|
+
// existing scaffolds re-running the CLI also get the corrected scripts).
|
|
187
|
+
const stale = {
|
|
188
|
+
"expo start": "expo start --dev-client",
|
|
189
|
+
"expo start --android": "expo run:android",
|
|
190
|
+
"expo start --ios": "expo run:ios",
|
|
191
|
+
};
|
|
192
|
+
for (const [scriptName, current] of Object.entries(pkg.scripts)) {
|
|
193
|
+
if (scriptName in want && stale[current] === want[scriptName]) {
|
|
194
|
+
pkg.scripts[scriptName] = want[scriptName];
|
|
195
|
+
}
|
|
196
|
+
}
|
|
175
197
|
writeJson(p, pkg);
|
|
176
198
|
}
|
|
177
199
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
// react-native-mmkv 3.x+ exports `MMKV` as a class (was `createMMKV()` factory
|
|
2
|
+
// in older versions). MyRoster's source predates the API change.
|
|
3
|
+
import { MMKV } from "react-native-mmkv";
|
|
2
4
|
|
|
3
|
-
const storage =
|
|
5
|
+
const storage = new MMKV();
|
|
4
6
|
|
|
5
7
|
export const reduxStorage = {
|
|
6
8
|
setItem: (key: string, value: string) => {
|
|
@@ -12,7 +14,7 @@ export const reduxStorage = {
|
|
|
12
14
|
return Promise.resolve(value);
|
|
13
15
|
},
|
|
14
16
|
removeItem: (key: string) => {
|
|
15
|
-
storage.
|
|
17
|
+
storage.delete(key);
|
|
16
18
|
return Promise.resolve();
|
|
17
19
|
},
|
|
18
20
|
};
|
|
@@ -1,24 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
let customInsets = { ...insets };
|
|
11
|
-
if (ANDROID) {
|
|
12
|
-
customInsets = { ...insets, bottom: insets?.bottom + RF(12) };
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
return (
|
|
16
|
-
<SafeAreaInsetsContext.Provider value={customInsets}>
|
|
17
|
-
{children}
|
|
18
|
-
</SafeAreaInsetsContext.Provider>
|
|
19
|
-
);
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
export const useSafeArea = () => {
|
|
23
|
-
return useContext(SafeAreaInsetsContext);
|
|
24
|
-
};
|
|
1
|
+
// V5 plan dropped MyRoster's `SafeAreaInsetsProvider` (Android-padding tweak)
|
|
2
|
+
// from `_layout.tsx` — relying on stock `react-native-safe-area-context` is
|
|
3
|
+
// cleaner and avoids a context that was never wrapped around the tree.
|
|
4
|
+
//
|
|
5
|
+
// `useSafeArea` is preserved as a thin re-export so existing component code
|
|
6
|
+
// (AppWrapper, AppButton, etc.) keeps compiling without edits.
|
|
7
|
+
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|
8
|
+
|
|
9
|
+
export const useSafeArea = useSafeAreaInsets;
|